extend unlock logic to support multi-node unlock plans and update version number

This commit is contained in:
2026-05-19 23:58:54 +02:00
parent 3d54b3ffc1
commit f2aa1e82cc
10 changed files with 39 additions and 21 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ mod_name=Fretux's Skill Engine
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=All Rights Reserved mod_license=All Rights Reserved
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=1.3.2 mod_version=1.3.3
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # 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. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html
@@ -12,6 +12,7 @@ import net.minecraft.server.level.ServerPlayer;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -182,25 +183,28 @@ public class PlayerSkillData {
unlockedNodes.clear(); unlockedNodes.clear();
unlockedAbilities.clear(); unlockedAbilities.clear();
activeTags.clear(); activeTags.clear();
Arrays.fill(abilitySlots, null);
Arrays.fill(abilityCooldowns, 0);
tagCooldowns.clear();
ListTag nodeList = tag.getList("UnlockedNodes", Tag.TAG_COMPOUND); ListTag nodeList = tag.getList("UnlockedNodes", Tag.TAG_COMPOUND);
for (Tag t : nodeList) { for (Tag t : nodeList) {
ResourceLocation id = new ResourceLocation(((CompoundTag) t).getString("Id")); ResourceLocation id = ResourceLocation.parse(((CompoundTag) t).getString("Id"));
unlockedNodes.add(id); unlockedNodes.add(id);
SkillNode node = SkillNodeRegistry.get(id); SkillNode node = SkillNodeRegistry.get(id);
if (node != null) activeTags.addAll(node.getTags()); if (node != null) activeTags.addAll(node.getTags());
} }
ListTag tagList = tag.getList("ActiveTags", Tag.TAG_COMPOUND); ListTag tagList = tag.getList("ActiveTags", Tag.TAG_COMPOUND);
for (Tag t : tagList) { for (Tag t : tagList) {
activeTags.add(new ResourceLocation(((CompoundTag) t).getString("Tag"))); activeTags.add(ResourceLocation.parse(((CompoundTag) t).getString("Tag")));
} }
ListTag slots = tag.getList("AbilitySlots", Tag.TAG_COMPOUND); ListTag slots = tag.getList("AbilitySlots", Tag.TAG_COMPOUND);
for (int i = 0; i < 3 && i < slots.size(); i++) { for (int i = 0; i < 3 && i < slots.size(); i++) {
String id = slots.getCompound(i).getString("Id"); String id = slots.getCompound(i).getString("Id");
abilitySlots[i] = id.isEmpty() ? null : new ResourceLocation(id); abilitySlots[i] = id.isEmpty() ? null : ResourceLocation.parse(id);
} }
ListTag abilityList = tag.getList("UnlockedAbilities", Tag.TAG_COMPOUND); ListTag abilityList = tag.getList("UnlockedAbilities", Tag.TAG_COMPOUND);
for (Tag t : abilityList) { for (Tag t : abilityList) {
unlockedAbilities.add(new ResourceLocation(((CompoundTag) t).getString("Id"))); unlockedAbilities.add(ResourceLocation.parse(((CompoundTag) t).getString("Id")));
} }
ListTag cdList = tag.getList("AbilityCooldowns", Tag.TAG_COMPOUND); ListTag cdList = tag.getList("AbilityCooldowns", Tag.TAG_COMPOUND);
for (int i = 0; i < abilityCooldowns.length && i < cdList.size(); i++) { for (int i = 0; i < abilityCooldowns.length && i < cdList.size(); i++) {
@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class PlayerSkillProvider implements ICapabilityProvider, ICapabilitySerializable<CompoundTag> { public class PlayerSkillProvider implements ICapabilityProvider, ICapabilitySerializable<CompoundTag> {
public static final ResourceLocation ID = new ResourceLocation("skillengine", "player_skill_data"); public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath("skillengine", "player_skill_data");
private final PlayerSkillData backend = new PlayerSkillData(); private final PlayerSkillData backend = new PlayerSkillData();
private final LazyOptional<PlayerSkillData> optional = LazyOptional.of(() -> backend); private final LazyOptional<PlayerSkillData> optional = LazyOptional.of(() -> backend);
@@ -22,9 +22,9 @@ public class SkillEngineCapabilities {
if (event.getObject() instanceof Player) { if (event.getObject() instanceof Player) {
SkillEngine.LOGGER.info("Attaching PlayerSkillData capability"); SkillEngine.LOGGER.info("Attaching PlayerSkillData capability");
event.addCapability( event.addCapability(
new ResourceLocation(SkillEngine.MODID, "player_skill_data"), ResourceLocation.fromNamespaceAndPath(SkillEngine.MODID, "player_skill_data"),
new PlayerSkillProvider() new PlayerSkillProvider()
); );
} }
} }
} }
@@ -23,5 +23,9 @@ public class ClientKeybinds {
"key.categories.ui" "key.categories.ui"
); );
event.register(OPEN_ABILITIES); event.register(OPEN_ABILITIES);
event.register(AbilityKeybindHandler.ABILITY_1);
event.register(AbilityKeybindHandler.ABILITY_2);
event.register(AbilityKeybindHandler.ABILITY_3);
} }
} }
@@ -18,11 +18,15 @@ public class SkilltreeClientState {
private static final int[] clientCooldowns = new int[3]; private static final int[] clientCooldowns = new int[3];
public static void updateCooldown(int slot, int cd) { public static void updateCooldown(int slot, int cd) {
clientCooldowns[slot - 1] = cd; int index = slot - 1;
if (index < 0 || index >= clientCooldowns.length) return;
clientCooldowns[index] = Math.max(0, cd);
} }
public static int getClientCooldown(int slot) { public static int getClientCooldown(int slot) {
return clientCooldowns[slot - 1]; int index = slot - 1;
if (index < 0 || index >= clientCooldowns.length) return 0;
return clientCooldowns[index];
} }
public static void unlockNode(ResourceLocation id) { public static void unlockNode(ResourceLocation id) {
@@ -34,9 +34,11 @@ public class ServerboundActivateAbilityPacket {
if (player == null) return; if (player == null) return;
player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> { player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> {
if (msg.slot < 1 || msg.slot > 3) return;
ResourceLocation abilityId = data.getAbilityInSlot(msg.slot); ResourceLocation abilityId = data.getAbilityInSlot(msg.slot);
if (abilityId == null) return; if (abilityId == null) return;
if (!data.isAbilityUnlocked(abilityId)) return;
AbilityNode ability = AbilityNodeRegistry.get(abilityId); AbilityNode ability = AbilityNodeRegistry.get(abilityId);
if (ability == null) return; if (ability == null) return;
@@ -1,6 +1,7 @@
package net.fretux.skillengine.network; package net.fretux.skillengine.network;
import net.fretux.skillengine.capability.SkillEngineCapabilities; import net.fretux.skillengine.capability.SkillEngineCapabilities;
import net.fretux.skillengine.skilltree.AbilityNodeRegistry;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -32,9 +33,12 @@ public class ServerboundBindAbilityPacket {
ServerPlayer player = ctx.get().getSender(); ServerPlayer player = ctx.get().getSender();
if (player == null) return; if (player == null) return;
player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> {
data.bindAbility(msg.slot, msg.abilityId) if (msg.slot < 1 || msg.slot > 3) return;
); if (AbilityNodeRegistry.get(msg.abilityId) == null) return;
if (!data.isAbilityUnlocked(msg.abilityId)) return;
data.bindAbility(msg.slot, msg.abilityId);
});
PacketHandler.syncSkillsTo(player); PacketHandler.syncSkillsTo(player);
}); });
ctx.get().setPacketHandled(true); ctx.get().setPacketHandled(true);
@@ -48,11 +48,11 @@ public class AbilityNodeLoader extends SimpleJsonResourceReloadListener {
float y = pos.get("y").getAsFloat(); float y = pos.get("y").getAsFloat();
List<ResourceLocation> links = new ArrayList<>(); List<ResourceLocation> links = new ArrayList<>();
obj.getAsJsonArray("links").forEach(e -> obj.getAsJsonArray("links").forEach(e ->
links.add(new ResourceLocation(e.getAsString()))); links.add(ResourceLocation.parse(e.getAsString())));
List<ResourceLocation> tags = new ArrayList<>(); List<ResourceLocation> tags = new ArrayList<>();
obj.getAsJsonArray("tags").forEach(e -> obj.getAsJsonArray("tags").forEach(e ->
tags.add(new ResourceLocation(e.getAsString()))); tags.add(ResourceLocation.parse(e.getAsString())));
ResourceLocation icon = new ResourceLocation(obj.get("icon").getAsString()); ResourceLocation icon = ResourceLocation.parse(obj.get("icon").getAsString());
int cooldown = obj.has("cooldown") ? obj.get("cooldown").getAsInt() : 0; int cooldown = obj.has("cooldown") ? obj.get("cooldown").getAsInt() : 0;
AbilityNode node = new AbilityNode(id, title, description, x, y, links, tags, icon, cooldown); AbilityNode node = new AbilityNode(id, title, description, x, y, links, tags, icon, cooldown);
AbilityNodeRegistry.put(node); AbilityNodeRegistry.put(node);
@@ -40,7 +40,7 @@ public class SkillNodeLoader extends SimpleJsonResourceReloadListener {
jsons.forEach((id, element) -> { jsons.forEach((id, element) -> {
JsonObject obj = element.getAsJsonObject(); JsonObject obj = element.getAsJsonObject();
ResourceLocation nodeId = obj.has("id") ResourceLocation nodeId = obj.has("id")
? new ResourceLocation(obj.get("id").getAsString()) ? ResourceLocation.parse(obj.get("id").getAsString())
: id; : id;
String title = obj.get("title").getAsString(); String title = obj.get("title").getAsString();
String description = obj.get("description").getAsString(); String description = obj.get("description").getAsString();
@@ -50,11 +50,11 @@ public class SkillNodeLoader extends SimpleJsonResourceReloadListener {
float y = pos.get("y").getAsFloat(); float y = pos.get("y").getAsFloat();
List<ResourceLocation> links = new ArrayList<>(); List<ResourceLocation> links = new ArrayList<>();
obj.getAsJsonArray("links").forEach(e -> obj.getAsJsonArray("links").forEach(e ->
links.add(new ResourceLocation(e.getAsString()))); links.add(ResourceLocation.parse(e.getAsString())));
List<ResourceLocation> tags = new ArrayList<>(); List<ResourceLocation> tags = new ArrayList<>();
obj.getAsJsonArray("tags").forEach(e -> obj.getAsJsonArray("tags").forEach(e ->
tags.add(new ResourceLocation(e.getAsString()))); tags.add(ResourceLocation.parse(e.getAsString())));
ResourceLocation icons = new ResourceLocation(obj.get("icons").getAsString()); ResourceLocation icons = ResourceLocation.parse(obj.get("icons").getAsString());
Map<String, Integer> prereqAttributes = new HashMap<>(); Map<String, Integer> prereqAttributes = new HashMap<>();
if (obj.has("prerequisites")) { if (obj.has("prerequisites")) {
JsonObject prereqObj = obj.getAsJsonObject("prerequisites"); JsonObject prereqObj = obj.getAsJsonObject("prerequisites");
@@ -65,7 +65,7 @@ public class SkillNodeLoader extends SimpleJsonResourceReloadListener {
List<ResourceLocation> exclusiveWith = new ArrayList<>(); List<ResourceLocation> exclusiveWith = new ArrayList<>();
if (obj.has("exclusive_with")) { if (obj.has("exclusive_with")) {
obj.getAsJsonArray("exclusive_with").forEach(e -> obj.getAsJsonArray("exclusive_with").forEach(e ->
exclusiveWith.add(new ResourceLocation(e.getAsString()))); exclusiveWith.add(ResourceLocation.parse(e.getAsString())));
} }
SkillNode node = new SkillNode( SkillNode node = new SkillNode(
nodeId, nodeId,