Add action and handler for gliding, equip, refactored PolicyParser and implementations to support world matching
Some checks are pending
Build / build (push) Waiting to run
Some checks are pending
Build / build (push) Waiting to run
This commit is contained in:
parent
96005d8c86
commit
f4a362c1c7
35 changed files with 651 additions and 177 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -2,4 +2,5 @@
|
||||||
build/
|
build/
|
||||||
out/
|
out/
|
||||||
.idea/
|
.idea/
|
||||||
libs/
|
libs/
|
||||||
|
run/
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,25 @@ tasks.register("buildAll") {
|
||||||
dependsOn(tasks.withType<Jar>())
|
dependsOn(tasks.withType<Jar>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register<Jar>("shadowJar") {
|
||||||
|
from(sourceSets["main"].output)
|
||||||
|
mcVersions.forEach { ver ->
|
||||||
|
from(sourceSets[ver].output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is kinda gross and, essentially, we shouldn't have it here...
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
|
||||||
|
archiveClassifier.set("all-implementations")
|
||||||
|
archiveVersion.set(project.version.toString())
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
"Implemented-Versions" to mcVersions.joinToString(",")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* JAVA SETTINGS */
|
/* JAVA SETTINGS */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
|
@ -103,4 +122,18 @@ tasks.withType<JavaCompile> {
|
||||||
|
|
||||||
tasks.runServer {
|
tasks.runServer {
|
||||||
minecraftVersion("1.21")
|
minecraftVersion("1.21")
|
||||||
|
downloadPlugins {
|
||||||
|
modrinth("viaversion", "5.7.0")
|
||||||
|
modrinth("luckperms", "v5.5.17-bukkit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("runServerClean") {
|
||||||
|
doFirst {
|
||||||
|
exec {
|
||||||
|
commandLine("rm", "run/plugins/Eye-of-Nemesis/settings.yml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependsOn("runServer")
|
||||||
}
|
}
|
||||||
34
docs/Nodes.md
Normal file
34
docs/Nodes.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Nodes
|
||||||
|
Nodes narrow down even further if an action can be done or not. A node needs _properties_ to know what it should check against, for example, a HIT node needs a _list_ of blocks that it will check if the player is holding; while a USE_ENCHANTMENT node needs a mapping of enchantment to level. Some nodes like glyde don't need a value and will ignore if you provide one.
|
||||||
|
```yaml
|
||||||
|
nodes:
|
||||||
|
- [HIT]:
|
||||||
|
values:
|
||||||
|
- 'GOLD_SWORD'
|
||||||
|
- [USE_ENCHANTMENT]:
|
||||||
|
values:
|
||||||
|
- "UNBREAKING": "1"
|
||||||
|
- [GLYDE]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available nodes
|
||||||
|
### INTERACT
|
||||||
|
Triggered on `InteractionEvent`, returns true when the provided `list` contains the material used to interact.
|
||||||
|
|
||||||
|
### HIT
|
||||||
|
Triggered on `EntityDamageByEntityEvent`, returns true when the provided `list` contains the material used to hit.
|
||||||
|
|
||||||
|
### PLACE
|
||||||
|
Triggered on `BlockPlaceEvent`, returns true when the provided `list` contains the material being placed.
|
||||||
|
|
||||||
|
### BREAK
|
||||||
|
Triggered on `BlockBreakEvent`, returns true when the provided `list` contains the material used to break.
|
||||||
|
|
||||||
|
### EQUIP
|
||||||
|
Triggered on `InventoryClickEvent` and `PlayerInteractEvent` (only if item is an armor), returns true when the provided `list` contains the material being equipped.
|
||||||
|
|
||||||
|
### GLYDE
|
||||||
|
Triggered on `PlayerMoveEvent`, returns true if player is gliding.
|
||||||
|
|
||||||
|
### USE_ENCHANTMENT
|
||||||
|
Triggered on `BlockBreakEvent` and `onEntityDamageByEntityEvent`, returns true the used item has an enchantment matching the provided mapping of enchantment-level.
|
||||||
89
docs/Policies.md
Normal file
89
docs/Policies.md
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
# Policies
|
||||||
|
Policies are a list of nodes with a specific condition to be met, they also determine what effect a node is going to have. Below is an example policy:
|
||||||
|
```yaml
|
||||||
|
- name: "Allow example"
|
||||||
|
type: "location"
|
||||||
|
effect: ALLOW
|
||||||
|
weight: 1
|
||||||
|
worlds: [world]
|
||||||
|
locations:
|
||||||
|
coordinates:
|
||||||
|
- corner1: { x: 2100, y: 256, z: 1400 }
|
||||||
|
corner2: { x: 1000, y: -64, z: 2200 }
|
||||||
|
nodes:
|
||||||
|
- [INTERACT, BREAK, HIT, PLACE]:
|
||||||
|
values:
|
||||||
|
- AIR
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
### `name`
|
||||||
|
Name of the policy, must not contain spaces or else commands that require you to type the policy name will not work.
|
||||||
|
|
||||||
|
Example: `name: "disable-axe-damage"`
|
||||||
|
|
||||||
|
### `type`
|
||||||
|
One of the policy [types](#Types).
|
||||||
|
|
||||||
|
Example: `type: location`
|
||||||
|
|
||||||
|
### `effect`
|
||||||
|
Can be `deny` to block the action if a node check returns true, `ALLOW` to revert `DENY` effects if the node check is true or `ALLOWONLY` to allow the action **only** if the node check returns true.
|
||||||
|
|
||||||
|
Example: `effect: DENY`
|
||||||
|
|
||||||
|
### `weight`
|
||||||
|
A policy with greater weight will override a conflicting policy of lower weight.
|
||||||
|
|
||||||
|
Example: `weight: 0`
|
||||||
|
|
||||||
|
### `nodes`
|
||||||
|
Must contain a list of node mappings to evaluate if the policy applies to a player.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```yaml
|
||||||
|
nodes:
|
||||||
|
- [HIT]:
|
||||||
|
values:
|
||||||
|
- '.*_AXE$'
|
||||||
|
```
|
||||||
|
|
||||||
|
### `locations`
|
||||||
|
Only used for `type: "location"`, is a list of mappings where corner1 and corner2 should map x, y and z to two corners of a rectangular area where the policy will take effect; `worlds` may be defined here.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
locations:
|
||||||
|
worlds: [world]
|
||||||
|
coordinates:
|
||||||
|
- corner1: { x: 2100, y: 256, z: 1400 }
|
||||||
|
corner2: { x: 1000, y: -64, z: 2200 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `permissions`
|
||||||
|
Only used for `type: "permission"`, is a list of permissions.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
permissions:
|
||||||
|
- "server.axehit"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `names`
|
||||||
|
Only used for `type: "playerName"`, is a list of player names.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
### `global`
|
||||||
|
Always matches.
|
||||||
|
|
||||||
|
### `location`
|
||||||
|
Matches if the player location is inside any rectangle defined in the `locations` property.
|
||||||
|
|
||||||
|
### `playerName`
|
||||||
|
Matches if the player name is in the `names` property.
|
||||||
|
|
||||||
|
### `permission`
|
||||||
|
Matches if the player has a permission in the `permissions` property.
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
name: "Eye-of-Nemesis"
|
|
||||||
version: ${version}
|
|
||||||
main: io.github.adrianvic.nemesiseye.Nemesis
|
|
||||||
author: 'Adrian Victor'
|
|
||||||
description: "Change what players can do based in custom criteria."
|
|
||||||
commands:
|
|
||||||
eye:
|
|
||||||
description: "Run /eye help to see all available commands."
|
|
||||||
permissions:
|
|
||||||
nemesiseye.reload:
|
|
||||||
default: op
|
|
||||||
nemesiseye.policy.list.all:
|
|
||||||
default: op
|
|
||||||
nemesiseye.policy.list.self:
|
|
||||||
default: true
|
|
||||||
nemesiseye.help:
|
|
||||||
default: true
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
# __ _______ __ ___________________ _______
|
|
||||||
# / / \ _ \ \ \ \_ _____/\_____ \ \ \
|
|
||||||
# / / / /_\ \ \ \ | __)_ / | \ / | \
|
|
||||||
# \ \ \ \_/ \ / / | \/ | \/ | \
|
|
||||||
# \_\ \_____ / /_/ /_______ /\_______ /\____|__ /
|
|
||||||
# \/ \/ \/ \/
|
|
||||||
# EYE OF NEMESIS - Example config file.
|
|
||||||
# Documentation in our wiki: https://github.com/adrianvic/NemesisEye
|
|
||||||
|
|
||||||
Policies:
|
|
||||||
- name: "Block-illegal-items" # NO SPACES
|
|
||||||
type: global
|
|
||||||
effect: DENY
|
|
||||||
weight: 0
|
|
||||||
policyAllowList: false
|
|
||||||
nodes:
|
|
||||||
- [BREAK, PLACE, HIT, INTERACT]:
|
|
||||||
value:
|
|
||||||
- BEDROCK
|
|
||||||
- name: "Bedrock-allow-admins"
|
|
||||||
type: "permission"
|
|
||||||
effect: ALLOW
|
|
||||||
weight: 1
|
|
||||||
permissions:
|
|
||||||
- "server.usebedrock"
|
|
||||||
nodes:
|
|
||||||
- [BREAK, PLACE, HIT, INTERACT]:
|
|
||||||
values:
|
|
||||||
- BEDROCK
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
impl.version=b1_7_3
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
package io.github.adrianvic.nemesiseye;
|
package io.github.adrianvic.nemesiseye;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -44,41 +41,6 @@ public class DataShifter {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Glimmer.Box> configLocationParser(Object rawLocations) {
|
|
||||||
Glimmer glim = Nemesis.getInstance().getGlimmer();
|
|
||||||
|
|
||||||
if (rawLocations == null) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parsing locations
|
|
||||||
List<?> groups = rawLocations instanceof List ? (List<?>) rawLocations : List.of();
|
|
||||||
|
|
||||||
ArrayList<Glimmer.Box> boxes = new ArrayList<>(groups.size());
|
|
||||||
|
|
||||||
// Now iterate over regions
|
|
||||||
for (Object rObj : groups) {
|
|
||||||
Map<?, ?> region = (Map<?, ?>) rObj;
|
|
||||||
Map<?, ?> c1 = (Map<?, ?>) region.get("corner1");
|
|
||||||
Map<?, ?> c2 = (Map<?, ?>) region.get("corner2");
|
|
||||||
|
|
||||||
double x1 = ((Number) c1.get("x")).doubleValue();
|
|
||||||
double y1 = ((Number) c1.get("y")).doubleValue();
|
|
||||||
double z1 = ((Number) c1.get("z")).doubleValue();
|
|
||||||
|
|
||||||
double x2 = ((Number) c2.get("x")).doubleValue();
|
|
||||||
double y2 = ((Number) c2.get("y")).doubleValue();
|
|
||||||
double z2 = ((Number) c2.get("z")).doubleValue();
|
|
||||||
|
|
||||||
Location loc1 = new Location(glim.getWorlds().getFirst(), x1, y1, z1);
|
|
||||||
Location loc2 = new Location(glim.getWorlds().getFirst(), x2, y2, z2);
|
|
||||||
|
|
||||||
boxes.add(Glimmer.Box.of(loc1, loc2));
|
|
||||||
}
|
|
||||||
|
|
||||||
return boxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends Enum<T>> T enumOrDefault(Class<T> type, String string, T def) {
|
public static <T extends Enum<T>> T enumOrDefault(Class<T> type, String string, T def) {
|
||||||
try {
|
try {
|
||||||
return Enum.valueOf(type, string);
|
return Enum.valueOf(type, string);
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,126 @@
|
||||||
package io.github.adrianvic.nemesiseye;
|
package io.github.adrianvic.nemesiseye;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.policy.Action;
|
import io.github.adrianvic.nemesiseye.policy.Action;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.HumanEntity;
|
import org.bukkit.entity.HumanEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
import org.bukkit.event.player.PlayerHarvestBlockEvent;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Events {
|
public class Events {
|
||||||
|
|
||||||
public static void onBlockBreak(BlockBreakEvent event) {
|
public static void onBlockBreak(BlockBreakEvent event) {
|
||||||
event.setCancelled(!Validator.can(event.getPlayer(), List.of(Action.BREAK, Action.USE_ENCHANTMENT), event));
|
event.setCancelled(
|
||||||
|
!Validator.can(
|
||||||
|
event.getPlayer(),
|
||||||
|
List.of(Action.BREAK, Action.USE_ENCHANTMENT),
|
||||||
|
event
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onInteractionEvent(PlayerInteractEvent event) {
|
public static void onInteractionEvent(PlayerInteractEvent event) {
|
||||||
if (event.getItem() != null) {
|
ItemStack item = event.getItem();
|
||||||
event.setCancelled(!Validator.can(event.getPlayer(), Action.INTERACT, event));
|
|
||||||
|
if (item == null || item.getType().isAir()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Right-click armor equipping
|
||||||
|
if (isArmor(item)
|
||||||
|
&& !Validator.can(event.getPlayer(), Action.EQUIP, event)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal item interaction
|
||||||
|
event.setCancelled(
|
||||||
|
!Validator.can(event.getPlayer(), Action.INTERACT, event)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onBlockPlaceEvent(BlockPlaceEvent event) {
|
public static void onBlockPlaceEvent(BlockPlaceEvent event) {
|
||||||
event.setCancelled(!Validator.can(event.getPlayer(), Action.PLACE, event));
|
event.setCancelled(
|
||||||
|
!Validator.can(event.getPlayer(), Action.PLACE, event)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) {
|
public static void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) {
|
||||||
if (event.getDamager() instanceof Player) {
|
if (event.getDamager() instanceof Player player) {
|
||||||
event.setCancelled(!Validator.can((HumanEntity) event.getDamager(), List.of(Action.HIT, Action.USE_ENCHANTMENT), event));
|
event.setCancelled(
|
||||||
|
!Validator.can(
|
||||||
|
player,
|
||||||
|
List.of(Action.HIT, Action.USE_ENCHANTMENT),
|
||||||
|
event
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static void onPlayerMoveEvent(PlayerMoveEvent event) {
|
||||||
|
if (event.getPlayer().isGliding()
|
||||||
|
&& !Validator.can(
|
||||||
|
event.getPlayer(),
|
||||||
|
List.of(Action.GLYDE),
|
||||||
|
event
|
||||||
|
)) {
|
||||||
|
event.getPlayer().setGliding(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onInventoryClickEvent(InventoryClickEvent event) {
|
||||||
|
if (!isArmorEquipAttempt(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HumanEntity entity = event.getWhoClicked();
|
||||||
|
|
||||||
|
if (!Validator.can(entity, Action.EQUIP, event)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isArmorEquipAttempt(InventoryClickEvent event) {
|
||||||
|
if (event.getSlotType() == InventoryType.SlotType.ARMOR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.isShiftClick()) {
|
||||||
|
return isArmor(event.getCurrentItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getClick() == ClickType.NUMBER_KEY
|
||||||
|
&& event.getSlotType() == InventoryType.SlotType.ARMOR
|
||||||
|
&& event.getWhoClicked() instanceof Player player) {
|
||||||
|
return isArmor(
|
||||||
|
player.getInventory().getItem(event.getHotbarButton())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isArmor(ItemStack item) {
|
||||||
|
if (item == null || item.getType().isAir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material type = item.getType();
|
||||||
|
String name = type.name();
|
||||||
|
|
||||||
|
return name.endsWith("_HELMET")
|
||||||
|
|| name.endsWith("_CHESTPLATE")
|
||||||
|
|| name.endsWith("_LEGGINGS")
|
||||||
|
|| name.endsWith("_BOOTS")
|
||||||
|
|| type == Material.ELYTRA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
package io.github.adrianvic.nemesiseye;
|
package io.github.adrianvic.nemesiseye;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
|
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
|
||||||
|
import io.github.adrianvic.nemesiseye.reflection.VersionMatcher;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
public final class Nemesis extends JavaPlugin {
|
public final class Nemesis extends JavaPlugin {
|
||||||
private Glimmer glim;
|
private Glimmer glim;
|
||||||
private static final String VERSION_PROP = "impl.version";
|
private static final String VERSION_PROP = "impl.version";
|
||||||
|
|
@ -16,44 +13,11 @@ public final class Nemesis extends JavaPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
glim = loadGlim();
|
glim = new VersionMatcher().loadGlim();
|
||||||
glim.onLoad();
|
glim.onLoad();
|
||||||
Config.getInstance().load();
|
Config.getInstance().load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readImplVersion() {
|
|
||||||
Properties props = new Properties();
|
|
||||||
try (InputStream is = getClass().getClassLoader()
|
|
||||||
.getResourceAsStream("version.properties")) {
|
|
||||||
if (is == null) {
|
|
||||||
throw new IllegalStateException("version.properties not found on classpath.");
|
|
||||||
}
|
|
||||||
props.load(is);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Failed to load version.properties", e);
|
|
||||||
}
|
|
||||||
String version = props.getProperty(VERSION_PROP);
|
|
||||||
if (version == null || version.isBlank()) {
|
|
||||||
throw new IllegalStateException(VERSION_PROP + " property missing in version.properties.");
|
|
||||||
}
|
|
||||||
return version.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Glimmer loadGlim() {
|
|
||||||
String implVersion = readImplVersion();
|
|
||||||
String className = "io.github.adrianvic.nemesiseye.impl." + implVersion;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> clazz = Class.forName(className, true, getClass().getClassLoader());
|
|
||||||
if (!Glimmer.class.isAssignableFrom(clazz)) {
|
|
||||||
throw new IllegalStateException(className + " does not implement Glimmer.");
|
|
||||||
}
|
|
||||||
return (Glimmer) clazz.getDeclaredConstructor().newInstance();
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new IllegalStateException("Failed to instantiate " + className, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@ import java.util.List;
|
||||||
public class Validator {
|
public class Validator {
|
||||||
public static boolean can(HumanEntity entity, List<Action> actions, Event event) {
|
public static boolean can(HumanEntity entity, List<Action> actions, Event event) {
|
||||||
for (Action action : actions) {
|
for (Action action : actions) {
|
||||||
System.out.println(action);
|
|
||||||
if (!can(entity, action, event)) {
|
if (!can(entity, action, event)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +24,6 @@ public class Validator {
|
||||||
boolean allowed = false;
|
boolean allowed = false;
|
||||||
|
|
||||||
for (Policy policy : getPoliciesForEntity(entity)) {
|
for (Policy policy : getPoliciesForEntity(entity)) {
|
||||||
|
|
||||||
boolean matches = policy.matches(entity, action, event);
|
boolean matches = policy.matches(entity, action, event);
|
||||||
|
|
||||||
switch (policy.effect()) {
|
switch (policy.effect()) {
|
||||||
|
|
@ -38,10 +37,6 @@ public class Validator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restricted) {
|
|
||||||
return allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,9 +44,11 @@ public class Validator {
|
||||||
public static List<Policy> getPoliciesForEntity(HumanEntity entity) {
|
public static List<Policy> getPoliciesForEntity(HumanEntity entity) {
|
||||||
List<Policy> ps = Config.getInstance().getPolicies();
|
List<Policy> ps = Config.getInstance().getPolicies();
|
||||||
List<Policy> result = new ArrayList<>();
|
List<Policy> result = new ArrayList<>();
|
||||||
|
|
||||||
for (Policy policy : ps) {
|
for (Policy policy : ps) {
|
||||||
if (policy.applies(entity)) result.add(policy);
|
if (policy.applies(entity)) result.add(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class EyeCore {
|
||||||
else if (commandSender.hasPermission(sub.permission())) {
|
else if (commandSender.hasPermission(sub.permission())) {
|
||||||
return sub.execute(commandSender, Arrays.copyOfRange(strings, 1, strings.length));
|
return sub.execute(commandSender, Arrays.copyOfRange(strings, 1, strings.length));
|
||||||
} else {
|
} else {
|
||||||
Nemesis.getInstance().getLogger().info("does not have %s".formatted(sub.permission()));
|
// Nemesis.getInstance().getLogger().info("does not have %s".formatted(sub.permission()));
|
||||||
Commands.sendNoPermissionError(commandSender);
|
Commands.sendNoPermissionError(commandSender);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ public enum Action {
|
||||||
INTERACT,
|
INTERACT,
|
||||||
BREAK,
|
BREAK,
|
||||||
HIT,
|
HIT,
|
||||||
CRAFT,
|
// TODO CRAFT,
|
||||||
EQUIP,
|
EQUIP,
|
||||||
PLACE,
|
PLACE,
|
||||||
USE_ENCHANTMENT
|
USE_ENCHANTMENT,
|
||||||
|
GLYDE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package io.github.adrianvic.nemesiseye.policy;
|
package io.github.adrianvic.nemesiseye.policy;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.policy.handlers.bePlaced;
|
import io.github.adrianvic.nemesiseye.policy.handlers.*;
|
||||||
import io.github.adrianvic.nemesiseye.policy.handlers.useEnchantment;
|
|
||||||
import io.github.adrianvic.nemesiseye.policy.handlers.useItem;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -15,6 +13,9 @@ public class NodeHandlers {
|
||||||
handlers.put(Action.PLACE, new bePlaced());
|
handlers.put(Action.PLACE, new bePlaced());
|
||||||
handlers.put(Action.INTERACT, new useItem());
|
handlers.put(Action.INTERACT, new useItem());
|
||||||
handlers.put(Action.USE_ENCHANTMENT, new useEnchantment());
|
handlers.put(Action.USE_ENCHANTMENT, new useEnchantment());
|
||||||
|
handlers.put(Action.GLYDE, new glyde());
|
||||||
|
handlers.put(Action.EQUIP, new equip());
|
||||||
|
handlers.put(Action.BREAK, new useItem()); // TODO: implement place handler
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeHandler get(Action type) {
|
public static NodeHandler get(Action type) {
|
||||||
|
|
|
||||||
|
|
@ -8,20 +8,27 @@ import java.util.List;
|
||||||
public interface Policy {
|
public interface Policy {
|
||||||
String name();
|
String name();
|
||||||
List<PolicyNode> nodes();
|
List<PolicyNode> nodes();
|
||||||
|
|
||||||
boolean policyAllowList();
|
boolean policyAllowList();
|
||||||
boolean applies(HumanEntity entity);
|
boolean applies(HumanEntity entity);
|
||||||
Effect effect();
|
Effect effect();
|
||||||
int weight();
|
int weight();
|
||||||
|
List<String> worlds();
|
||||||
|
|
||||||
default void addNode(PolicyNode node) {
|
default void addNode(PolicyNode node) {
|
||||||
nodes().add(node);
|
nodes().add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean matches(HumanEntity entity, Action action, Event event) {
|
default boolean matches(HumanEntity entity, Action action, Event event) {
|
||||||
|
if (!worlds().contains(entity.getWorld().getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (PolicyNode node : nodes()) {
|
for (PolicyNode node : nodes()) {
|
||||||
if (node.matches(entity, action, event)) {
|
if (node.matches(entity, action, event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ public record PolicyNode(List<Action> actions, List<Object> values) {
|
||||||
if (!nodeActions.isEmpty() && !nodeValues.isEmpty()) {
|
if (!nodeActions.isEmpty() && !nodeValues.isEmpty()) {
|
||||||
PolicyNode newNode = new PolicyNode(nodeActions, nodeValues);
|
PolicyNode newNode = new PolicyNode(nodeActions, nodeValues);
|
||||||
nodes.add(newNode);
|
nodes.add(newNode);
|
||||||
System.out.println(newNode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,13 +56,17 @@ public record PolicyNode(List<Action> actions, List<Object> values) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(HumanEntity entity, Action action, Event event) {
|
public boolean matches(HumanEntity entity, Action action, Event event) {
|
||||||
if (!actions.contains(action)) return false;
|
if (!actions.contains(action)) {
|
||||||
|
return false;
|
||||||
for (NodeHandler handler : getHandler()) {
|
|
||||||
if (handler.check(entity, this, action, event)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
NodeHandler handler = NodeHandlers.get(action);
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean result = handler.check(entity, this, action, event);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,20 @@ public interface PolicyParser {
|
||||||
boolean nodesAllowList = Boolean.TRUE.equals(raw.get("nodesAllowList"));
|
boolean nodesAllowList = Boolean.TRUE.equals(raw.get("nodesAllowList"));
|
||||||
Effect effect = DataShifter.enumOrDefault(Effect.class, (String) raw.get("effect"), Effect.DENY);
|
Effect effect = DataShifter.enumOrDefault(Effect.class, (String) raw.get("effect"), Effect.DENY);
|
||||||
String name = (String) raw.get("name");
|
String name = (String) raw.get("name");
|
||||||
int weight = (int) raw.get("weight");
|
Integer weightObj = (Integer) raw.get("weight");
|
||||||
|
int weight = weightObj != null ? weightObj : 0;
|
||||||
|
|
||||||
|
// Worlds
|
||||||
|
List<String> worlds = new ArrayList<>();
|
||||||
|
if (raw.get("worlds") instanceof List<?> list) {
|
||||||
|
for (Object object : list) {
|
||||||
|
if (object instanceof String result) {
|
||||||
|
worlds.add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worlds.add("world");
|
||||||
|
}
|
||||||
|
|
||||||
// Nodes
|
// Nodes
|
||||||
Object rawNodes = raw.get("nodes");
|
Object rawNodes = raw.get("nodes");
|
||||||
|
|
@ -27,7 +40,7 @@ public interface PolicyParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PolicyNode> nodes = PolicyNode.parseNodes(nodeList, effect);
|
List<PolicyNode> nodes = PolicyNode.parseNodes(nodeList, effect);
|
||||||
return parse(new Core(name, nodes, nodesAllowList, policyAllowList, effect, weight), raw);
|
return parse(new Core(name, worlds, nodes, nodesAllowList, policyAllowList, effect, weight), raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
Policy parse(Core corePolicy, Map<?, ?> raw);
|
Policy parse(Core corePolicy, Map<?, ?> raw);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package io.github.adrianvic.nemesiseye.policy.handlers;
|
||||||
|
|
||||||
|
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
|
||||||
|
import io.github.adrianvic.nemesiseye.DataShifter;
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.Action;
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.NodeHandler;
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class equip implements NodeHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check(HumanEntity entity, PolicyNode node, Action action, Event event) {
|
||||||
|
ItemStack item = null;
|
||||||
|
|
||||||
|
if (event instanceof PlayerArmorChangeEvent e) {
|
||||||
|
// Right click equip, dispenser equip, etc...
|
||||||
|
item = e.getNewItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event instanceof InventoryClickEvent e) {
|
||||||
|
InventoryType.SlotType slotType = e.getSlotType();
|
||||||
|
|
||||||
|
// Number key swap into armor slot
|
||||||
|
if (e.getClick() == ClickType.NUMBER_KEY
|
||||||
|
&& slotType == InventoryType.SlotType.ARMOR
|
||||||
|
&& entity instanceof Player player) {
|
||||||
|
item = player.getInventory().getItem(e.getHotbarButton());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift click armor from inventory
|
||||||
|
else if (e.isShiftClick()) {
|
||||||
|
ItemStack current = e.getCurrentItem();
|
||||||
|
|
||||||
|
if (isArmor(current)) {
|
||||||
|
item = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cursor click onto armor slot
|
||||||
|
else if (slotType == InventoryType.SlotType.ARMOR) {
|
||||||
|
ItemStack cursor = e.getCursor();
|
||||||
|
|
||||||
|
if (isArmor(cursor)) {
|
||||||
|
item = cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isArmor(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String type = item.getType().name();
|
||||||
|
|
||||||
|
for (String s : DataShifter.parseValueToStringList(node.values())) {
|
||||||
|
if (DataShifter.safeMatches(s, type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isArmor(ItemStack item) {
|
||||||
|
if (item == null || item.getType().isAir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = item.getType().name();
|
||||||
|
|
||||||
|
return name.endsWith("_HELMET")
|
||||||
|
|| name.endsWith("_CHESTPLATE")
|
||||||
|
|| name.endsWith("_LEGGINGS")
|
||||||
|
|| name.endsWith("_BOOTS")
|
||||||
|
|| item.getType() == org.bukkit.Material.ELYTRA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.github.adrianvic.nemesiseye.policy.handlers;
|
||||||
|
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.Action;
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.NodeHandler;
|
||||||
|
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
|
||||||
|
public class glyde implements NodeHandler {
|
||||||
|
@Override
|
||||||
|
public boolean check(HumanEntity entity, PolicyNode node, Action action, Event event) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,6 @@ import java.util.Map;
|
||||||
public class GlobalPolicyParser implements PolicyParser {
|
public class GlobalPolicyParser implements PolicyParser {
|
||||||
@Override
|
@Override
|
||||||
public Policy parse(Core corePolicy, Map<?, ?> raw) {
|
public Policy parse(Core corePolicy, Map<?, ?> raw) {
|
||||||
return new GlobalPolicy(corePolicy.name(), corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
return new GlobalPolicy(corePolicy.name(), corePolicy.worlds(), corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
package io.github.adrianvic.nemesiseye.policy.parser;
|
package io.github.adrianvic.nemesiseye.policy.parser;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.DataShifter;
|
|
||||||
import io.github.adrianvic.nemesiseye.Nemesis;
|
import io.github.adrianvic.nemesiseye.Nemesis;
|
||||||
import io.github.adrianvic.nemesiseye.policy.*;
|
import io.github.adrianvic.nemesiseye.policy.*;
|
||||||
import io.github.adrianvic.nemesiseye.policy.policies.Core;
|
import io.github.adrianvic.nemesiseye.policy.policies.Core;
|
||||||
import io.github.adrianvic.nemesiseye.policy.policies.LocationPolicy;
|
import io.github.adrianvic.nemesiseye.policy.policies.LocationPolicy;
|
||||||
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
|
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -14,7 +15,48 @@ public class LocationPolicyParser implements PolicyParser {
|
||||||
private Glimmer glim = Nemesis.getInstance().getGlimmer();
|
private Glimmer glim = Nemesis.getInstance().getGlimmer();
|
||||||
|
|
||||||
public Policy parse(Core corePolicy, Map<?, ?> raw) {
|
public Policy parse(Core corePolicy, Map<?, ?> raw) {
|
||||||
List<Glimmer.Box> locations = DataShifter.configLocationParser(raw.get("locations"));
|
Object rawLocations = raw.get("locations");
|
||||||
return new LocationPolicy(corePolicy.name(), locations, corePolicy.nodes(), corePolicy.nodeAllowlist(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
Object rawCoordinates = null;
|
||||||
|
List<String> worlds = new ArrayList<>();
|
||||||
|
if (rawLocations instanceof Map<?,?> rawLocationMap) {
|
||||||
|
rawCoordinates = rawLocationMap.get("coordinates");
|
||||||
|
|
||||||
|
if (rawLocationMap.get("worlds") instanceof List<?> rawWorldsList) {
|
||||||
|
for (Object worldObject : rawWorldsList) {
|
||||||
|
if (worldObject instanceof String worldString) {
|
||||||
|
worlds.add(worldString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worlds.add("world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Glimmer.Box> locations = new ArrayList<>();
|
||||||
|
|
||||||
|
// Parsing locations
|
||||||
|
List<?> groups = rawCoordinates instanceof List ? (List<?>) rawCoordinates : List.of();
|
||||||
|
|
||||||
|
// Now iterate over regions
|
||||||
|
for (Object rObj : groups) {
|
||||||
|
Map<?, ?> region = (Map<?, ?>) rObj;
|
||||||
|
Map<?, ?> c1 = (Map<?, ?>) region.get("corner1");
|
||||||
|
Map<?, ?> c2 = (Map<?, ?>) region.get("corner2");
|
||||||
|
|
||||||
|
double x1 = ((Number) c1.get("x")).doubleValue();
|
||||||
|
double y1 = ((Number) c1.get("y")).doubleValue();
|
||||||
|
double z1 = ((Number) c1.get("z")).doubleValue();
|
||||||
|
|
||||||
|
double x2 = ((Number) c2.get("x")).doubleValue();
|
||||||
|
double y2 = ((Number) c2.get("y")).doubleValue();
|
||||||
|
double z2 = ((Number) c2.get("z")).doubleValue();
|
||||||
|
|
||||||
|
Location loc1 = new Location(glim.getWorlds().getFirst(), x1, y1, z1);
|
||||||
|
Location loc2 = new Location(glim.getWorlds().getFirst(), x2, y2, z2);
|
||||||
|
|
||||||
|
locations.add(Glimmer.Box.of(loc1, loc2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LocationPolicy(corePolicy.name(), corePolicy.worlds(), locations, corePolicy.nodes(), corePolicy.nodeAllowlist(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package io.github.adrianvic.nemesiseye.policy.parser;
|
package io.github.adrianvic.nemesiseye.policy.parser;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.policy.Policy;
|
import io.github.adrianvic.nemesiseye.policy.Policy;
|
||||||
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
|
|
||||||
import io.github.adrianvic.nemesiseye.policy.PolicyParser;
|
import io.github.adrianvic.nemesiseye.policy.PolicyParser;
|
||||||
import io.github.adrianvic.nemesiseye.policy.policies.Core;
|
import io.github.adrianvic.nemesiseye.policy.policies.Core;
|
||||||
import io.github.adrianvic.nemesiseye.policy.policies.PermissionPolicy;
|
import io.github.adrianvic.nemesiseye.policy.policies.PermissionPolicy;
|
||||||
|
|
@ -24,6 +23,6 @@ public class PermissionPolicyParser implements PolicyParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PermissionPolicy(corePolicy.name(), permissions, corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
return new PermissionPolicy(corePolicy.name(), corePolicy.worlds(), permissions, corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,6 @@ public class PlayerNamePolicyParser implements PolicyParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PlayerNamePolicy(corePolicy.name(), names, corePolicy.nodes(), corePolicy.effect(), corePolicy.policyAllowList(), corePolicy.weight());
|
return new PlayerNamePolicy(corePolicy.name(), corePolicy.worlds(), names, corePolicy.nodes(), corePolicy.effect(), corePolicy.policyAllowList(), corePolicy.weight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import org.bukkit.entity.HumanEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record Core(String name, List<PolicyNode> nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
public record Core(String name, List<String> worlds, List<PolicyNode> nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(HumanEntity entity) {
|
public boolean applies(HumanEntity entity) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import org.bukkit.entity.HumanEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record GlobalPolicy(String name, List<PolicyNode> nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
public record GlobalPolicy(String name, List<String> worlds, List<PolicyNode> nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
||||||
public boolean applies(HumanEntity entity) {
|
public boolean applies(HumanEntity entity) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,13 @@ import org.bukkit.entity.HumanEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record LocationPolicy(String name, List<Glimmer.Box> locations, List<PolicyNode> nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
public record LocationPolicy(String name, List<String> worlds, List<Glimmer.Box> locations, List<PolicyNode> nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(HumanEntity entity) {
|
public boolean applies(HumanEntity entity) {
|
||||||
for (Glimmer.Box box : locations) {
|
for (Glimmer.Box box : locations) {
|
||||||
if (box.contains(entity.getLocation().toVector())) return !policyAllowList;
|
if (box.contains(entity.getLocation().toVector(), entity.getWorld())) {
|
||||||
|
return !policyAllowList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return policyAllowList;
|
return policyAllowList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import org.bukkit.entity.HumanEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record PermissionPolicy(String name, List<String> permissions, List<PolicyNode> nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
public record PermissionPolicy(String name, List<String> worlds, List<String> permissions, List<PolicyNode> nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(HumanEntity entity) {
|
public boolean applies(HumanEntity entity) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import org.bukkit.entity.HumanEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record PlayerNamePolicy(String name, List<String> playerName, List<PolicyNode> nodes, Effect effect, boolean policyAllowList, int weight) implements Policy {
|
public record PlayerNamePolicy(String name, List<String> worlds, List<String> playerName, List<PolicyNode> nodes, Effect effect, boolean policyAllowList, int weight) implements Policy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(HumanEntity entity) {
|
public boolean applies(HumanEntity entity) {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import org.bukkit.util.Vector;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public interface Glimmer {
|
public interface Glimmer {
|
||||||
void onLoad();
|
void onLoad();
|
||||||
|
|
@ -32,14 +33,16 @@ public interface Glimmer {
|
||||||
|
|
||||||
class Box {
|
class Box {
|
||||||
public final double x1, y1, z1, x2, y2, z2;
|
public final double x1, y1, z1, x2, y2, z2;
|
||||||
|
public final String world;
|
||||||
|
|
||||||
public Box(double x1, double y1, double z1, double x2, double y2, double z2) {
|
public Box(String world, double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||||
this.x1 = Math.min(x1, x2);
|
this.x1 = Math.min(x1, x2);
|
||||||
this.y1 = Math.min(y1, y2);
|
this.y1 = Math.min(y1, y2);
|
||||||
this.z1 = Math.min(z1, z2);
|
this.z1 = Math.min(z1, z2);
|
||||||
this.x2 = Math.max(x1, x2);
|
this.x2 = Math.max(x1, x2);
|
||||||
this.y2 = Math.max(y1, y2);
|
this.y2 = Math.max(y1, y2);
|
||||||
this.z2 = Math.max(z1, z2);
|
this.z2 = Math.max(z1, z2);
|
||||||
|
this.world = world;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(double x, double y, double z) {
|
public boolean contains(double x, double y, double z) {
|
||||||
|
|
@ -47,13 +50,22 @@ public interface Glimmer {
|
||||||
&& y >= y1 && y <= y2
|
&& y >= y1 && y <= y2
|
||||||
&& z >= z1 && z <= z2;
|
&& z >= z1 && z <= z2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(Vector v) {
|
public boolean contains(Vector v) {
|
||||||
return v.getX() >= x1 && v.getX() <= x2
|
return v.getX() >= x1 && v.getX() <= x2
|
||||||
&& v.getY() >= y1 && v.getY() <= y2
|
&& v.getY() >= y1 && v.getY() <= y2
|
||||||
&& v.getZ() >= z1 && v.getZ() <= z2;
|
&& v.getZ() >= z1 && v.getZ() <= z2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Box of(Location loc1, Location loc2) { return new Box(loc1.getX(), loc1.getY(), loc1.getZ(), loc2.getX(), loc2.getY(), loc2.getZ()); }
|
public boolean contains(Vector v, String w) {
|
||||||
|
return (Objects.equals(w, world)) && contains(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Vector v, World w) {
|
||||||
|
return contains(v, w.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Box of(Location loc1, Location loc2) { return new Box(loc1.getWorld().getName(), loc1.getX(), loc1.getY(), loc1.getZ(), loc2.getX(), loc2.getY(), loc2.getZ()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
package io.github.adrianvic.nemesiseye.reflection;
|
||||||
|
|
||||||
|
import io.github.adrianvic.nemesiseye.DataShifter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class VersionMatcher {
|
||||||
|
|
||||||
|
public VersionMatcher() {}
|
||||||
|
|
||||||
|
private record Entry(String pattern, String classSuffix) {}
|
||||||
|
|
||||||
|
public String getVersion(String type, String serverVersion) {
|
||||||
|
if (type == null || serverVersion == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<Entry>> map = populateMap();
|
||||||
|
List<Entry> entries = map.get(type.toLowerCase());
|
||||||
|
if (entries == null || entries.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Entry e : entries) {
|
||||||
|
if (DataShifter.safeMatches(e.pattern, serverVersion)) {
|
||||||
|
return e.pattern + "|" + e.classSuffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Entry> sorted = new ArrayList<>(entries);
|
||||||
|
Collections.sort(sorted, (a, b) -> compareVersions(a.pattern, b.pattern));
|
||||||
|
|
||||||
|
Entry oldest = sorted.get(0);
|
||||||
|
Entry newest = sorted.get(sorted.size() - 1);
|
||||||
|
|
||||||
|
int cmpOldest = compareVersions(serverVersion, oldest.pattern);
|
||||||
|
int cmpNewest = compareVersions(serverVersion, newest.pattern);
|
||||||
|
|
||||||
|
if (cmpOldest < 0) {
|
||||||
|
return oldest.pattern + "|" + oldest.classSuffix;
|
||||||
|
} else if (cmpNewest > 0) {
|
||||||
|
return newest.pattern + "|" + newest.classSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should not happen because we already tried all patterns
|
||||||
|
return newest.pattern + "|" + newest.classSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<Entry>> populateMap() {
|
||||||
|
Map<String, List<Entry>> map = new HashMap<>();
|
||||||
|
|
||||||
|
// RELEASE patterns, newest first (order does not matter for matching)
|
||||||
|
map.put("release", List.of(
|
||||||
|
new Entry("^1\\.21\\..*$", "r1_21")
|
||||||
|
));
|
||||||
|
|
||||||
|
// BETA patterns
|
||||||
|
map.put("beta", List.of(
|
||||||
|
new Entry("^1\\.7\\.3$", "b1_7_3")
|
||||||
|
));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int compareVersions(String v1, String v2) {
|
||||||
|
String clean1 = v1.replaceAll("[^0-9.]", "");
|
||||||
|
String clean2 = v2.replaceAll("[^0-9.]", "");
|
||||||
|
|
||||||
|
String[] a1 = clean1.split("\\.");
|
||||||
|
String[] a2 = clean2.split("\\.");
|
||||||
|
|
||||||
|
int len = Math.max(a1.length, a2.length);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int n1 = i < a1.length ? parseInt(a1[i]) : 0;
|
||||||
|
int n2 = i < a2.length ? parseInt(a2[i]) : 0;
|
||||||
|
if (n1 != n2) {
|
||||||
|
return n1 - n2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int parseInt(String s) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(s);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Glimmer loadGlim() {
|
||||||
|
String rawVersion;
|
||||||
|
try {
|
||||||
|
rawVersion = Bukkit.getMinecraftVersion(); // returns something like "1.21.10"
|
||||||
|
} catch (NoSuchMethodError e) {
|
||||||
|
return betaLoadGlim();
|
||||||
|
}
|
||||||
|
|
||||||
|
String matchInfo = getVersion("release", rawVersion);
|
||||||
|
if (matchInfo.isEmpty()) {
|
||||||
|
// TODO: Should change to something more robust, it's not beta since we have Bukkit.getMinecraftVersion()
|
||||||
|
return betaLoadGlim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// split the returned string: "pattern|classSuffix"
|
||||||
|
String[] partsInfo = matchInfo.split("\\|");
|
||||||
|
String classSuffix = partsInfo[1]; // e.g. "r1_21"
|
||||||
|
|
||||||
|
String[] versionParts = rawVersion.split("\\.");
|
||||||
|
int major = parseInt(versionParts[0]);
|
||||||
|
int minor = parseInt(versionParts[1]);
|
||||||
|
int patch = versionParts.length > 2 ? parseInt(versionParts[2]) : 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
String className = "io.github.adrianvic.nemesiseye.impl." + classSuffix;
|
||||||
|
Glimmer glimmer = tryInstantiate(className);
|
||||||
|
if (glimmer != null) return glimmer;
|
||||||
|
|
||||||
|
if (patch > 0) {
|
||||||
|
patch--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (minor > 0) {
|
||||||
|
minor--;
|
||||||
|
patch = 20;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
className = "io.github.adrianvic.nemesiseye.impl.r" + major + "_" + minor;
|
||||||
|
glimmer = tryInstantiate(className);
|
||||||
|
if (glimmer != null) return glimmer;
|
||||||
|
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"No suitable implementation found for version " + rawVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glimmer betaLoadGlim() {
|
||||||
|
// Bukkit.getVersion() // returns something like "1.1.10 (MC: 1.7.3)" WEIRD
|
||||||
|
return tryInstantiate("io.github.adrianvic.nemesiseye.impl.b1_7_3"); // only supported beta version for now
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glimmer tryInstantiate(String className) {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(className, true, getClass().getClassLoader());
|
||||||
|
if (!Glimmer.class.isAssignableFrom(clazz)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (Glimmer) clazz.getDeclaredConstructor().newInstance();
|
||||||
|
} catch (ReflectiveOperationException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
name: "Eye-of-Nemesis"
|
name: "Eye-of-Nemesis"
|
||||||
version: ${version}
|
version: ${version}
|
||||||
main: io.github.adrianvic.nemesiseye.Nemesis
|
main: io.github.adrianvic.nemesiseye.Nemesis
|
||||||
api-version: '1.21'
|
api-version: '1.13'
|
||||||
author: 'Adrian Victor'
|
author: 'Adrian Victor'
|
||||||
website: "https://github.io/adrianvic/NemesisEye"
|
website: "https://github.io/adrianvic/NemesisEye"
|
||||||
description: "Change what players can do based in custom criteria."
|
description: "Change what players can do based in custom criteria."
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
Policies:
|
Policies:
|
||||||
- name: "Bedrock-allow-admins"
|
- name: "Bedrock-allow-admins"
|
||||||
type: "permission"
|
type: "permission"
|
||||||
|
worlds: [world]
|
||||||
effect: ALLOW
|
effect: ALLOW
|
||||||
weight: 3
|
weight: 3
|
||||||
permissions:
|
permissions:
|
||||||
|
|
@ -21,6 +22,7 @@ Policies:
|
||||||
|
|
||||||
- name: "Bedrock-deny"
|
- name: "Bedrock-deny"
|
||||||
type: "global"
|
type: "global"
|
||||||
|
worlds: [world]
|
||||||
effect: DENY
|
effect: DENY
|
||||||
weight: 2
|
weight: 2
|
||||||
nodes:
|
nodes:
|
||||||
|
|
@ -31,11 +33,14 @@ Policies:
|
||||||
- name: "Block-non-beta-items" # No spaces here or else commands which need the name as argument will not work
|
- name: "Block-non-beta-items" # No spaces here or else commands which need the name as argument will not work
|
||||||
type: "location" # global | location | permission | playerName
|
type: "location" # global | location | permission | playerName
|
||||||
effect: DENY # DENY | ALLOW (overrides deny) | ALLOWONLY (allow only if met)
|
effect: DENY # DENY | ALLOW (overrides deny) | ALLOWONLY (allow only if met)
|
||||||
|
worlds: [world]
|
||||||
weight: 0 # Greater weight overrides lower
|
weight: 0 # Greater weight overrides lower
|
||||||
policyAllowList: false # Inverts the policy validation logic, for example a location policy will affect all players NOT inside it's location
|
policyAllowList: false # Inverts the policy validation logic, for example a location policy will affect all players NOT inside it's location
|
||||||
locations:
|
locations:
|
||||||
- corner1: { x: 2100, y: 256, z: 1400 }
|
worlds: [world]
|
||||||
corner2: { x: 1000, y: -64, z: 2200 }
|
coordinates:
|
||||||
|
- corner1: { x: 2100, y: 256, z: 1400 }
|
||||||
|
corner2: { x: 1000, y: -64, z: 2200 }
|
||||||
nodes:
|
nodes:
|
||||||
- [INTERACT, BREAK, HIT, PLACE]:
|
- [INTERACT, BREAK, HIT, PLACE]:
|
||||||
values:
|
values:
|
||||||
|
|
@ -48,9 +53,11 @@ Policies:
|
||||||
type: "location"
|
type: "location"
|
||||||
effect: ALLOW
|
effect: ALLOW
|
||||||
weight: 1
|
weight: 1
|
||||||
|
worlds: [world]
|
||||||
locations:
|
locations:
|
||||||
- corner1: { x: 2100, y: 256, z: 1400 }
|
coordinates:
|
||||||
corner2: { x: 1000, y: -64, z: 2200 }
|
- corner1: { x: 2100, y: 256, z: 1400 }
|
||||||
|
corner2: { x: 1000, y: -64, z: 2200 }
|
||||||
nodes:
|
nodes:
|
||||||
- [INTERACT, BREAK, HIT, PLACE]:
|
- [INTERACT, BREAK, HIT, PLACE]:
|
||||||
values:
|
values:
|
||||||
|
|
@ -2,12 +2,14 @@ package io.github.adrianvic.nemesiseye.impl;
|
||||||
|
|
||||||
import io.github.adrianvic.nemesiseye.Events;
|
import io.github.adrianvic.nemesiseye.Events;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
import org.bukkit.event.player.PlayerHarvestBlockEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
|
||||||
public class EventListener implements Listener {
|
public class EventListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
|
@ -29,4 +31,10 @@ public class EventListener implements Listener {
|
||||||
public void onBlockPlaceEvent(BlockPlaceEvent event) {
|
public void onBlockPlaceEvent(BlockPlaceEvent event) {
|
||||||
Events.onBlockPlaceEvent(event);
|
Events.onBlockPlaceEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMoveEvent(PlayerMoveEvent event) { Events.onPlayerMoveEvent(event); }
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||||
|
public void onInventoryClickEvent(InventoryClickEvent event) { Events.onInventoryClickEvent(event);}
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +48,6 @@ public class r1_21 implements Glimmer {
|
||||||
|
|
||||||
for (Map<?, ?> policyMap : rawPolicies) {
|
for (Map<?, ?> policyMap : rawPolicies) {
|
||||||
if (policyMap.get("type") != null && policyMap.get("type") instanceof String type) {
|
if (policyMap.get("type") != null && policyMap.get("type") instanceof String type) {
|
||||||
System.out.println(type);
|
|
||||||
allPolicies.add(PolicyParsers.get(type).parse(policyMap));
|
allPolicies.add(PolicyParsers.get(type).parse(policyMap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
impl.version=r1_21
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue