Skip to content

Add configurable requirements for blocks #342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void reload(CommandSender sender) {
plugin.config().loadOptions();
plugin.getMessageProvider().loadDefaultLanguageOption();
plugin.getRequirementManager().load();
plugin.getRequirementManager().loadBlocks();
// Load blocked/disabled worlds lists
plugin.getWorldManager().loadWorlds();
// Load skills
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import dev.aurelium.auraskills.api.skill.Skill;
import dev.aurelium.auraskills.bukkit.AuraSkills;
import dev.aurelium.auraskills.bukkit.item.SkillsItem;
import dev.aurelium.auraskills.bukkit.requirement.blocks.BlockRequirement;
import dev.aurelium.auraskills.bukkit.requirement.blocks.RequirementNode;
import dev.aurelium.auraskills.bukkit.util.armor.ArmorEquipEvent;
import dev.aurelium.auraskills.common.config.Option;
import dev.aurelium.auraskills.common.message.MessageKey;
Expand Down Expand Up @@ -96,6 +98,7 @@ public void onBlockBreak(BlockBreakEvent event) {
if (item.getType() == Material.AIR) return;
checkItemRequirements(player, item, event);
}
checkBlockRequirements(event.getPlayer(), event.getBlock().getType(), event);
}

@EventHandler(priority = EventPriority.HIGH)
Expand All @@ -107,6 +110,7 @@ public void onPlace(BlockPlaceEvent event) {
if (item.getType() == Material.AIR) return;
checkItemRequirements(player, item, event);
}
checkBlockRequirements(event.getPlayer(), event.getBlock().getType(), event);
}

@EventHandler(priority = EventPriority.HIGH)
Expand Down Expand Up @@ -163,4 +167,22 @@ private void checkItemRequirements(Player player, ItemStack item, Cancellable ev
}
}

