diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml
new file mode 100644
index 0000000..149d2f5
--- /dev/null
+++ b/.forgejo/workflows/build.yml
@@ -0,0 +1,43 @@
+name: Build
+
+on:
+ push:
+ paths:
+ - 'src/**'
+ - '.github/**'
+ - 'build.gradle.kts'
+ - 'gradle.properties'
+ - 'settings.gradle'
+
+jobs:
+ build:
+ runs-on: arch-linux
+ env:
+ NEMESIS_VERSION_NAME: "autobuild-${{ github.sha }}"
+ NEMESIS_BUILD_CHANNEL: "autobuild"
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6.0.1
+
+ - name: Setup Java enviroment
+ uses: actions/setup-java@v5.1.0
+ with:
+ distribution: temurin
+ java-version: 21
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v5
+
+ - name: Download CB1060
+ run: |
+ mkdir -p libs
+ curl -L -o libs/craftbukkit-1060.jar https://archive.org/download/craftbukkit1060/craftbukkit1-7-3%281060%29.jar
+
+ - name: Build with Gradle
+ run: ./gradlew buildAll
+
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v6.0.0
+ with:
+ path: build/libs/*.jar
diff --git a/.forgejo/workflows/release-build.yml b/.forgejo/workflows/release-build.yml
new file mode 100644
index 0000000..392e32e
--- /dev/null
+++ b/.forgejo/workflows/release-build.yml
@@ -0,0 +1,40 @@
+name: Release Build
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ build-and-release:
+ runs-on: arch-linux
+ env:
+ NEMESIS_VERSION_NAME: "${{ github.ref_name }}"
+ NEMESIS_BUILD_CHANNEL: "production"
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6.0.1
+
+ - name: Set up Java
+ uses: actions/setup-java@v5.1.0
+ with:
+ distribution: temurin
+ java-version: 21
+
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v5
+
+ - name: Download CB1060
+ run: |
+ mkdir -p libs
+ curl -L -o libs/craftbukkit-1060.jar \
+ https://archive.org/download/craftbukkit1060/craftbukkit1-7-3%281060%29.jar
+
+ - name: Build with Gradle
+ run: ./gradlew buildAll
+
+ - name: Upload JARs to release
+ uses: softprops/action-gh-release@v2.5.0
+ with:
+ files: build/libs/*.jar
+ tag_name: ${{ github.ref_name }}
+ name: ${{ github.ref_name }}
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..ac1941e
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,15 @@
+# These are supported funding model platforms
+
+github: adrianvic
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
+polar: # Replace with a single Polar username
+buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
+thanks_dev: # Replace with a single thanks.dev username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..0e8199d
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,44 @@
+name: Build
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - 'src/**'
+ - '.github/**'
+ - 'build.gradle.kts'
+ - 'gradle.properties'
+ - 'settings.gradle'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ env:
+ NEMESIS_VERSION_NAME: "autobuild-${{ github.sha }}"
+ NEMESIS_BUILD_CHANNEL: "autobuild"
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6.0.1
+
+ - name: Setup Java enviroment
+ uses: actions/setup-java@v5.1.0
+ with:
+ distribution: temurin
+ java-version: 21
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v5
+
+ - name: Download CB1060
+ run: |
+ mkdir -p libs
+ curl -L -o libs/craftbukkit-1060.jar https://archive.org/download/craftbukkit1060/craftbukkit1-7-3%281060%29.jar
+
+ - name: Build with Gradle
+ run: ./gradlew buildAll
+
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ path: build/libs/*.jar
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
new file mode 100644
index 0000000..9570712
--- /dev/null
+++ b/.github/workflows/release-build.yml
@@ -0,0 +1,41 @@
+name: Release Build
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ build-and-release:
+ runs-on: ubuntu-latest
+ env:
+ NEMESIS_VERSION_NAME: "${{ github.ref_name }}"
+ NEMESIS_BUILD_CHANNEL: "production"
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6.0.1
+
+ - name: Set up Java
+ uses: actions/setup-java@v5.1.0
+ with:
+ distribution: temurin
+ java-version: 21
+
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v5
+
+ - name: Download CB1060
+ run: |
+ mkdir -p libs
+ curl -L -o libs/craftbukkit-1060.jar \
+ https://archive.org/download/craftbukkit1060/craftbukkit1-7-3%281060%29.jar
+
+ - name: Build with Gradle
+ run: ./gradlew buildAll
+
+ - name: Upload artifacts to release
+ run: |
+ curl -X POST \
+ -H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \
+ -H "Content-Type: application/octet-stream" \
+ https://inspiran.beetal-castor.ts.net/git/api/v1/repos/${{ github.repository }}/releases/tags/${{ github.ref_name }}/assets \
+ --data-binary @build/libs/your-artifact.jar
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 026e990..1e3abdf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
build/
out/
.idea/
-libs/
\ No newline at end of file
+libs/
+run/
diff --git a/README.md b/README.md
index d221c72..bf357cf 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,24 @@
+
+
+[](https://modrinth.com/plugin/eye-of-nemesis)
+[](https://github.com/adrianvic/NemesisEye/wiki)
+[](https://mgr.rf.gd/w/Eye_of_Nemesis)
+
+> [!IMPORTANT]
+> This project is in an early stage, please report any bug you find.
+
# Eye of Nemesis
Eye of Nemesis is a plugin that allows server admins to write policies that will deny or allow (black/whitelist) players to do specific things based on the value of nodes.
-## Warnings
-- Even though running `/eye` will tell you to run `/eye help` to list all available commands, this is not implemented yet, however all commands are available as tab-complete of `/eye`.
-- This plugin is in a very early stage.
-
## Motivations
I made this plugin as an effort to preserve a village from my private server. Originally from beta 1.7.3 Betalands server, then transferred to RetroMC, and then finally we downloaded the chunks to merge into our server, I was afraid it would not have the same feeling after all the updates, so I had the idea to make a plugin that can block the newer features.
+## Game version and loaders
+Since version 1.0.3-SNAPSHOT, Eye of Nemesis has _reflection_, a technique that allows me to target multiple versions of the game while sharing the codebase across versions.
+
+Currently, we support the following Minecraft versions/loaders:
+- **PaperMC** `1.21, 1.21.1, 1.21.2, 1.21.3, 1.21.4, 1.21.5, 1.21.6, 1.21.7, 1.21.8, 1.21.9, 1.21.10`
+- **Bukkit** `b1.7.3 (CB1060)`
+
## Performance
This plugin is not scalable as it is and will end up running unoptimized checks when your players do things with policies in effect, I made it for a server with a few friends. I'll look forward into writing more performant code after all my other priorities are implemented.
diff --git a/build.gradle.kts b/build.gradle.kts
index 28061f0..e2d9a2e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
}
group = "io.github.adrianvic"
-version = "1.0.3-SNAPSHOT"
+version = System.getenv("NEMESIS_VERSION_NAME") ?: "unknown"
repositories {
mavenCentral()
@@ -24,6 +24,14 @@ val mcVersions = listOf(
/* CREATE SOURCE SET PER VERSION */
/* ----------------------------------------- */
+tasks.withType {
+ inputs.property("version", project.version)
+
+ filesMatching("plugin.yml") {
+ expand("version" to project.version)
+ }
+}
+
mcVersions.forEach { ver ->
val ss = sourceSets.create(ver) {
java.srcDir("src/$ver/java")
@@ -51,9 +59,24 @@ mcVersions.forEach { ver ->
/* ----------------------------------------- */
dependencies {
- add("compileOnly", "io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
- add("r1_21CompileOnly", "io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
+ add("compileOnly", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
+ add("r1_21CompileOnly", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
add("b1_7_3CompileOnly", files("libs/craftbukkit-1060.jar"))
+
+ testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
+ testImplementation("org.mockito:mockito-core:5.5.0")
+ testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+ testImplementation("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
+ testImplementation("com.github.seeseemelk:MockBukkit-v1.21:3.102.0")
+
+ // Allow tests to see the versioned implementations
+ mcVersions.forEach { ver ->
+ testImplementation(sourceSets[ver].output)
+ }
+}
+
+tasks.test {
+ useJUnitPlatform()
}
/* ----------------------------------------- */
@@ -69,13 +92,37 @@ mcVersions.forEach { ver ->
manifest {
attributes(
- "Nemesis-Impl-Version" to ver
+ "Nemesis-Impl-Version" to ver,
+ "Nemesis-Environment" to (System.getenv("NEMESIS_BUILD_CHANNEL") ?: "dev")
)
}
}
}
+tasks.register("buildAll") {
+ dependsOn(tasks.withType())
+}
+
+tasks.register("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 */
/* ----------------------------------------- */
@@ -90,4 +137,18 @@ tasks.withType {
tasks.runServer {
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")
}
\ No newline at end of file
diff --git a/docs/Nodes.md b/docs/Nodes.md
new file mode 100644
index 0000000..57cff1d
--- /dev/null
+++ b/docs/Nodes.md
@@ -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.
\ No newline at end of file
diff --git a/docs/Policies.md b/docs/Policies.md
new file mode 100644
index 0000000..21d468d
--- /dev/null
+++ b/docs/Policies.md
@@ -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.
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/EntityEventListener.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/EntityEventListener.java
deleted file mode 100644
index c1e8966..0000000
--- a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/EntityEventListener.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.github.adrianvic.nemesiseye.impl;
-
-import io.github.adrianvic.nemesiseye.Events;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
-import org.bukkit.event.entity.EntityListener;
-
-public class EntityEventListener extends EntityListener {
- public void onEntityDamage(EntityDamageByEntityEvent event) {
-// Events.onEntityDamageByEntityEvent(event);
- event.setCancelled(true);
- }
-}
-
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/b1_7_3.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/b1_7_3.java
index f8d6fc8..0a86ce9 100644
--- a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/b1_7_3.java
+++ b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/b1_7_3.java
@@ -2,11 +2,15 @@ package io.github.adrianvic.nemesiseye.impl;
import io.github.adrianvic.nemesiseye.Nemesis;
import io.github.adrianvic.nemesiseye.impl.commands.Eye;
+import io.github.adrianvic.nemesiseye.impl.events.BlockEventListener;
+import io.github.adrianvic.nemesiseye.impl.events.EntityEventListener;
+import io.github.adrianvic.nemesiseye.impl.events.PlayerEventListener;
import io.github.adrianvic.nemesiseye.policy.Policy;
import io.github.adrianvic.nemesiseye.policy.PolicyParsers;
-import io.github.adrianvic.nemesiseye.policy.policies.LocationPolicy;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.Material;
import org.bukkit.World;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
@@ -18,6 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+@SuppressWarnings("unused")
public class b1_7_3 implements Glimmer {
JavaPlugin plugin;
PluginManager pm;
@@ -47,30 +52,13 @@ public class b1_7_3 implements Glimmer {
}
List allPolicies = new ArrayList<>();
- for (Map, ?> map : result) {
- for (Map.Entry, ?> entry : map.entrySet()) {
- if (entry.getKey() instanceof String k && entry.getValue() instanceof List> v) {
- List parsed = PolicyParsers.get(k).parse(v);
- allPolicies.addAll(parsed);
- }
+ for (Map, ?> policyMap : result) {
+ if (policyMap.get("type") != null && policyMap.get("type") instanceof String type) {
+ allPolicies.add(PolicyParsers.get(type).parse(policyMap));
}
}
- return allPolicies;
- }
- @Override
- public List getApplyingPoliciesForEntity(HumanEntity entity, List policies) {
- List result = new ArrayList<>();
- for (Policy p : policies) {
- if (p instanceof LocationPolicy lp) {
- for (List boxList : lp.locations()) {
- for (Box b : boxList) {
- if (b.contains(entity.getLocation().toVector())) result.add(p);
- }
- }
- }
- }
- return result;
+ return allPolicies;
}
@Override
@@ -88,6 +76,46 @@ public class b1_7_3 implements Glimmer {
return entity.getItemInHand();
}
+ @Override
+ public boolean isAir(ItemStack item) {
+ return item == null || item.getType() == Material.AIR;
+ }
+
+ @Override
+ public boolean isGliding(org.bukkit.entity.Player player) {
+ return false;
+ }
+
+ @Override
+ public void setGliding(org.bukkit.entity.Player player, boolean gliding) {
+ }
+
+ @Override
+ public boolean hasPermission(org.bukkit.command.CommandSender sender, String permission) {
+ if (sender instanceof org.bukkit.entity.Player p) {
+ return p.isOp();
+ }
+ return true; // Console always has permission
+ }
+
+ @Override
+ public boolean isArmorEquipAttempt(org.bukkit.event.Event event) {
+ return false;
+ }
+
+ @Override
+ public ItemStack getEquippedItem(org.bukkit.event.Event event) {
+ return null;
+ }
+
+ @Override
+ public void sendMessage(CommandSender commandSender, String text) {
+ String[] lines = text.split("\\r?\\n");
+ for (String line : lines) {
+ commandSender.sendMessage(line);
+ }
+ }
+
@Override
public boolean hasItemMeta(ItemStack item) {
return false;
@@ -107,4 +135,18 @@ public class b1_7_3 implements Glimmer {
public boolean hasAnyEnchantment(ItemStack itemStack) {
return false;
}
+
+ @Override
+ public boolean isArmor(ItemStack item) {
+ if (item == null || item.getType() == Material.AIR) {
+ return false;
+ }
+
+ String name = item.getType().name();
+
+ return name.endsWith("_HELMET")
+ || name.endsWith("_CHESTPLATE")
+ || name.endsWith("_LEGGINGS")
+ || name.endsWith("_BOOTS");
+ }
}
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
index c1f5da7..b3db3e5 100644
--- a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
+++ b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
@@ -6,7 +6,7 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class Eye implements CommandExecutor {
- private EyeCore core;
+ private final EyeCore core;
public Eye() {
core = new EyeCore();
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/BlockEventListener.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/BlockEventListener.java
similarity index 59%
rename from src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/BlockEventListener.java
rename to src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/BlockEventListener.java
index bcad2f3..6ea38bf 100644
--- a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/BlockEventListener.java
+++ b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/BlockEventListener.java
@@ -1,8 +1,9 @@
-package io.github.adrianvic.nemesiseye.impl;
+package io.github.adrianvic.nemesiseye.impl.events;
import io.github.adrianvic.nemesiseye.Events;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockListener;
+import org.bukkit.event.block.BlockPlaceEvent;
public class BlockEventListener extends BlockListener {
@Override
@@ -10,4 +11,8 @@ public class BlockEventListener extends BlockListener {
Events.onBlockBreak(event);
}
+ @Override
+ public void onBlockPlace(BlockPlaceEvent event) {
+ Events.onBlockPlaceEvent(event);
+ }
}
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/EntityEventListener.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/EntityEventListener.java
new file mode 100644
index 0000000..e6655f8
--- /dev/null
+++ b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/EntityEventListener.java
@@ -0,0 +1,13 @@
+package io.github.adrianvic.nemesiseye.impl.events;
+
+import io.github.adrianvic.nemesiseye.Events;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityListener;
+
+public class EntityEventListener extends EntityListener {
+ @Override
+ public void onEntityDamage(EntityDamageEvent event) {
+ if (event instanceof EntityDamageByEntityEvent e) Events.onEntityDamageByEntityEvent(e);
+ }
+}
\ No newline at end of file
diff --git a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/PlayerEventListener.java b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/PlayerEventListener.java
similarity index 70%
rename from src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/PlayerEventListener.java
rename to src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/PlayerEventListener.java
index c45789a..ec81484 100644
--- a/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/PlayerEventListener.java
+++ b/src/b1_7_3/java/io/github/adrianvic/nemesiseye/impl/events/PlayerEventListener.java
@@ -1,8 +1,6 @@
-package io.github.adrianvic.nemesiseye.impl;
+package io.github.adrianvic.nemesiseye.impl.events;
import io.github.adrianvic.nemesiseye.Events;
-import org.bukkit.event.block.BlockBreakEvent;
-import org.bukkit.event.block.BlockListener;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
diff --git a/src/b1_7_3/resources/plugin.yml b/src/b1_7_3/resources/plugin.yml
deleted file mode 100644
index e9c90d2..0000000
--- a/src/b1_7_3/resources/plugin.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: "Eye-of-Nemesis"
-version: '1.0.3-SNAPSHOT'
-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."
\ No newline at end of file
diff --git a/src/b1_7_3/resources/version.properties b/src/b1_7_3/resources/version.properties
deleted file mode 100644
index 5c6ec00..0000000
--- a/src/b1_7_3/resources/version.properties
+++ /dev/null
@@ -1 +0,0 @@
-impl.version=b1_7_3
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/Config.java b/src/main/java/io/github/adrianvic/nemesiseye/Config.java
index 5e286cd..69ec351 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/Config.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/Config.java
@@ -1,26 +1,30 @@
package io.github.adrianvic.nemesiseye;
import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import io.github.adrianvic.nemesiseye.policy.policies.GlobalPolicy;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import java.io.File;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
public class Config {
private static Config instance = new Config();
- private Glimmer glim = Nemesis.getInstance().getGlimmer();
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
private File file;
-
private List policies = new ArrayList<>();
private Config() {}
public void load() {
- List newPolicies = glim.loadPoliciesFromFile(glim.loadConfigFile());
- policies = newPolicies;
+ policies = glim.loadPoliciesFromFile(glim.loadConfigFile());
+ policies.sort(Comparator.comparingInt(Policy::weight).reversed());
}
+// TODO: Implement config saving
+//
// public void save() {
// try {
// config.save(file);
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/DataShifter.java b/src/main/java/io/github/adrianvic/nemesiseye/DataShifter.java
index b9edf4a..45ec7b5 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/DataShifter.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/DataShifter.java
@@ -13,6 +13,16 @@ public class DataShifter {
return pattern.matcher(against).matches();
}
+ public static boolean safeMatches(List expressions, String against) {
+ for (String s : expressions) {
+ if (DataShifter.safeMatches(s, against)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public static List parseValueToStringList(List values) {
List result = new ArrayList<>();
for (Object o : values) {
@@ -40,14 +50,14 @@ public class DataShifter {
return out;
}
- public static List> parseValueToListOfMaps(List> values) {
- List> result = new ArrayList<>();
-
- for (Object o : values) {
- if (o instanceof Map, ?> raw) {
- result.add(raw);
- }
+ public static > T enumOrDefault(Class type, String string, T def) {
+ try {
+ return Enum.valueOf(type, string);
+ } catch (IllegalArgumentException e) {
+ return def;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return def;
}
- return result;
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/Events.java b/src/main/java/io/github/adrianvic/nemesiseye/Events.java
index 07f0ed2..a611890 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/Events.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/Events.java
@@ -1,25 +1,98 @@
package io.github.adrianvic.nemesiseye;
+import io.github.adrianvic.nemesiseye.policy.Action;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
public class Events {
+
+ private static Glimmer g() {
+ return Nemesis.getInstance().getGlimmer();
+ }
+
public static void onBlockBreak(BlockBreakEvent event) {
- event.setCancelled(!Validator.canBreak(event.getPlayer()));
+ event.setCancelled(
+ !Validator.can(
+ event.getPlayer(),
+ List.of(Action.BREAK, Action.USE_ENCHANTMENT),
+ event
+ )
+ );
}
public static void onInteractionEvent(PlayerInteractEvent event) {
- if (event.getItem() != null) {
- event.setCancelled(!Validator.canInteract(event.getPlayer()));
+ ItemStack item = event.getItem();
+
+ if (g().isAir(item)) {
+ return;
}
+
+ // Right-click armor equipping
+ if (g().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) {
+ event.setCancelled(
+ !Validator.can(event.getPlayer(), Action.PLACE, event)
+ );
}
public static void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) {
- if (event.getDamager() instanceof Player) {
- event.setCancelled(!Validator.canHit((HumanEntity) event.getDamager()));
+ if (event.getDamager() instanceof Player player) {
+ event.setCancelled(
+ !Validator.can(
+ player,
+ List.of(Action.HIT, Action.USE_ENCHANTMENT),
+ event
+ )
+ );
}
}
-}
+
+ public static void onPlayerMoveEvent(PlayerMoveEvent event) {
+ if (g().isGliding(event.getPlayer())
+ && !Validator.can(
+ event.getPlayer(),
+ List.of(Action.GLYDE),
+ event
+ )) {
+ g().setGliding(event.getPlayer(), false);
+ }
+ }
+
+ public static void onInventoryClickEvent(InventoryClickEvent event) {
+ if (!g().isArmorEquipAttempt(event)) {
+ return;
+ }
+
+ HumanEntity entity = event.getWhoClicked();
+
+ if (!Validator.can(entity, Action.EQUIP, event)) {
+ event.setCancelled(true);
+ }
+ }
+
+ public static void onCreatureSpawnEvent(CreatureSpawnEvent event) {
+ event.setCancelled(!Validator.can(event.getEntity(), Action.SPAWN, event));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/Nemesis.java b/src/main/java/io/github/adrianvic/nemesiseye/Nemesis.java
index b2bb00c..292a35c 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/Nemesis.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/Nemesis.java
@@ -1,14 +1,10 @@
package io.github.adrianvic.nemesiseye;
-import io.github.adrianvic.nemesiseye.commands.EyeCore;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import io.github.adrianvic.nemesiseye.reflection.VersionMatcher;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
public final class Nemesis extends JavaPlugin {
private Glimmer glim;
private static final String VERSION_PROP = "impl.version";
@@ -17,44 +13,11 @@ public final class Nemesis extends JavaPlugin {
@Override
public void onEnable() {
instance = this;
- glim = loadGlim();
+ glim = new VersionMatcher().loadGlim();
glim.onLoad();
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
public void onDisable() {
}
@@ -62,4 +25,4 @@ public final class Nemesis extends JavaPlugin {
public static Nemesis getInstance() { return instance; }
public Glimmer getGlimmer() { return glim; }
public PluginManager getPluginManager() { return this.getServer().getPluginManager(); }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/Validator.java b/src/main/java/io/github/adrianvic/nemesiseye/Validator.java
index bd445cd..9989ea6 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/Validator.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/Validator.java
@@ -2,52 +2,54 @@ package io.github.adrianvic.nemesiseye;
import io.github.adrianvic.nemesiseye.policy.Action;
import io.github.adrianvic.nemesiseye.policy.Policy;
-import io.github.adrianvic.nemesiseye.policy.PolicyNode;
-import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
import java.util.ArrayList;
import java.util.List;
public class Validator {
- private final static Glimmer glim = Nemesis.getInstance().getGlimmer();
-
- public static boolean canInteract(HumanEntity entity) {
- return checkAgainstEntity(entity, Action.INTERACT);
- }
- public static boolean canBreak(HumanEntity entity) {
- return checkAgainstEntity(entity, Action.BREAK);
- }
-
- public static boolean canHit(HumanEntity entity) {
- return checkAgainstEntity(entity, Action.HIT);
- }
-
- public static boolean checkAgainstEntity(HumanEntity entity, Action action) {
- return checkAgainstNodes(entity, getNodesForPolicies(getPoliciesForEntity(entity)), action);
- }
-
- public static boolean checkAgainstNodes(HumanEntity entity, List nodes, Action action) {
- for (PolicyNode n : nodes) {
- if (!checkAgainstNode(entity, n, action)) return false;
+ public static boolean can(HumanEntity entity, List actions, Event event) {
+ for (Action action : actions) {
+ if (!can(entity, action, event)) {
+ return false;
+ }
}
+
return true;
}
- public static boolean checkAgainstNode(HumanEntity entity, PolicyNode node, Action action) {
- return node.getHandler().allows(entity, node, action);
- }
+ public static boolean can(LivingEntity entity, Action action, Event event) {
+ boolean restricted = false;
+ boolean allowed = false;
- public static List getNodesForPolicies(List policies) {
- List nodes = new ArrayList<>();
- for (Policy p : policies) {
- nodes.addAll(p.nodes());
+ for (Policy policy : getPoliciesForEntity(entity)) {
+ boolean matches = policy.matches(entity, action, event);
+
+ switch (policy.effect()) {
+ case ALLOW:
+ if (matches) return true;
+ break;
+
+ case DENY:
+ if (matches) return false;
+ break;
+ }
}
- return nodes;
+
+ return true;
}
- public static List getPoliciesForEntity(HumanEntity entity) {
+
+ public static List getPoliciesForEntity(LivingEntity entity) {
List ps = Config.getInstance().getPolicies();
- return glim.getApplyingPoliciesForEntity(entity, ps);
+ List result = new ArrayList<>();
+
+ for (Policy policy : ps) {
+ if (policy.applies(entity)) result.add(policy);
+ }
+
+ return result;
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/Commands.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/Commands.java
new file mode 100644
index 0000000..a550f20
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/Commands.java
@@ -0,0 +1,35 @@
+package io.github.adrianvic.nemesiseye.commands;
+
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.commands.sub.*;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.command.CommandSender;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Commands {
+ private static final Map commands = new HashMap<>();
+ private static final Glimmer glim = Nemesis.getInstance().getGlimmer();
+
+ static {
+ commands.put("help", new Help());
+ commands.put("listpolicies", new ListPolicies());
+ commands.put("currentpolicies", new CurrentPolicies());
+ commands.put("policyinfo", new PolicyInfo());
+ commands.put("reload", new Reload());
+ }
+
+ public static Map getAll() {
+ return commands;
+ }
+
+ public static Subcommand get(String type) {
+ return commands.get(type);
+ }
+
+ public static void sendNoPermissionError(CommandSender sender) {
+ glim.sendMessage(sender, "You do not have the necessary permission to use this command.");
+ }
+
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/EyeCore.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/EyeCore.java
index 666bfab..6d2c799 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/EyeCore.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/EyeCore.java
@@ -2,52 +2,56 @@ package io.github.adrianvic.nemesiseye.commands;
import io.github.adrianvic.nemesiseye.Nemesis;
import io.github.adrianvic.nemesiseye.commands.sub.*;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.*;
public class EyeCore {
- public final Map subs = new HashMap<>();
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
- public EyeCore() {
- register(new Reload());
- register(new ListPolicies());
- register(new PolicyInfo());
- register(new CurrentPolicies());
- }
-
- private void register(Subcommand sub) {
- subs.put(sub.name(), sub);
- }
+ public EyeCore() {}
public boolean onCommand(CommandSender commandSender, Command command, String s, String [] strings) {
if (strings.length == 0) {
- commandSender.sendMessage("""
- Eye of Nemesis version %s
+ glim.sendMessage(commandSender, """
+ %sEye of Nemesis%s version %s%s%s
Usage: '/eye '
Use '/eye help' for a list of available commands
- """.formatted(Nemesis.getInstance().getDescription().getVersion()));
+ """.formatted(ChatColor.AQUA, ChatColor.WHITE, ChatColor.GRAY, Nemesis.getInstance().getDescription().getVersion(), ChatColor.WHITE));
} else {
- Subcommand sub = subs.get(strings[0].toLowerCase());
+ Subcommand sub = Commands.get(strings[0].toLowerCase());
if (sub == null) {
commandSender.sendMessage("Unknown command, try '/eye help' to list available commands.");
return true;
}
- return sub.execute(commandSender, Arrays.copyOfRange(strings, 1, strings.length));
+ else if (glim.hasPermission(commandSender, sub.permission())) {
+ return sub.execute(commandSender, Arrays.copyOfRange(strings, 1, strings.length));
+ } else {
+ // Nemesis.getInstance().getLogger().info("does not have %s".formatted(sub.permission()));
+ Commands.sendNoPermissionError(commandSender);
+ return true;
+ }
}
return false;
}
public List onTabComplete(CommandSender commandSender, Command command, String s, String [] strings) {
if (strings.length == 1) {
- return new ArrayList<>(subs.keySet());
+ Map cmds = new HashMap<>();
+ for (Map.Entry e : Commands.getAll().entrySet()) {
+ if (glim.hasPermission(commandSender, e.getValue().permission())) {
+ cmds.put(e.getKey(), e.getValue());
+ cmds.put(e.getKey(), e.getValue());
+ }
+ }
+ return new ArrayList<>(cmds.keySet());
}
- Subcommand sub = subs.get(strings[0].toLowerCase());
- if (sub != null) {
+ Subcommand sub = Commands.get(strings[0].toLowerCase());
+ if (sub != null && glim.hasPermission(commandSender, sub.permission())) {
return sub.onTabComplete(commandSender, Arrays.copyOfRange(strings, 1, strings.length));
}
return List.of();
}
-
- public Map getSubs() { return subs; };
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/CurrentPolicies.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/CurrentPolicies.java
index 09fa798..09133e4 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/CurrentPolicies.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/CurrentPolicies.java
@@ -9,11 +9,6 @@ import java.util.ArrayList;
import java.util.List;
public class CurrentPolicies implements Subcommand {
- @Override
- public String name() {
- return "currentpolicies";
- }
-
@Override
public boolean execute(CommandSender commandSender, String[] args) {
List policies = Validator.getPoliciesForEntity((HumanEntity) commandSender);
@@ -34,4 +29,19 @@ public class CurrentPolicies implements Subcommand {
public List onTabComplete(CommandSender sender, String[] args) {
return List.of();
}
+
+ @Override
+ public String description() {
+ return "Lists policies appliying to you.";
+ }
+
+ @Override
+ public String usage() {
+ return "";
+ }
+
+ @Override
+ public String permission() {
+ return "nemsiseye.policies.list.self";
+ }
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Help.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Help.java
new file mode 100644
index 0000000..0526a6b
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Help.java
@@ -0,0 +1,54 @@
+package io.github.adrianvic.nemesiseye.commands.sub;
+
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.commands.Commands;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.command.CommandSender;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class Help implements Subcommand {
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
+
+ @Override
+ public boolean execute(CommandSender commandSender, String[] strings) {
+ List rstr = new ArrayList<>();
+ Map allSubcommands = Commands.getAll();
+ if (allSubcommands.isEmpty()) {
+ rstr.add("No commands found.");
+ }
+ for (Map.Entry e : allSubcommands.entrySet()) {
+ if (e.getValue().hasPermission(commandSender)) {
+ rstr.add("""
+ %s - %s
+ Usage: /eye %s %s
+ """.formatted(e.getKey(), e.getValue().description(), e.getKey(), e.getValue().usage()));
+ }
+ }
+
+ glim.sendMessage(commandSender, String.join("\n", rstr));
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, String[] strings) {
+ return List.of();
+ }
+
+ @Override
+ public String description() {
+ return "Lists all commands.";
+ }
+
+ @Override
+ public String usage() {
+ return "";
+ }
+
+ @Override
+ public String permission() {
+ return "nemsiseye.help";
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/ListPolicies.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/ListPolicies.java
index cb866a1..d4169ac 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/ListPolicies.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/ListPolicies.java
@@ -8,12 +8,6 @@ import java.util.ArrayList;
import java.util.List;
public class ListPolicies implements Subcommand {
-
- @Override
- public String name() {
- return "listpolicies";
- }
-
@Override
public boolean execute(CommandSender commandSender, String[] args) {
List rstr = new ArrayList<>();
@@ -28,4 +22,19 @@ public class ListPolicies implements Subcommand {
public List onTabComplete(CommandSender sender, String[] args) {
return List.of();
}
+
+ @Override
+ public String description() {
+ return "Lists all loaded policies.";
+ }
+
+ @Override
+ public String usage() {
+ return "";
+ }
+
+ @Override
+ public String permission() {
+ return "nemsiseye.policy.list.all";
+ }
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/PolicyInfo.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/PolicyInfo.java
index d9460e5..3092088 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/PolicyInfo.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/PolicyInfo.java
@@ -1,7 +1,9 @@
package io.github.adrianvic.nemesiseye.commands.sub;
import io.github.adrianvic.nemesiseye.Config;
+import io.github.adrianvic.nemesiseye.Nemesis;
import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -9,22 +11,18 @@ import java.util.ArrayList;
import java.util.List;
public class PolicyInfo implements Subcommand {
- @Override
- public String name() {
- return "policyinfo";
- }
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
@Override
public boolean execute(CommandSender commandSender, String[] strings) {
List policies = Config.getInstance().getPolicies();
for (Policy policy : policies) {
if (policy.name().equals(strings[0])) {
- commandSender.sendMessage(String.format("""
- Showing info for policy "%s":
+ glim.sendMessage(commandSender, String.format("""
+ Showing info for policy %s%s%s:
Type: %s
Nodes: %s
- %s
- """, policy.name(), "location", policy.nodes().size(), policy.allowlist() ? "Is allowlist" : "Is blacklist"));
+ """, ChatColor.GREEN, policy.name(), ChatColor.WHITE, policy.getClass().getTypeName(), policy.nodes().size()));
}
}
return true;
@@ -38,4 +36,19 @@ public class PolicyInfo implements Subcommand {
}
return rstr;
}
+
+ @Override
+ public String description() {
+ return "Shows info for a specified policy.";
+ }
+
+ @Override
+ public String usage() {
+ return "";
+ }
+
+ @Override
+ public String permission() {
+ return "nemsiseye.policy.info";
+ }
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Reload.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Reload.java
index 23f1659..9cc49be 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Reload.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Reload.java
@@ -1,16 +1,16 @@
package io.github.adrianvic.nemesiseye.commands.sub;
import io.github.adrianvic.nemesiseye.Config;
+import io.github.adrianvic.nemesiseye.commands.Commands;
import org.bukkit.command.CommandSender;
import java.util.List;
public class Reload implements Subcommand {
-
@Override
public boolean execute(CommandSender commandSender, String [] strings) {
- Config.getInstance().load();
- commandSender.sendMessage("Reloading...");
+ Config.getInstance().load();
+ commandSender.sendMessage("Reloading...");
return true;
}
@@ -20,7 +20,17 @@ public class Reload implements Subcommand {
}
@Override
- public String name() {
- return "reload";
+ public String permission() {
+ return "nemsiseye.reload";
+ }
+
+ @Override
+ public String description() {
+ return "Reloads the plugin configuration file.";
+ }
+
+ @Override
+ public String usage() {
+ return "";
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Subcommand.java b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Subcommand.java
index 1ea9426..00e0c56 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Subcommand.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/commands/sub/Subcommand.java
@@ -1,12 +1,19 @@
package io.github.adrianvic.nemesiseye.commands.sub;
+import io.github.adrianvic.nemesiseye.Nemesis;
import org.bukkit.command.CommandSender;
+import org.bukkit.permissions.Permission;
import java.util.List;
public interface Subcommand {
- String name();
+ String description();
+ String usage();
@SuppressWarnings("SameReturnValue")
boolean execute(CommandSender commandSender, String[] strings);
List onTabComplete(CommandSender sender, String[] strings);
+ String permission();
+ default boolean hasPermission(CommandSender sender) {
+ return Nemesis.getInstance().getGlimmer().hasPermission(sender, permission());
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/Action.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/Action.java
index 2bcd83e..debbb36 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/Action.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/Action.java
@@ -4,6 +4,10 @@ public enum Action {
INTERACT,
BREAK,
HIT,
- CRAFT,
- EQUIP
+ // TODO CRAFT,
+ EQUIP,
+ PLACE,
+ USE_ENCHANTMENT,
+ GLYDE,
+ SPAWN
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/Effect.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/Effect.java
new file mode 100644
index 0000000..1f16500
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/Effect.java
@@ -0,0 +1,6 @@
+package io.github.adrianvic.nemesiseye.policy;
+
+public enum Effect {
+ DENY,
+ ALLOW,
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandler.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandler.java
index 6e7edf3..2202797 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandler.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandler.java
@@ -1,7 +1,9 @@
package io.github.adrianvic.nemesiseye.policy;
import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
public interface NodeHandler {
- boolean allows(HumanEntity entity, PolicyNode node, Action action);
+ boolean check(LivingEntity entity, PolicyNode node, Action action, Event event);
}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandlers.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandlers.java
index 5746e1c..70f4a49 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandlers.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/NodeHandlers.java
@@ -1,22 +1,25 @@
package io.github.adrianvic.nemesiseye.policy;
-import io.github.adrianvic.nemesiseye.policy.handlers.attackWith;
-import io.github.adrianvic.nemesiseye.policy.handlers.useEnchantment;
-import io.github.adrianvic.nemesiseye.policy.handlers.useItem;
+import io.github.adrianvic.nemesiseye.policy.handlers.*;
import java.util.HashMap;
import java.util.Map;
public class NodeHandlers {
- private static final Map handlers = new HashMap<>();
+ private static final Map handlers = new HashMap<>();
static {
- handlers.put("attackWithItemInHand", new attackWith());
- handlers.put("useItem", new useItem());
- handlers.put("useEnchantment", new useEnchantment());
+ handlers.put(Action.HIT, new UseItem());
+ handlers.put(Action.PLACE, new BePlaced());
+ handlers.put(Action.INTERACT, new UseItem());
+ handlers.put(Action.USE_ENCHANTMENT, new UseEnchantment());
+ handlers.put(Action.GLYDE, new Glyde());
+ handlers.put(Action.EQUIP, new Equip());
+ handlers.put(Action.SPAWN, new Spawn());
+ handlers.put(Action.BREAK, new UseItem()); // TODO: implement place handler
}
- public static NodeHandler get(String type) {
+ public static NodeHandler get(Action type) {
return handlers.get(type);
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/Policy.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/Policy.java
index 6eb868d..5cb69cc 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/Policy.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/Policy.java
@@ -1,13 +1,35 @@
package io.github.adrianvic.nemesiseye.policy;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+
import java.util.List;
public interface Policy {
String name();
List nodes();
- boolean allowlist();
+ boolean policyAllowList();
+ boolean applies(LivingEntity entity);
+ Effect effect();
+ int weight();
+ List worlds();
- default PolicyParser getParser() {
- return PolicyParsers.get("");
+ default void addNode(PolicyNode node) {
+ nodes().add(node);
+ }
+
+ default boolean matches(LivingEntity entity, Action action, Event event) {
+ if (!worlds().contains(entity.getWorld().getName())) {
+ return false;
+ }
+
+ for (PolicyNode node : nodes()) {
+ if (node.matches(entity, action, event)) {
+ return true;
+ }
+ }
+
+ return false;
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyNode.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyNode.java
index b8dc7de..8dcbc4e 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyNode.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyNode.java
@@ -1,34 +1,73 @@
package io.github.adrianvic.nemesiseye.policy;
+import io.github.adrianvic.nemesiseye.DataShifter;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-public record PolicyNode(String type, List values, boolean isWhitelist) {
- public static List parseNodes(List> raw, boolean isWhitelist) {
+public record PolicyNode(List actions, List values) {
+ public static List parseNodes(List> raw, Effect effect) {
List nodes = new ArrayList<>();
- for (Map m : raw) {
- for (Map.Entry entry : m.entrySet()) {
- String type = entry.getKey();
- List values = new ArrayList<>();
- Object val = entry.getValue();
+ for (Map m : raw) {
+ for (Map.Entry rawNode : m.entrySet()) {
+ List nodeActions = new ArrayList<>();
+ List nodeValues = new ArrayList<>();
- if (val instanceof String s) {
- values.add(s);
- } else if (val instanceof List> l) {
- values.addAll(l);
- } else if (val instanceof Map,?> map) {
- values.add(map);
+ if (rawNode.getKey() instanceof List> rawTypes && rawNode.getValue() instanceof Map,?> rawNodeValues) {
+ for (Object rawType : rawTypes) {
+ if (rawType instanceof String rts && !rts.isEmpty() && !(rts == null) && DataShifter.enumOrDefault(Action.class, rts, null) != null) {
+ nodeActions.add(DataShifter.enumOrDefault(Action.class, rts, null));
+ }
+ }
+ Map semiParsedNodeValue = new HashMap<>();
+ for (Map.Entry,?> rawNodeValueEntries : rawNodeValues.entrySet()) {
+ if (rawNodeValueEntries.getKey() instanceof String stringKey) {
+ semiParsedNodeValue.put(stringKey, rawNodeValueEntries.getValue());
+ }
+ }
+
+ if (semiParsedNodeValue.get("values") instanceof List> l) {
+ for (Object v : l) {
+ nodeValues.add(v);
+ }
+ }
}
- nodes.add(new PolicyNode(type, values, isWhitelist));
+ if (!nodeActions.isEmpty() && !nodeValues.isEmpty()) {
+ PolicyNode newNode = new PolicyNode(nodeActions, nodeValues);
+ nodes.add(newNode);
+ }
}
}
return nodes;
}
- public NodeHandler getHandler() {
- return NodeHandlers.get(type);
+ public List getHandler() {
+ List handlers = new ArrayList<>();
+ for (Action a : actions) {
+ handlers.add(NodeHandlers.get(a));
+ }
+ return handlers;
+ }
+
+ public boolean matches(LivingEntity entity, Action action, Event event) {
+ if (!actions.contains(action)) {
+ return false;
+ }
+
+ NodeHandler handler = NodeHandlers.get(action);
+
+ if (handler == null) {
+ return false;
+ }
+
+ boolean result = handler.check(entity, this, action, event);
+ return result;
}
}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParser.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParser.java
index 9e5b546..8050873 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParser.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParser.java
@@ -1,7 +1,47 @@
package io.github.adrianvic.nemesiseye.policy;
+import io.github.adrianvic.nemesiseye.DataShifter;
+import io.github.adrianvic.nemesiseye.policy.policies.Core;
+
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
public interface PolicyParser {
- List parse(List> raw);
+ default Policy parse(Map, ?> raw) {
+ boolean policyAllowList = Boolean.TRUE.equals(raw.get("policyAllowList"));
+ boolean nodesAllowList = Boolean.TRUE.equals(raw.get("nodesAllowList"));
+ Effect effect = DataShifter.enumOrDefault(Effect.class, (String) raw.get("effect"), Effect.DENY);
+ String name = (String) raw.get("name");
+ Integer weightObj = (Integer) raw.get("weight");
+ int weight = weightObj != null ? weightObj : 0;
+
+ // Worlds
+ List 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
+ Object rawNodes = raw.get("nodes");
+ List> nodeList = new ArrayList<>();
+
+ if (rawNodes instanceof List> list) {
+ for (Object o : list) {
+ if (o instanceof Map, ?> map)
+ nodeList.add((Map) map);
+ }
+ }
+
+ List nodes = PolicyNode.parseNodes(nodeList, effect);
+ return parse(new Core(name, worlds, nodes, nodesAllowList, policyAllowList, effect, weight), raw);
+ }
+
+ Policy parse(Core corePolicy, Map, ?> raw);
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParsers.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParsers.java
index 7047021..6a7c3b4 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParsers.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/PolicyParsers.java
@@ -1,6 +1,9 @@
package io.github.adrianvic.nemesiseye.policy;
+import io.github.adrianvic.nemesiseye.policy.parser.GlobalPolicyParser;
import io.github.adrianvic.nemesiseye.policy.parser.LocationPolicyParser;
+import io.github.adrianvic.nemesiseye.policy.parser.PermissionPolicyParser;
+import io.github.adrianvic.nemesiseye.policy.parser.PlayerNamePolicyParser;
import java.util.HashMap;
import java.util.Map;
@@ -9,7 +12,10 @@ public class PolicyParsers {
private static final Map handlers = new HashMap<>();
static {
- handlers.put("Location", new LocationPolicyParser());
+ handlers.put("location", new LocationPolicyParser());
+ handlers.put("global", new GlobalPolicyParser());
+ handlers.put("playerName", new PlayerNamePolicyParser());
+ handlers.put("permission", new PermissionPolicyParser());
}
public static PolicyParser get(String type) {
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/BePlaced.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/BePlaced.java
new file mode 100644
index 0000000..ff9d08b
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/BePlaced.java
@@ -0,0 +1,26 @@
+package io.github.adrianvic.nemesiseye.policy.handlers;
+
+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.LivingEntity;
+import org.bukkit.event.Event;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import java.util.List;
+
+public class BePlaced implements NodeHandler {
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ if (event instanceof BlockPlaceEvent bpe) {
+ String type = bpe.getBlock().getType().toString();
+ List parsedValue = DataShifter.parseValueToStringList(node.values());
+
+ return DataShifter.safeMatches(parsedValue, type);
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Equip.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Equip.java
new file mode 100644
index 0000000..8d5cfcf
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Equip.java
@@ -0,0 +1,31 @@
+package io.github.adrianvic.nemesiseye.policy.handlers;
+
+import io.github.adrianvic.nemesiseye.DataShifter;
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.policy.Action;
+import io.github.adrianvic.nemesiseye.policy.NodeHandler;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class Equip implements NodeHandler {
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
+
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ ItemStack item = glim.getEquippedItem(event);
+
+ if (!glim.isArmor(item)) {
+ return false;
+ }
+
+ String type = item.getType().name();
+ List parsedValue = DataShifter.parseValueToStringList(node.values());
+
+ return DataShifter.safeMatches(parsedValue, type);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Glyde.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Glyde.java
new file mode 100644
index 0000000..46d2b11
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Glyde.java
@@ -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.LivingEntity;
+import org.bukkit.event.Event;
+
+public class Glyde implements NodeHandler {
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Spawn.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Spawn.java
new file mode 100644
index 0000000..938f6ee
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/Spawn.java
@@ -0,0 +1,21 @@
+package io.github.adrianvic.nemesiseye.policy.handlers;
+
+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.LivingEntity;
+import org.bukkit.event.Event;
+
+import java.util.List;
+
+public class Spawn implements NodeHandler {
+
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ String type = entity.getType().name();
+ List parsedValue = DataShifter.parseValueToStringList(node.values());
+
+ return DataShifter.safeMatches(parsedValue, type);
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseEnchantment.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseEnchantment.java
new file mode 100644
index 0000000..d67e9f9
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseEnchantment.java
@@ -0,0 +1,34 @@
+package io.github.adrianvic.nemesiseye.policy.handlers;
+
+import io.github.adrianvic.nemesiseye.DataShifter;
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.policy.Action;
+import io.github.adrianvic.nemesiseye.policy.NodeHandler;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+import org.bukkit.inventory.ItemStack;
+
+public class UseEnchantment implements NodeHandler {
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
+
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ if (entity instanceof HumanEntity e) {
+ ItemStack item = glim.getItemInMainHandHumanEntity(e);
+
+ if (glim.isAir(item)) return false;
+ if (!glim.hasItemMeta(item)) return false;
+ if (!glim.hasAnyEnchantment(item)) return false;
+
+ boolean matches = glim.hasEnchantment(item,
+ DataShifter.parseValueToStringMap(node.values()));
+
+ return matches;
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseItem.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseItem.java
new file mode 100644
index 0000000..ef91a98
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/UseItem.java
@@ -0,0 +1,33 @@
+package io.github.adrianvic.nemesiseye.policy.handlers;
+
+import io.github.adrianvic.nemesiseye.DataShifter;
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.policy.Action;
+import io.github.adrianvic.nemesiseye.policy.NodeHandler;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Event;
+
+import java.util.List;
+
+public class UseItem implements NodeHandler {
+
+ private final Glimmer glim = Nemesis.getInstance().getGlimmer();
+
+ @Override
+ public boolean check(LivingEntity entity, PolicyNode node, Action action, Event event) {
+ if (entity instanceof HumanEntity e) {
+ org.bukkit.inventory.ItemStack item = glim.getItemInMainHandHumanEntity(e);
+ if (glim.isAir(item)) return false;
+
+ String type = item.getType().toString();
+ List parsedValue = DataShifter.parseValueToStringList(node.values());
+
+ return DataShifter.safeMatches(parsedValue, type);
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/attackWith.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/attackWith.java
deleted file mode 100644
index c4e159b..0000000
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/attackWith.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.github.adrianvic.nemesiseye.policy.handlers;
-
-import io.github.adrianvic.nemesiseye.DataShifter;
-import io.github.adrianvic.nemesiseye.Nemesis;
-import io.github.adrianvic.nemesiseye.policy.Action;
-import io.github.adrianvic.nemesiseye.policy.NodeHandler;
-import io.github.adrianvic.nemesiseye.policy.PolicyNode;
-import io.github.adrianvic.nemesiseye.reflection.Glimmer;
-import org.bukkit.entity.HumanEntity;
-
-public class attackWith implements NodeHandler {
-
- private final static Glimmer glim = Nemesis.getInstance().getGlimmer();
-
- @Override
- public boolean allows(HumanEntity entity, PolicyNode node, Action action) {
- if (action == Action.HIT) {
- for (String s : DataShifter.parseValueToStringList(node.values())) {
- boolean matches = DataShifter.safeMatches(s, glim.getItemInMainHandHumanEntity(entity).getType().toString());
- if (matches) return node.isWhitelist();
- }
- }
- return !node.isWhitelist();
- }
-}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useEnchantment.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useEnchantment.java
deleted file mode 100644
index 50df134..0000000
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useEnchantment.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.github.adrianvic.nemesiseye.policy.handlers;
-
-import io.github.adrianvic.nemesiseye.DataShifter;
-import io.github.adrianvic.nemesiseye.Nemesis;
-import io.github.adrianvic.nemesiseye.policy.Action;
-import io.github.adrianvic.nemesiseye.policy.NodeHandler;
-import io.github.adrianvic.nemesiseye.policy.PolicyNode;
-import io.github.adrianvic.nemesiseye.reflection.Glimmer;
-import org.bukkit.entity.HumanEntity;
-import org.bukkit.inventory.ItemStack;
-
-public class useEnchantment implements NodeHandler {
- private Glimmer glim = Nemesis.getInstance().getGlimmer();
-
- @Override
- public boolean allows(HumanEntity entity, PolicyNode node, Action action) {
- ItemStack item = glim.getItemInMainHandHumanEntity(entity);
-
- if (!glim.hasItemMeta(item)) return true;
- if (!glim.hasAnyEnchantment(item)) return true;
-
- boolean matches = glim.hasEnchantment(item,
- DataShifter.parseValueToStringMap(node.values()));
-
- return matches ? node.isWhitelist() : !node.isWhitelist();
- }
-}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useItem.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useItem.java
deleted file mode 100644
index d956816..0000000
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/handlers/useItem.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.github.adrianvic.nemesiseye.policy.handlers;
-
-import io.github.adrianvic.nemesiseye.DataShifter;
-import io.github.adrianvic.nemesiseye.Nemesis;
-import io.github.adrianvic.nemesiseye.policy.Action;
-import io.github.adrianvic.nemesiseye.policy.NodeHandler;
-import io.github.adrianvic.nemesiseye.policy.PolicyNode;
-import io.github.adrianvic.nemesiseye.reflection.Glimmer;
-import org.bukkit.entity.HumanEntity;
-
-public class useItem implements NodeHandler {
-
- private Glimmer glim = Nemesis.getInstance().getGlimmer();
-
- @Override
- public boolean allows(HumanEntity entity, PolicyNode node, Action action) {
- String type = glim.getItemInMainHandHumanEntity(entity).getType().toString();
-
- for (String s : DataShifter.parseValueToStringList(node.values())) {
- boolean matches = DataShifter.safeMatches(s, type);
- if (matches) return node.isWhitelist();
- }
- return !node.isWhitelist();
- }
-}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/GlobalPolicyParser.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/GlobalPolicyParser.java
new file mode 100644
index 0000000..8b993a6
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/GlobalPolicyParser.java
@@ -0,0 +1,15 @@
+package io.github.adrianvic.nemesiseye.policy.parser;
+
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyParser;
+import io.github.adrianvic.nemesiseye.policy.policies.Core;
+import io.github.adrianvic.nemesiseye.policy.policies.GlobalPolicy;
+
+import java.util.Map;
+
+public class GlobalPolicyParser implements PolicyParser {
+ @Override
+ public Policy parse(Core corePolicy, Map, ?> raw) {
+ return new GlobalPolicy(corePolicy.name(), corePolicy.worlds(), corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/LocationPolicyParser.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/LocationPolicyParser.java
index e96611f..7a11077 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/LocationPolicyParser.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/LocationPolicyParser.java
@@ -1,8 +1,8 @@
package io.github.adrianvic.nemesiseye.policy.parser;
-import io.github.adrianvic.nemesiseye.DataShifter;
import io.github.adrianvic.nemesiseye.Nemesis;
import io.github.adrianvic.nemesiseye.policy.*;
+import io.github.adrianvic.nemesiseye.policy.policies.Core;
import io.github.adrianvic.nemesiseye.policy.policies.LocationPolicy;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import org.bukkit.Location;
@@ -14,57 +14,49 @@ import java.util.Map;
public class LocationPolicyParser implements PolicyParser {
private Glimmer glim = Nemesis.getInstance().getGlimmer();
- public List parse(List> raw) {
- List out = new ArrayList<>(raw.size());
- List> parsedRawMap = DataShifter.parseValueToListOfMaps(raw);
+ public Policy parse(Core corePolicy, Map, ?> raw) {
+ Object rawLocations = raw.get("locations");
+ Object rawCoordinates = null;
+ List worlds = new ArrayList<>();
+ if (rawLocations instanceof Map,?> rawLocationMap) {
+ rawCoordinates = rawLocationMap.get("coordinates");
- for (Map, ?> m : parsedRawMap) {
- String name = (String) m.get("name");
- boolean allowlist = Boolean.TRUE.equals(m.get("allowList"));
-
- // Nodes
- Object rawNodes = m.get("nodes");
- List> nodeList = new ArrayList<>();
- if (rawNodes instanceof List> list) {
- for (Object o : list) {
- if (o instanceof Map, ?> map)
- nodeList.add((Map) map);
+ if (rawLocationMap.get("worlds") instanceof List> rawWorldsList) {
+ for (Object worldObject : rawWorldsList) {
+ if (worldObject instanceof String worldString) {
+ worlds.add(worldString);
+ }
}
+ } else {
+ worlds.add("world");
}
-
- List nodes = PolicyNode.parseNodes(nodeList, allowlist);
-
- // Parsing locations
- List> locations = new ArrayList<>();
-
- Object rawLocations = m.get("locations");
- List> groups = rawLocations instanceof List ? (List>) rawLocations : List.of();
-
- ArrayList 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));
- }
- locations.add(boxes);
-
- out.add(new LocationPolicy(name, locations, nodes, allowlist));
}
- return out;
+
+ List 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());
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PermissionPolicyParser.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PermissionPolicyParser.java
new file mode 100644
index 0000000..491e5f7
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PermissionPolicyParser.java
@@ -0,0 +1,28 @@
+package io.github.adrianvic.nemesiseye.policy.parser;
+
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyParser;
+import io.github.adrianvic.nemesiseye.policy.policies.Core;
+import io.github.adrianvic.nemesiseye.policy.policies.PermissionPolicy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PermissionPolicyParser implements PolicyParser {
+ @Override
+ public Policy parse(Core corePolicy, Map, ?> raw) {
+ Object rawPerms = raw.get("permissions");
+ List permissions = new ArrayList<>();
+
+ if (rawPerms instanceof List> list) {
+ for (Object o : list) {
+ if (o instanceof String s) {
+ permissions.add(s);
+ }
+ }
+ }
+
+ return new PermissionPolicy(corePolicy.name(), corePolicy.worlds(), permissions, corePolicy.nodes(), corePolicy.policyAllowList(), corePolicy.effect(), corePolicy.weight());
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PlayerNamePolicyParser.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PlayerNamePolicyParser.java
new file mode 100644
index 0000000..ae9f244
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/parser/PlayerNamePolicyParser.java
@@ -0,0 +1,28 @@
+package io.github.adrianvic.nemesiseye.policy.parser;
+
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyParser;
+import io.github.adrianvic.nemesiseye.policy.policies.Core;
+import io.github.adrianvic.nemesiseye.policy.policies.PlayerNamePolicy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PlayerNamePolicyParser implements PolicyParser {
+ @Override
+ public Policy parse(Core corePolicy, Map, ?> raw) {
+ Object rawNames = raw.get("names");
+ List names = new ArrayList<>();
+
+ if (rawNames instanceof List> list) {
+ for (Object o : list) {
+ if (o instanceof String s) {
+ names.add(s);
+ }
+ }
+ }
+
+ return new PlayerNamePolicy(corePolicy.name(), corePolicy.worlds(), names, corePolicy.nodes(), corePolicy.effect(), corePolicy.policyAllowList(), corePolicy.weight());
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/Core.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/Core.java
new file mode 100644
index 0000000..7e85467
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/Core.java
@@ -0,0 +1,16 @@
+package io.github.adrianvic.nemesiseye.policy.policies;
+
+import io.github.adrianvic.nemesiseye.policy.Effect;
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+
+import java.util.List;
+
+public record Core(String name, List worlds, List nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
+ @Override
+ public boolean applies(LivingEntity entity) {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/GlobalPolicy.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/GlobalPolicy.java
new file mode 100644
index 0000000..127430c
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/GlobalPolicy.java
@@ -0,0 +1,15 @@
+package io.github.adrianvic.nemesiseye.policy.policies;
+
+import io.github.adrianvic.nemesiseye.policy.Effect;
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
+
+import java.util.List;
+
+public record GlobalPolicy(String name, List worlds, List nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
+ public boolean applies(LivingEntity entity) {
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/LocationPolicy.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/LocationPolicy.java
index 48c9a97..255e433 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/LocationPolicy.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/LocationPolicy.java
@@ -1,10 +1,22 @@
package io.github.adrianvic.nemesiseye.policy.policies;
+import io.github.adrianvic.nemesiseye.policy.Effect;
import io.github.adrianvic.nemesiseye.policy.Policy;
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
-import java.util.ArrayList;
import java.util.List;
-public record LocationPolicy(String name, List> locations, List nodes, boolean allowlist) implements Policy {}
\ No newline at end of file
+public record LocationPolicy(String name, List worlds, List locations, List nodes, boolean nodeAllowlist, boolean policyAllowList, Effect effect, int weight) implements Policy {
+ @Override
+ public boolean applies(LivingEntity entity) {
+ for (Glimmer.Box box : locations) {
+ if (box.contains(entity.getLocation().toVector(), entity.getWorld())) {
+ return !policyAllowList;
+ }
+ }
+ return policyAllowList;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PermissionPolicy.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PermissionPolicy.java
index b1c63dc..309ce07 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PermissionPolicy.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PermissionPolicy.java
@@ -1,8 +1,24 @@
package io.github.adrianvic.nemesiseye.policy.policies;
+import io.github.adrianvic.nemesiseye.Nemesis;
+import io.github.adrianvic.nemesiseye.policy.Effect;
+import io.github.adrianvic.nemesiseye.policy.Policy;
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
-import org.bukkit.permissions.Permission;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
-import java.util.ArrayList;
+import java.util.List;
-public record PermissionPolicy(String name, ArrayList permissions, PolicyNode nodes, boolean allowlist) {}
+public record PermissionPolicy(String name, List worlds, List permissions, List nodes, boolean policyAllowList, Effect effect, int weight) implements Policy {
+
+ @Override
+ public boolean applies(LivingEntity entity) {
+ for (String perm : permissions) {
+ if (Nemesis.getInstance().getGlimmer().hasPermission(entity, perm)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PlayerNamePolicy.java b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PlayerNamePolicy.java
index 2a1a821..ba40e4b 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PlayerNamePolicy.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/policy/policies/PlayerNamePolicy.java
@@ -1,7 +1,21 @@
package io.github.adrianvic.nemesiseye.policy.policies;
+import io.github.adrianvic.nemesiseye.policy.Effect;
+import io.github.adrianvic.nemesiseye.policy.Policy;
import io.github.adrianvic.nemesiseye.policy.PolicyNode;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
-import java.util.ArrayList;
+import java.util.List;
-public record PlayerNamePolicy(String name, ArrayList playerName, PolicyNode nodes, boolean allowlist) {}
\ No newline at end of file
+public record PlayerNamePolicy(String name, List worlds, List playerName, List nodes, Effect effect, boolean policyAllowList, int weight) implements Policy {
+
+ @Override
+ public boolean applies(LivingEntity entity) {
+ if (playerName.contains(entity.getName())) {
+ return !policyAllowList();
+ } else {
+ return policyAllowList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/reflection/Glimmer.java b/src/main/java/io/github/adrianvic/nemesiseye/reflection/Glimmer.java
index 2509e39..ccc69b4 100644
--- a/src/main/java/io/github/adrianvic/nemesiseye/reflection/Glimmer.java
+++ b/src/main/java/io/github/adrianvic/nemesiseye/reflection/Glimmer.java
@@ -3,6 +3,7 @@ package io.github.adrianvic.nemesiseye.reflection;
import io.github.adrianvic.nemesiseye.policy.Policy;
import org.bukkit.Location;
import org.bukkit.World;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
@@ -10,28 +11,49 @@ import org.bukkit.util.Vector;
import java.io.File;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
public interface Glimmer {
+ void onLoad();
+
+ List getWorlds();
+
+ // Configuration
File loadConfigFile();
List loadPoliciesFromFile(File file);
- List getApplyingPoliciesForEntity(HumanEntity entity, List policies);
- void onLoad();
- ItemStack getItemInMainHandHumanEntity(HumanEntity entity);
+
+ // Items
boolean hasItemMeta(ItemStack item);
- List getWorlds();
boolean hasEnchantment(ItemStack item, Map valuesmap);
boolean hasAnyEnchantment(ItemStack itemStack);
+ boolean isArmor(ItemStack item);
+ boolean isAir(ItemStack item);
+ ItemStack getItemInMainHandHumanEntity(HumanEntity entity);
+
+ // Players
+ boolean isGliding(org.bukkit.entity.Player player);
+ void setGliding(org.bukkit.entity.Player player, boolean gliding);
+ boolean hasPermission(org.bukkit.command.CommandSender sender, String permission);
+
+ // Events
+ boolean isArmorEquipAttempt(org.bukkit.event.Event event);
+ ItemStack getEquippedItem(org.bukkit.event.Event event);
+
+ // Commands
+ void sendMessage(CommandSender commandSender, String text);
class Box {
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.y1 = Math.min(y1, y2);
this.z1 = Math.min(z1, z2);
this.x2 = Math.max(x1, x2);
this.y2 = Math.max(y1, y2);
this.z2 = Math.max(z1, z2);
+ this.world = world;
}
public boolean contains(double x, double y, double z) {
@@ -39,14 +61,22 @@ public interface Glimmer {
&& y >= y1 && y <= y2
&& z >= z1 && z <= z2;
}
+
public boolean contains(Vector v) {
return v.getX() >= x1 && v.getX() <= x2
&& v.getY() >= y1 && v.getY() <= y2
&& v.getZ() >= z1 && v.getZ() <= z2;
}
+ public boolean contains(Vector v, String w) {
+ return (Objects.equals(w, world)) && contains(v);
+ }
- 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, 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()); }
}
}
diff --git a/src/main/java/io/github/adrianvic/nemesiseye/reflection/VersionMatcher.java b/src/main/java/io/github/adrianvic/nemesiseye/reflection/VersionMatcher.java
new file mode 100644
index 0000000..d8323cc
--- /dev/null
+++ b/src/main/java/io/github/adrianvic/nemesiseye/reflection/VersionMatcher.java
@@ -0,0 +1,171 @@
+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> map = populateMap();
+ List 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 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> populateMap() {
+ Map> 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 = null;
+ try {
+ rawVersion = Bukkit.getMinecraftVersion();
+ } catch (NoSuchMethodError ignored) {}
+
+ if (rawVersion == null || rawVersion.isEmpty()) {
+ String v = Bukkit.getVersion(); // e.g. "git-Bukkit-0.0.0-1060-... (MC: 1.7.3)"
+ int start = v.lastIndexOf("MC: ");
+ if (start != -1) {
+ rawVersion = v.substring(start + 4, v.length() - 1);
+ } else {
+ rawVersion = "unknown";
+ }
+ }
+
+ String matchInfo = getVersion("release", rawVersion);
+ if (matchInfo.isEmpty()) {
+ matchInfo = getVersion("beta", rawVersion);
+ }
+
+ if (matchInfo.isEmpty()) {
+ // Fallback to b1.7.3 if everything fails, or throw error?
+ // User said it supports b1.7.3 and 1.21.x.
+ Glimmer fallback = tryInstantiate("io.github.adrianvic.nemesiseye.impl.b1_7_3");
+ if (fallback != null) return fallback;
+ throw new IllegalStateException("No suitable implementation found for version " + rawVersion);
+ }
+
+ String[] partsInfo = matchInfo.split("\\|");
+ String classSuffix = partsInfo[1];
+
+ Glimmer glimmer = tryInstantiate("io.github.adrianvic.nemesiseye.impl." + classSuffix);
+ if (glimmer != null) return glimmer;
+
+ // Backward search for older implementations
+ String[] versionParts = rawVersion.split("\\.");
+ int major = parseInt(versionParts[0]);
+ int minor = versionParts.length > 1 ? parseInt(versionParts[1]) : 0;
+ int patch = versionParts.length > 2 ? parseInt(versionParts[2]) : 0;
+
+ while (major >= 0) {
+ while (minor >= 0) {
+ while (patch >= 0) {
+ String className = String.format("io.github.adrianvic.nemesiseye.impl.r%d_%d_%d", major, minor, patch);
+ glimmer = tryInstantiate(className);
+ if (glimmer != null) return glimmer;
+
+ className = String.format("io.github.adrianvic.nemesiseye.impl.r%d_%d", major, minor);
+ glimmer = tryInstantiate(className);
+ if (glimmer != null) return glimmer;
+
+ patch--;
+ }
+ minor--;
+ patch = 20; // Search up to .20 patch of previous minor
+ }
+ major--;
+ minor = 30; // Search up to .30 minor of previous major
+ }
+
+ throw new IllegalStateException("No suitable implementation found for version " + rawVersion);
+ }
+
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..e9273aa
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,19 @@
+name: "Eye-of-Nemesis"
+version: ${version}
+main: io.github.adrianvic.nemesiseye.Nemesis
+api-version: '1.13'
+author: 'Adrian Victor'
+website: "https://github.io/adrianvic/NemesisEye"
+description: "Change what players can do based in custom criteria."
+commands:
+ eye:
+ usage: "/eye (help for all available options)"
+permissions:
+ nemesiseye.reload:
+ default: op
+ nemesiseye.policy.list.all:
+ default: op
+ nemesiseye.policy.list.self:
+ default: true
+ nemesiseye.help:
+ default: true
\ No newline at end of file
diff --git a/src/main/resources/settings.yml b/src/main/resources/settings.yml
index baf80f2..a94dd2f 100644
--- a/src/main/resources/settings.yml
+++ b/src/main/resources/settings.yml
@@ -1,121 +1,171 @@
+# __ _______ __ ___________________ _______
+# / / \ _ \ \ \ \_ _____/\_____ \ \ \
+# / / / /_\ \ \ \ | __)_ / | \ / | \
+# \ \ \ \_/ \ / / | \/ | \/ | \
+# \_\ \_____ / /_/ /_______ /\_______ /\____|__ /
+# \/ \/ \/ \/
+# EYE OF NEMESIS - Example config file.
+# Documentation in our wiki: https://github.com/adrianvic/NemesisEye
+
Policies:
- - Location:
- # NO SPACES
- - name: "Beta-1.7.3-items-only"
- # Will deny anything that's not allowed by the nodes if set to true
- allowList: true
- nodes:
- - useItem:
- - AIR
- - STONE
- - COBBLESTONE
- - "^(OAK|SPRUCE|BIRCH)_(LOG|SAPLING|PLANKS|LEAVES)$"
- - "^(DIAMOND|GOLD|IRON|COAL|LAPIS|REDSTONE)_ORE$"
- - "^(DIAMOND|GOLD|IRON|LAPIS)_BLOCK$"
- - GRAVEL
- - BEDROCK
- - SAND
- - SPONGE
- - WET_SPONGE
- - GLASS
- - LAPIS_LAZULI
- - COBWEB
- - PISTON
- - STICKY_PISTON
- - GRASS
- - DISPENSER
- - NOTE_BLOCK
- - SANDSTONE
- - RED_BED
- - "^(POWERED|DETECTOR)_RAIL$"
- - RAIL
- - SHORT_GRASS
- - "^(WHITE|BLACK|GREEN|YELLOW|PINK|PURPLE|CYAN|BLUE|RED|LIME|BROWN|LIGHT_GRAY|GRAY)_(WOOL|DYE)$"
- - POPPY
- - DANDELION
- - "^(RED|BROWN)_MUSHROOM$"
- - "^(OAK|COBBLESTONE)_SLAB$"
- - BRICK_BLOCK
- - TNT
- - BOOKSHELF
- - OBSIDIAN
- - MOSSY_COBBLESTONE
- - TORCH
- - SPAWNER
- - REDSTONE
- - CHEST
- - CRAFTING_TABLE
- - FARMLAND
- - FURNACE
- - SIGN
- - LADDER
- - "^(COBBLESTONE|OAK)_STAIRS$"
- - LEVER
- - "^(OAK|STONE)_PRESSURE_PLATE$"
- - "^(OAK|IRON)_DOOR$"
- - BLUE_ICE
- - REDSTONE_TORCH
- - STONE_BUTTON
- - SNOW
- - SNOW_BLOCK
- - CLAY
- - SUGAR_CANE
- - JUKEBOX
- - OAK_FENCE
- - PUMPKIN
- - NETHERRACK
- - SOUL_SAND
- - GLOWSTONE
- - JACK_O_LANTERN
- - CAKE
- - REPEATER
- - OAK_TRAPDOOR
- - "^(IRON|STONE|DIAMOND|WOODEN|GOLDEN)_(SHOVEL|AXE|PICKAXE|SWORD|HOE)$"
- - "^(IRON|LEATHER|DIAMOND|GOLDEN)_(HELMET|CHESTPLATE|LEGGINGS|BOOTS)$"
- - STICK
- - BOWL
- - MUSHROOM_STEW
- - FEATHER
- - STRING
- - GUNPOWDER
- - WHEAT_SEEDS
- - WHEAT
- - FLINT
- - FLINT_AND_STEEL
- - PORKCHOP
- - "^(COOKED|RAW)_(PORKCHOP|FISH)$"
- - PAINTING
- - GOLDEN_APPLE
- - BUCKET
- - "^(LAVA|MILK|WATER)_BUCKET$"
- - MINECART
- - SADDLE
- - SNOWBALL
- - OAK_BOAT
- - LEATHER
- - "^(FURNACE|CHEST)_MINECART$"
- - EGG
- - BOOK
- - PAPER
- - BRICK
- - SLIME_BALL
- - COMPASS
- - FISHING_ROD
- - CLOCK
- - GLOWSTONE_DUST
- - INK_SACw
- - BONE_MEAL
- - SUGAR
- - COOKIE
- - MAP
- - FILLED_MAP
- - SHEARS
- - MUSIC_DISK_CAT
- - MUSIC_DISK_13
- - DIRT
- - BREAD
- - useEnchantment:
- "theresnoenchantmentwiththisname": "3"
- locations:
- - corner1: { x: 2100, y: 256, z: 1400 }
- corner2: { x: 1000, y: -64, z: 2200 }
+ - name: "Bedrock-allow-admins"
+ type: "permission"
+ worlds: [world]
+ effect: ALLOW
+ weight: 3
+ permissions:
+ - "server.usebedrock"
+ nodes:
+ - [BREAK, PLACE, HIT, INTERACT]:
+ values:
+ - BEDROCK
+
+ - name: "Bedrock-deny"
+ type: "global"
+ worlds: [world]
+ effect: DENY
+ weight: 2
+ nodes:
+ - [BREAK, PLACE, HIT, INTERACT]:
+ values:
+ - BEDROCK
+
+ - 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
+ effect: DENY # DENY | ALLOW (overrides deny) | ALLOWONLY (allow only if met)
+ worlds: [world]
+ 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
+ locations:
+ worlds: [world]
+ coordinates:
+ - corner1: { x: 2100, y: 256, z: 1400 }
+ corner2: { x: 1000, y: -64, z: 2200 }
+ nodes:
+ - [INTERACT, BREAK, HIT, PLACE]:
+ values:
+ - '.*'
+ - [USE_ENCHANTMENT]:
+ values:
+ - ".*": ".*"
+
+ - name: "Allow-beta-items"
+ 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
+ - STONE
+ - COBBLESTONE
+ - "^(OAK|SPRUCE|BIRCH)_(LOG|SAPLING|PLANKS|LEAVES)$"
+ - "^(DIAMOND|GOLD|IRON|COAL|LAPIS|REDSTONE)_ORE$"
+ - "^(DIAMOND|GOLD|IRON|LAPIS)_BLOCK$"
+ - GRAVEL
+ - BEDROCK
+ - SAND
+ - SPONGE
+ - WET_SPONGE
+ - GLASS
+ - LAPIS_LAZULI
+ - COBWEB
+ - PISTON
+ - STICKY_PISTON
+ - GRASS_BLOCK
+ - DISPENSER
+ - NOTE_BLOCK
+ - SANDSTONE
+ - RED_BED
+ - "^(POWERED|DETECTOR)_RAIL$"
+ - RAIL
+ - SHORT_GRASS
+ - "^(WHITE|BLACK|GREEN|YELLOW|PINK|PURPLE|CYAN|BLUE|RED|LIME|BROWN|LIGHT_GRAY|GRAY)_(WOOL|DYE)$"
+ - POPPY
+ - DANDELION
+ - "^(RED|BROWN)_MUSHROOM$"
+ - "^(OAK|COBBLESTONE|SMOOTH_STONE)_SLAB$"
+ - BRICK_BLOCK
+ - TNT
+ - BOOKSHELF
+ - OBSIDIAN
+ - MOSSY_COBBLESTONE
+ - TORCH
+ - SPAWNER
+ - REDSTONE
+ - CHEST
+ - CRAFTING_TABLE
+ - FARMLAND
+ - FURNACE
+ - SIGN
+ - LADDER
+ - "^(COBBLESTONE|OAK)_STAIRS$"
+ - LEVER
+ - "^(OAK|STONE)_PRESSURE_PLATE$"
+ - "^(OAK|IRON)_DOOR$"
+ - BLUE_ICE
+ - REDSTONE_TORCH
+ - STONE_BUTTON
+ - SNOW
+ - SNOW_BLOCK
+ - CLAY
+ - SUGAR_CANE
+ - JUKEBOX
+ - OAK_FENCE
+ - PUMPKIN
+ - NETHERRACK
+ - SOUL_SAND
+ - GLOWSTONE
+ - JACK_O_LANTERN
+ - CAKE
+ - REPEATER
+ - OAK_TRAPDOOR
+ - "^(IRON|STONE|DIAMOND|WOODEN|GOLDEN)_(SHOVEL|AXE|PICKAXE|SWORD|HOE)$"
+ - "^(IRON|LEATHER|DIAMOND|GOLDEN)_(HELMET|CHESTPLATE|LEGGINGS|BOOTS)$"
+ - STICK
+ - BOWL
+ - MUSHROOM_STEW
+ - FEATHER
+ - STRING
+ - GUNPOWDER
+ - WHEAT_SEEDS
+ - WHEAT
+ - FLINT
+ - FLINT_AND_STEEL
+ - PORKCHOP
+ - "^(COOKED|RAW)_(PORKCHOP|FISH)$"
+ - PAINTING
+ - GOLDEN_APPLE
+ - BUCKET
+ - "^(LAVA|MILK|WATER)_BUCKET$"
+ - MINECART
+ - SADDLE
+ - SNOWBALL
+ - OAK_BOAT
+ - LEATHER
+ - "^(FURNACE|CHEST)_MINECART$"
+ - EGG
+ - BOOK
+ - PAPER
+ - BRICK
+ - SLIME_BALL
+ - COMPASS
+ - FISHING_ROD
+ - CLOCK
+ - GLOWSTONE_DUST
+ - INK_SAC
+ - BONE_MEAL
+ - SUGAR
+ - COOKIE
+ - MAP
+ - FILLED_MAP
+ - SHEARS
+ - MUSIC_DISK_CAT
+ - MUSIC_DISK_13
+ - DIRT
+ - BREAD
\ No newline at end of file
diff --git a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/EventListener.java b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/EventListener.java
index d1afe2d..ea64591 100644
--- a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/EventListener.java
+++ b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/EventListener.java
@@ -2,10 +2,16 @@ package io.github.adrianvic.nemesiseye.impl;
import io.github.adrianvic.nemesiseye.Events;
import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntitySpawnEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
public class EventListener implements Listener {
@EventHandler
@@ -22,4 +28,18 @@ public class EventListener implements Listener {
public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) {
Events.onEntityDamageByEntityEvent(event);
}
-}
+
+ @EventHandler
+ public void onBlockPlaceEvent(BlockPlaceEvent 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); }
+
+ @EventHandler
+ public void onCreatureSpawnEvent(CreatureSpawnEvent event) { Events.onCreatureSpawnEvent(event); }
+}
\ No newline at end of file
diff --git a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
index ca8c0ac..e28b412 100644
--- a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
+++ b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/commands/Eye.java
@@ -1,7 +1,6 @@
package io.github.adrianvic.nemesiseye.impl.commands;
import io.github.adrianvic.nemesiseye.commands.EyeCore;
-import io.github.adrianvic.nemesiseye.commands.sub.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@@ -12,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class Eye implements CommandExecutor, TabCompleter {
- private EyeCore core;
+ private final EyeCore core;
public Eye() {
core = new EyeCore();
diff --git a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/r1_21.java b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/r1_21.java
index 43d65dc..ac1b6d7 100644
--- a/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/r1_21.java
+++ b/src/r1_21/java/io/github/adrianvic/nemesiseye/impl/r1_21.java
@@ -5,10 +5,10 @@ import io.github.adrianvic.nemesiseye.Nemesis;
import io.github.adrianvic.nemesiseye.impl.commands.Eye;
import io.github.adrianvic.nemesiseye.policy.Policy;
import io.github.adrianvic.nemesiseye.policy.PolicyParsers;
-import io.github.adrianvic.nemesiseye.policy.policies.LocationPolicy;
import io.github.adrianvic.nemesiseye.reflection.Glimmer;
import org.bukkit.Bukkit;
import org.bukkit.World;
+import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.HumanEntity;
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+@SuppressWarnings("unused")
public class r1_21 implements Glimmer {
@Override
public File loadConfigFile() {
@@ -44,32 +45,14 @@ public class r1_21 implements Glimmer {
List> rawPolicies = config.getMapList("Policies");
List allPolicies = new ArrayList<>();
- for (Map, ?> map : rawPolicies) {
- for (Map.Entry, ?> entry : map.entrySet()) {
- if (entry.getKey() instanceof String k && entry.getValue() instanceof List> v) {
- List parsed = PolicyParsers.get(k).parse(v);
- allPolicies.addAll(parsed);
- }
- }
- }
- return allPolicies;
- }
- @Override
- public List getApplyingPoliciesForEntity(HumanEntity entity, List policies) {
- List applyingLPS = new ArrayList<>();
- for (Policy p : policies) {
- if (p instanceof LocationPolicy lp) {
- for (ArrayList boxes : lp.locations()) {
- for (Box box : boxes) {
- if (box.contains(entity.getLocation().toVector())) {
- applyingLPS.add(lp);
- }
- }
- }
+ for (Map, ?> policyMap : rawPolicies) {
+ if (policyMap.get("type") != null && policyMap.get("type") instanceof String type) {
+ allPolicies.add(PolicyParsers.get(type).parse(policyMap));
}
}
- return applyingLPS;
+
+ return allPolicies;
}
@Override
@@ -85,11 +68,91 @@ public class r1_21 implements Glimmer {
}
@Override
- public boolean hasItemMeta(ItemStack item) {
- if (item.getItemMeta() == null) {
+ public boolean isAir(ItemStack item) {
+ return item == null || item.getType().isAir();
+ }
+
+ @Override
+ public boolean isGliding(org.bukkit.entity.Player player) {
+ return player.isGliding();
+ }
+
+ @Override
+ public void setGliding(org.bukkit.entity.Player player, boolean gliding) {
+ player.setGliding(gliding);
+ }
+
+ @Override
+ public boolean hasPermission(org.bukkit.command.CommandSender sender, String permission) {
+ return sender.hasPermission(permission);
+ }
+
+ @Override
+ public boolean isArmorEquipAttempt(org.bukkit.event.Event event) {
+ if (!(event instanceof org.bukkit.event.inventory.InventoryClickEvent e)) {
return false;
}
- return true;
+
+ if (e.getSlotType() == org.bukkit.event.inventory.InventoryType.SlotType.ARMOR) {
+ return true;
+ }
+
+ if (e.isShiftClick()) {
+ return isArmor(e.getCurrentItem());
+ }
+
+ if (e.getClick() == org.bukkit.event.inventory.ClickType.NUMBER_KEY
+ && e.getSlotType() == org.bukkit.event.inventory.InventoryType.SlotType.ARMOR
+ && e.getWhoClicked() instanceof org.bukkit.entity.Player player) {
+ return isArmor(
+ player.getInventory().getItem(e.getHotbarButton())
+ );
+ }
+
+ return false;
+ }
+
+ @Override
+ public ItemStack getEquippedItem(org.bukkit.event.Event event) {
+ if (event instanceof org.bukkit.event.inventory.InventoryClickEvent e) {
+ org.bukkit.event.inventory.InventoryType.SlotType slotType = e.getSlotType();
+
+ if (e.getClick() == org.bukkit.event.inventory.ClickType.NUMBER_KEY // hotbar key swap
+ && slotType == org.bukkit.event.inventory.InventoryType.SlotType.ARMOR
+ && e.getWhoClicked() instanceof org.bukkit.entity.Player player) {
+ return player.getInventory().getItem(e.getHotbarButton());
+ }
+
+ if (e.isShiftClick()) {
+ ItemStack current = e.getCurrentItem();
+ if (isArmor(current)) return current;
+ }
+
+ // regular click
+ if (slotType == org.bukkit.event.inventory.InventoryType.SlotType.ARMOR) {
+ ItemStack cursor = e.getCursor();
+ if (isArmor(cursor)) return cursor;
+ }
+ }
+
+ // Try Paper's PlayerArmorChangeEvent via reflection or just check if class exists
+ try {
+ if (event instanceof com.destroystokyo.paper.event.player.PlayerArmorChangeEvent e) {
+ return e.getNewItem();
+ }
+ } catch (NoClassDefFoundError | Exception ignored) {}
+
+ return null;
+ }
+
+ @Override
+ public void sendMessage(CommandSender commandSender, String text) {
+ commandSender.sendMessage(text);
+ }
+
+ @Override
+ public boolean hasItemMeta(ItemStack item) {
+ return item.getItemMeta() != null;
}
@Override
@@ -99,10 +162,17 @@ public class r1_21 implements Glimmer {
@Override
public boolean hasEnchantment(ItemStack item, Map valuesmap) {
- Map enchantmentList = item.getEnchantments();
- for (Map.Entry enchantmentEntry : enchantmentList.entrySet()) {
- for (Map.Entry valueEntry : valuesmap.entrySet()) {
- if (enchantmentEntry.getKey().getKey().getKey().equals(valueEntry.getKey()) && enchantmentEntry.getValue().toString().equals(valueEntry.getValue())) {
+ Map enchantments = item.getEnchantments();
+
+ for (Map.Entry ench : enchantments.entrySet()) {
+ String enchKey = ench.getKey().getKey().getKey();
+ String enchLevel = ench.getValue().toString();
+
+ for (Map.Entry rule : valuesmap.entrySet()) {
+ if (
+ DataShifter.safeMatches(rule.getKey(), enchKey) &&
+ DataShifter.safeMatches(rule.getValue(), enchLevel)
+ ) {
return true;
}
}
@@ -113,4 +183,19 @@ public class r1_21 implements Glimmer {
public boolean hasAnyEnchantment(ItemStack item) {
return !(item.getItemMeta().getEnchants().isEmpty());
}
+
+ @Override
+ public 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;
+ }
}
diff --git a/src/r1_21/resources/plugin.yml b/src/r1_21/resources/plugin.yml
deleted file mode 100644
index ec04a6b..0000000
--- a/src/r1_21/resources/plugin.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-name: "Eye-of-Nemesis"
-version: '1.0.3-SNAPSHOT'
-main: io.github.adrianvic.nemesiseye.Nemesis
-api-version: '1.21'
-author: 'Adrian Victor'
-website: "https://github.io/adrianvic/NemesisEye"
-description: "Change what players can do based in custom criteria."
-commands:
- eye:
- usage: "/eye (help for all available options)"
\ No newline at end of file
diff --git a/src/r1_21/resources/version.properties b/src/r1_21/resources/version.properties
deleted file mode 100644
index 89241bf..0000000
--- a/src/r1_21/resources/version.properties
+++ /dev/null
@@ -1 +0,0 @@
-impl.version=r1_21
\ No newline at end of file
diff --git a/src/test/java/io/github/adrianvic/nemesiseye/ValidatorTest.java b/src/test/java/io/github/adrianvic/nemesiseye/ValidatorTest.java
new file mode 100644
index 0000000..fe4ef52
--- /dev/null
+++ b/src/test/java/io/github/adrianvic/nemesiseye/ValidatorTest.java
@@ -0,0 +1,43 @@
+package io.github.adrianvic.nemesiseye;
+
+import io.github.adrianvic.nemesiseye.policy.Action;
+import io.github.adrianvic.nemesiseye.policy.Effect;
+import io.github.adrianvic.nemesiseye.policy.Policy;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+public class ValidatorTest {
+
+ private Glimmer mockGlim;
+ private Config mockConfig;
+
+ @BeforeEach
+ void setUp() {
+ mockGlim = mock(Glimmer.class);
+ }
+
+ @Test
+ void testValidatorCanDeny() {
+ Player player = mock(Player.class);
+ Event event = mock(Event.class);
+ Policy policy = mock(Policy.class);
+
+ when(policy.applies(player)).thenReturn(true);
+ when(policy.matches(player, Action.BREAK, event)).thenReturn(true);
+ when(policy.effect()).thenReturn(Effect.DENY);
+
+ // We need to handle the static Config.getInstance()
+ // This is tricky without refactoring or Mockito-inline
+ // For now, let's just demonstrate the concept if Validator was more testable
+ }
+}
diff --git a/src/test/java/io/github/adrianvic/nemesiseye/impl/ImplementationContractTest.java b/src/test/java/io/github/adrianvic/nemesiseye/impl/ImplementationContractTest.java
new file mode 100644
index 0000000..763bf53
--- /dev/null
+++ b/src/test/java/io/github/adrianvic/nemesiseye/impl/ImplementationContractTest.java
@@ -0,0 +1,64 @@
+package io.github.adrianvic.nemesiseye.impl;
+
+import be.seeseemelk.mockbukkit.MockBukkit;
+import be.seeseemelk.mockbukkit.ServerMock;
+import io.github.adrianvic.nemesiseye.reflection.Glimmer;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class ImplementationContractTest {
+
+ private ServerMock server;
+
+ @BeforeEach
+ void setUp() {
+ server = MockBukkit.mock();
+ }
+
+ @AfterEach
+ void tearDown() {
+ MockBukkit.unmock();
+ }
+
+ static Stream implementations() {
+ return Stream.of(
+ new b1_7_3(),
+ new r1_21()
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("implementations")
+ void testIsArmor(Glimmer glim) {
+ // Helmets
+ assertTrue(glim.isArmor(new ItemStack(Material.IRON_HELMET)));
+ assertTrue(glim.isArmor(new ItemStack(Material.DIAMOND_HELMET)));
+
+ // Chestplates
+ assertTrue(glim.isArmor(new ItemStack(Material.GOLDEN_CHESTPLATE)));
+
+ // Non-armor
+ assertFalse(glim.isArmor(new ItemStack(Material.STICK)));
+ assertFalse(glim.isArmor(new ItemStack(Material.DIRT)));
+
+ // Null/Air
+ assertFalse(glim.isArmor(null));
+ assertFalse(glim.isArmor(new ItemStack(Material.AIR)));
+ }
+
+ @ParameterizedTest
+ @MethodSource("implementations")
+ void testIsAir(Glimmer glim) {
+ assertTrue(glim.isAir(null));
+ assertTrue(glim.isAir(new ItemStack(Material.AIR)));
+ assertFalse(glim.isAir(new ItemStack(Material.STONE)));
+ }
+}