Add client-side ability cooldowns, sync, and GUI updates
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package net.fretux.skillengine.abilities;
|
||||
|
||||
import net.fretux.skillengine.SkillEngine;
|
||||
import net.fretux.skillengine.capability.PlayerSkillData;
|
||||
import net.fretux.skillengine.capability.SkillEngineCapabilities;
|
||||
import net.fretux.skillengine.network.ClientboundSyncCooldownPacket;
|
||||
import net.fretux.skillengine.network.PacketHandler;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = SkillEngine.MODID)
|
||||
public class AbilityCooldownHandler {
|
||||
private static int syncCounter = 0;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.PlayerTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
if (event.player.level().isClientSide) return;
|
||||
event.player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> {
|
||||
data.tickCooldowns();
|
||||
syncCounter++;
|
||||
if (syncCounter >= 10) {
|
||||
syncCounter = 0;
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
PacketHandler.CHANNEL.send(
|
||||
PacketDistributor.PLAYER.with(() -> (ServerPlayer) event.player),
|
||||
new ClientboundSyncCooldownPacket(i, data.getCooldown(i))
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,15 @@ public class PlayerSkillData {
|
||||
private final Set<ResourceLocation> unlockedAbilities = new HashSet<>();
|
||||
private final Set<ResourceLocation> activeTags = new HashSet<>();
|
||||
private final ResourceLocation[] abilitySlots = new ResourceLocation[3];
|
||||
private final int[] abilityCooldowns = new int[3];
|
||||
|
||||
public int getSkillPoints() { return skillPoints; }
|
||||
public void addSkillPoints(int amount) { skillPoints += amount; }
|
||||
public int getSkillPoints() {
|
||||
return skillPoints;
|
||||
}
|
||||
|
||||
public void addSkillPoints(int amount) {
|
||||
skillPoints += amount;
|
||||
}
|
||||
|
||||
public boolean isUnlocked(ResourceLocation nodeId) {
|
||||
return unlockedNodes.contains(nodeId);
|
||||
@@ -33,7 +39,7 @@ public class PlayerSkillData {
|
||||
skillPoints -= node.getCost();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<ResourceLocation> getUnlockedNodes() {
|
||||
return unlockedNodes;
|
||||
}
|
||||
@@ -86,6 +92,26 @@ public class PlayerSkillData {
|
||||
return abilitySlots.clone();
|
||||
}
|
||||
|
||||
public void setCooldown(int slot, int ticks) {
|
||||
int idx = slot - 1;
|
||||
if (idx < 0 || idx >= abilityCooldowns.length) return;
|
||||
abilityCooldowns[idx] = ticks;
|
||||
}
|
||||
|
||||
public int getCooldown(int slot) {
|
||||
int idx = slot - 1;
|
||||
if (idx < 0 || idx >= abilityCooldowns.length) return 0;
|
||||
return abilityCooldowns[idx];
|
||||
}
|
||||
|
||||
public void tickCooldowns() {
|
||||
for (int i = 0; i < abilityCooldowns.length; i++) {
|
||||
if (abilityCooldowns[i] > 0) {
|
||||
abilityCooldowns[i]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompoundTag save() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putInt("SkillPoints", skillPoints);
|
||||
@@ -117,6 +143,13 @@ public class PlayerSkillData {
|
||||
abilityList.add(t);
|
||||
}
|
||||
tag.put("UnlockedAbilities", abilityList);
|
||||
ListTag cdList = new ListTag();
|
||||
for (int cd : abilityCooldowns) {
|
||||
CompoundTag t = new CompoundTag();
|
||||
t.putInt("CD", cd);
|
||||
cdList.add(t);
|
||||
}
|
||||
tag.put("AbilityCooldowns", cdList);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@@ -127,14 +160,14 @@ public class PlayerSkillData {
|
||||
activeTags.clear();
|
||||
ListTag nodeList = tag.getList("UnlockedNodes", Tag.TAG_COMPOUND);
|
||||
for (Tag t : nodeList) {
|
||||
ResourceLocation id = new ResourceLocation(((CompoundTag)t).getString("Id"));
|
||||
ResourceLocation id = new ResourceLocation(((CompoundTag) t).getString("Id"));
|
||||
unlockedNodes.add(id);
|
||||
SkillNode node = SkillNodeRegistry.get(id);
|
||||
if (node != null) activeTags.addAll(node.getTags());
|
||||
}
|
||||
ListTag tagList = tag.getList("ActiveTags", Tag.TAG_COMPOUND);
|
||||
for (Tag t : tagList) {
|
||||
activeTags.add(new ResourceLocation(((CompoundTag)t).getString("Tag")));
|
||||
activeTags.add(new ResourceLocation(((CompoundTag) t).getString("Tag")));
|
||||
}
|
||||
ListTag slots = tag.getList("AbilitySlots", Tag.TAG_COMPOUND);
|
||||
for (int i = 0; i < 3 && i < slots.size(); i++) {
|
||||
@@ -143,10 +176,15 @@ public class PlayerSkillData {
|
||||
}
|
||||
ListTag abilityList = tag.getList("UnlockedAbilities", Tag.TAG_COMPOUND);
|
||||
for (Tag t : abilityList) {
|
||||
unlockedAbilities.add(new ResourceLocation(((CompoundTag)t).getString("Id")));
|
||||
unlockedAbilities.add(new ResourceLocation(((CompoundTag) t).getString("Id")));
|
||||
}
|
||||
ListTag cdList = tag.getList("AbilityCooldowns", Tag.TAG_COMPOUND);
|
||||
for (int i = 0; i < abilityCooldowns.length && i < cdList.size(); i++) {
|
||||
CompoundTag t = cdList.getCompound(i);
|
||||
abilityCooldowns[i] = t.getInt("CD");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getTotalSkillCost() {
|
||||
int total = 0;
|
||||
for (ResourceLocation id : unlockedNodes) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.fretux.skillengine.client;
|
||||
|
||||
import net.fretux.skillengine.skilltree.AbilityNode;
|
||||
import net.fretux.skillengine.skilltree.AbilityNodeRegistry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.event.RenderGuiEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class AbilityHudOverlay {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void render(RenderGuiEvent.Post event) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null) return;
|
||||
int xStart = event.getGuiGraphics().guiWidth() - 80;
|
||||
int yStart = 10;
|
||||
for (int slot = 1; slot <= 3; slot++) {
|
||||
var abilityId = SkilltreeClientState.getAbilityInSlot(slot);
|
||||
if (abilityId == null) continue;
|
||||
AbilityNode ability = AbilityNodeRegistry.get(abilityId);
|
||||
if (ability == null) continue;
|
||||
int cd = SkilltreeClientState.getClientCooldown(slot);
|
||||
ResourceLocation icon = ability.getIcon();
|
||||
GuiGraphics gfx = event.getGuiGraphics();
|
||||
gfx.blit(icon, xStart, yStart, 0, 0, 16, 16, 16, 16);
|
||||
if (cd > 0) {
|
||||
String text = String.valueOf(cd / 20);
|
||||
gfx.drawString(mc.font, text, xStart + 20, yStart + 4, 0xFF5555);
|
||||
}
|
||||
gfx.drawString(mc.font, "Ability " + slot, xStart + 40, yStart + 4, 0xFFFFFF);
|
||||
yStart += 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.fretux.skillengine.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.fretux.skillengine.network.PacketHandler;
|
||||
import net.fretux.skillengine.network.ServerboundActivateAbilityPacket;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraftforge.client.event.InputEvent;
|
||||
import net.minecraftforge.client.settings.KeyConflictContext;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class AbilityKeybindHandler {
|
||||
|
||||
public static final KeyMapping ABILITY_1 = new KeyMapping(
|
||||
"key.skillengine.ability1", KeyConflictContext.IN_GAME,
|
||||
InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_Y, "key.categories.gameplay"
|
||||
);
|
||||
|
||||
public static final KeyMapping ABILITY_2 = new KeyMapping(
|
||||
"key.skillengine.ability2", KeyConflictContext.IN_GAME,
|
||||
InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_X, "key.categories.gameplay"
|
||||
);
|
||||
|
||||
public static final KeyMapping ABILITY_3 = new KeyMapping(
|
||||
"key.skillengine.ability3", KeyConflictContext.IN_GAME,
|
||||
InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_C, "key.categories.gameplay"
|
||||
);
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onInput(InputEvent.Key event) {
|
||||
if (ABILITY_1.consumeClick()) {
|
||||
if (SkilltreeClientState.getClientCooldown(1) <= 0) {
|
||||
PacketHandler.CHANNEL.sendToServer(new ServerboundActivateAbilityPacket(1));
|
||||
}
|
||||
}
|
||||
if (ABILITY_2.consumeClick()) {
|
||||
if (SkilltreeClientState.getClientCooldown(2) <= 0) {
|
||||
PacketHandler.CHANNEL.sendToServer(new ServerboundActivateAbilityPacket(2));
|
||||
}
|
||||
}
|
||||
if (ABILITY_3.consumeClick()) {
|
||||
if (SkilltreeClientState.getClientCooldown(3) <= 0) {
|
||||
PacketHandler.CHANNEL.sendToServer(new ServerboundActivateAbilityPacket(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.fretux.skillengine.client;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.fretux.skillengine.SkillEngine;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = SkillEngine.MODID, value = Dist.CLIENT)
|
||||
public class ClientCooldownTicker {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int cd = SkilltreeClientState.getClientCooldown(i + 1);
|
||||
if (cd > 0) {
|
||||
SkilltreeClientState.updateCooldown(i + 1, cd - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,15 @@ public class SkilltreeClientState {
|
||||
private static final Set<ResourceLocation> unlockedAbilities = new HashSet<>();
|
||||
private static int currentSkillPoints = 0;
|
||||
private static final ResourceLocation[] abilitySlots = new ResourceLocation[3];
|
||||
private static final int[] clientCooldowns = new int[3];
|
||||
|
||||
public static void updateCooldown(int slot, int cd) {
|
||||
clientCooldowns[slot - 1] = cd;
|
||||
}
|
||||
|
||||
public static int getClientCooldown(int slot) {
|
||||
return clientCooldowns[slot - 1];
|
||||
}
|
||||
|
||||
public static void unlockNode(ResourceLocation id) {
|
||||
SkillEngine.LOGGER.info("[CLIENT] Unlocking node: {}", id);
|
||||
|
||||
@@ -246,6 +246,14 @@ public class SkilltreeScreen extends Screen {
|
||||
);
|
||||
}));
|
||||
}
|
||||
if (!hoveredNode.getExclusiveWith().isEmpty()) {
|
||||
tooltip.add(Component.literal("Mutually Exclusive with:")
|
||||
.withStyle(ChatFormatting.RED));
|
||||
for (ResourceLocation ex : hoveredNode.getExclusiveWith()) {
|
||||
tooltip.add(Component.literal(" - " + ex.toString())
|
||||
.withStyle(ChatFormatting.RED));
|
||||
}
|
||||
}
|
||||
gfx.renderComponentTooltip(font, tooltip, mouseX, mouseY);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.fretux.skillengine.network;
|
||||
|
||||
import net.fretux.skillengine.client.SkilltreeClientState;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ClientboundSyncCooldownPacket {
|
||||
|
||||
private final int slot;
|
||||
private final int cooldown;
|
||||
|
||||
public ClientboundSyncCooldownPacket(int slot, int cooldown) {
|
||||
this.slot = slot;
|
||||
this.cooldown = cooldown;
|
||||
}
|
||||
|
||||
public static void encode(ClientboundSyncCooldownPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeInt(msg.slot);
|
||||
buf.writeInt(msg.cooldown);
|
||||
}
|
||||
|
||||
public static ClientboundSyncCooldownPacket decode(FriendlyByteBuf buf) {
|
||||
return new ClientboundSyncCooldownPacket(buf.readInt(), buf.readInt());
|
||||
}
|
||||
|
||||
public static void handle(ClientboundSyncCooldownPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> SkilltreeClientState.updateCooldown(msg.slot, msg.cooldown));
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,16 @@ public class PacketHandler {
|
||||
.decoder(ServerboundBindAbilityPacket::decode)
|
||||
.consumerMainThread(ServerboundBindAbilityPacket::handle)
|
||||
.add();
|
||||
CHANNEL.messageBuilder(ClientboundSyncCooldownPacket.class, id++, NetworkDirection.PLAY_TO_CLIENT)
|
||||
.encoder(ClientboundSyncCooldownPacket::encode)
|
||||
.decoder(ClientboundSyncCooldownPacket::decode)
|
||||
.consumerMainThread(ClientboundSyncCooldownPacket::handle)
|
||||
.add();
|
||||
CHANNEL.messageBuilder(ServerboundActivateAbilityPacket.class, id++, NetworkDirection.PLAY_TO_SERVER)
|
||||
.encoder(ServerboundActivateAbilityPacket::encode)
|
||||
.decoder(ServerboundActivateAbilityPacket::decode)
|
||||
.consumerMainThread(ServerboundActivateAbilityPacket::handle)
|
||||
.add();
|
||||
}
|
||||
|
||||
public static void syncSkillsTo(ServerPlayer player) {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.fretux.skillengine.network;
|
||||
|
||||
import net.fretux.skillengine.capability.SkillEngineCapabilities;
|
||||
import net.fretux.skillengine.skilltree.AbilityNode;
|
||||
import net.fretux.skillengine.skilltree.AbilityNodeRegistry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ServerboundActivateAbilityPacket {
|
||||
|
||||
private final int slot;
|
||||
|
||||
public ServerboundActivateAbilityPacket(int slot) {
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public static void encode(ServerboundActivateAbilityPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeInt(msg.slot);
|
||||
}
|
||||
|
||||
public static ServerboundActivateAbilityPacket decode(FriendlyByteBuf buf) {
|
||||
return new ServerboundActivateAbilityPacket(buf.readInt());
|
||||
}
|
||||
|
||||
public static void handle(ServerboundActivateAbilityPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
|
||||
ServerPlayer player = ctx.get().getSender();
|
||||
if (player == null) return;
|
||||
|
||||
player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> {
|
||||
|
||||
ResourceLocation abilityId = data.getAbilityInSlot(msg.slot);
|
||||
if (abilityId == null) return;
|
||||
|
||||
AbilityNode ability = AbilityNodeRegistry.get(abilityId);
|
||||
if (ability == null) return;
|
||||
|
||||
int cd = data.getCooldown(msg.slot);
|
||||
if (cd > 0) return;
|
||||
ability.execute(player);
|
||||
data.setCooldown(msg.slot, ability.getCooldown());
|
||||
PacketHandler.CHANNEL.send(
|
||||
PacketDistributor.PLAYER.with(() -> player),
|
||||
new ClientboundSyncCooldownPacket(msg.slot, ability.getCooldown())
|
||||
);
|
||||
});
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package net.fretux.skillengine.skilltree;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,4 +46,8 @@ public class AbilityNode {
|
||||
public List<ResourceLocation> getTags() { return tags; }
|
||||
public ResourceLocation getIcon() { return icon; }
|
||||
public int getCooldown() { return cooldown; }
|
||||
|
||||
public void execute(ServerPlayer player) {
|
||||
player.sendSystemMessage(Component.literal("Activated ability: " + id));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user