private void checkBlockRequirements(Player player, Material material, Cancellable event) {
BlockRequirement blockRequirement = manager.getBlocks().stream().filter(b -> b.getMaterial() == material).findFirst().orElse(null);
if (blockRequirement != null) {
if (event instanceof BlockBreakEvent) {
if (!blockRequirement.checksBreaking()) return;
} else if (event instanceof BlockPlaceEvent) {
if (!blockRequirement.checksPlacing()) return;
}

for (RequirementNode node : blockRequirement.getNodes()) {
if (!node.check(player)) {
event.setCancelled(true);
String message = node.getDenyMessage();
if(!message.isEmpty()) player.sendMessage(message);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import dev.aurelium.auraskills.api.item.ModifierType;
import dev.aurelium.auraskills.api.registry.NamespacedId;
import dev.aurelium.auraskills.api.skill.Skill;
import dev.aurelium.auraskills.api.stat.Stat;
import dev.aurelium.auraskills.bukkit.AuraSkills;
import dev.aurelium.auraskills.bukkit.requirement.blocks.*;
import dev.aurelium.auraskills.common.config.ConfigurateLoader;
import dev.aurelium.auraskills.common.scheduler.TaskRunnable;
import org.bukkit.Material;
Expand All @@ -20,13 +22,15 @@
public class RequirementManager implements Listener {

private Set<GlobalRequirement> globalRequirements;
private List<BlockRequirement> blockRequirements;
private final Map<UUID, Integer> errorMessageTimer;
private final AuraSkills plugin;

public RequirementManager(AuraSkills plugin) {
errorMessageTimer = new HashMap<>();
this.plugin = plugin;
load();
loadBlocks();
tickTimer();
}

Expand Down Expand Up @@ -74,10 +78,68 @@ public void load() {
}
}

public void loadBlocks() {
ConfigurateLoader loader = new ConfigurateLoader(plugin, TypeSerializerCollection.builder().build());
try {
ConfigurationNode config = loader.loadUserFile("config.yml");

this.blockRequirements = new ArrayList<>();
List<? extends ConfigurationNode> blockNodes = config.node("requirement", "blocks").childrenList();
for (ConfigurationNode blockNode : blockNodes) {
Material material = Material.valueOf(blockNode.node("material").getString().toUpperCase(Locale.ROOT));
boolean allowPlace = blockNode.node("allow_place").getBoolean();
boolean allowBreak = blockNode.node("allow_break").getBoolean();
List<? extends ConfigurationNode> requirementNodes = blockNode.node("requirements").childrenList();
LinkedList<RequirementNode> nodes = new LinkedList<>();

for (ConfigurationNode requirementNode : requirementNodes) {
String type = requirementNode.node("type").getString();
String message = requirementNode.node("message").getString("");

switch (type) {
case "skill_level" -> {
Skill skill = plugin.getSkillRegistry().getOrNull(NamespacedId.fromDefault(requirementNode.node("skill").getString().toLowerCase(Locale.ROOT)));
int level = requirementNode.node("level").getInt();
nodes.add(new SkillNode(plugin, skill, level, message));
}
case "permission" -> {
String permission = requirementNode.node("permission").getString();
nodes.add(new PermissionNode(plugin, permission, message));
}
case "excluded_world" -> {
String[] worlds = (String[]) requirementNode.node("world").getList(String.class).toArray();
nodes.add(new ExcludedWorldNode(plugin, worlds, message));
}
case "stat" -> {
Stat stat = plugin.getStatManager().getEnabledStats().stream().filter(s -> s.getId().equals(NamespacedId.fromDefault(requirementNode.node("stat").getString().toLowerCase(Locale.ROOT)))).findFirst().orElse(null);
int value = requirementNode.node("value").getInt();
nodes.add(new StatNode(plugin, stat, value, message));
}
default ->
plugin.logger().warn("Unknown requirement type: " + type);
}
}

BlockRequirement blockRequirement = new BlockRequirement(material, allowPlace, allowBreak, nodes);
blockRequirements.add(blockRequirement);
}
if (!blockRequirements.isEmpty()) {
plugin.logger().info("Loaded " + blockRequirements.size() + " global requirement" + (blockRequirements.size() != 1 ? "s" : ""));
}
} catch (IOException e) {
plugin.logger().warn("Error loading block requirements: " + e.getMessage());
e.printStackTrace();
}
}

public Set<GlobalRequirement> getGlobalRequirements() {
return globalRequirements;
}

public List<BlockRequirement> getBlocks() {
return blockRequirements;
}

public Set<GlobalRequirement> getGlobalRequirementsType(ModifierType type) {
Set<GlobalRequirement> matched = new HashSet<>();
for (GlobalRequirement requirement : globalRequirements) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import org.bukkit.Material;

import java.util.LinkedList;

public class BlockRequirement {

private final Material material;
private final boolean checksPlace;
private final boolean checksBreak;
private final LinkedList<RequirementNode> nodes;

public BlockRequirement(Material material, boolean checksPlace, boolean checksBreak, LinkedList<RequirementNode> nodes) {
this.material = material;
this.checksPlace = checksPlace;
this.checksBreak = checksBreak;
this.nodes = nodes;
}

public Material getMaterial() {
return material;
}

public boolean checksPlacing() {
return checksPlace;
}

public boolean checksBreaking() {
return checksBreak;
}

public LinkedList<RequirementNode> getNodes() {
return nodes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import dev.aurelium.auraskills.bukkit.AuraSkills;
import org.bukkit.entity.Player;

public class ExcludedWorldNode extends RequirementNode {

private final String[] worlds;
private final String message;

public ExcludedWorldNode(AuraSkills plugin, String[] worlds, String message) {
super(plugin);
this.worlds = worlds;
this.message = message;
}

@Override
public boolean check(Player player) {
for (String world : worlds) {
if (player.getWorld().getName().equalsIgnoreCase(world)) {
return false;
}
}
return true;
}

@Override
public String getDenyMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import dev.aurelium.auraskills.bukkit.AuraSkills;
import org.bukkit.entity.Player;

public class PermissionNode extends RequirementNode {

private final String permission;
private final String message;

public PermissionNode(AuraSkills plugin, String permission, String message) {
super(plugin);
this.permission = permission;
this.message = message;
}

public boolean check(Player player) {
return player.hasPermission(permission);
}

public String getDenyMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import dev.aurelium.auraskills.bukkit.AuraSkills;
import org.bukkit.entity.Player;

public abstract class RequirementNode {

protected AuraSkills plugin;

public RequirementNode(AuraSkills plugin) {
this.plugin = plugin;
}

public abstract String getDenyMessage();
public abstract boolean check(Player player);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import dev.aurelium.auraskills.api.skill.Skill;
import dev.aurelium.auraskills.bukkit.AuraSkills;
import org.bukkit.entity.Player;

public class SkillNode extends RequirementNode {

private final Skill skill;
private final int level;
private final String message;

public SkillNode(AuraSkills plugin, Skill skill, int level, String message) {
super(plugin);
this.skill = skill;
this.level = level;
this.message = message;
}

public boolean check(Player player) {
return plugin.getUser(player).getSkillLevel(skill) >= level;
}

public String getDenyMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.aurelium.auraskills.bukkit.requirement.blocks;

import dev.aurelium.auraskills.api.stat.Stat;
import dev.aurelium.auraskills.bukkit.AuraSkills;
import org.bukkit.entity.Player;

public class StatNode extends RequirementNode {

private final Stat stat;
private final int value;
private final String message;

public StatNode(AuraSkills plugin, Stat stat, int value, String message) {
super(plugin);
this.stat = stat;
this.value = value;
this.message = message;
}

public boolean check(Player player) {
return plugin.getUser(player).getStatLevel(stat) >= value;
}

public String getDenyMessage() {
return message;
}
}
1 change: 1 addition & 0 deletions common/src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ requirement:
armor:
prevent_armor_equip: true
global: [ ]
blocks:
damage:
correct_last_damage: true
critical:
Expand Down
Loading