diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
new file mode 100644
index 0000000..752bb1b
--- /dev/null
+++ b/.github/workflows/gradle.yml
@@ -0,0 +1,23 @@
+name: Gradle Build
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/checkout@v4
+ with:
+ repository: headhunter45/ScoreKeeper
+ path: ScoreKeeper
+ - uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: '25'
+ - uses: gradle/actions/setup-gradle@v4
+ - run: ./gradlew publishToMavenLocal
+ working-directory: ScoreKeeper
+ - run: ./gradlew test build
\ No newline at end of file
diff --git a/README.md b/README.md
index 69d2cf5..523d381 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ ScoreTable:
Restart the server after editing the configuration. A configured value of `0` suppresses that entity from the score table shown to players when they join.
-MobScores has no commands of its own. Current killer attribution is recorded for zombie entities directly damaged by a player; projectile and other mob attribution are not currently handled. Points are awarded through ScoreKeeper's existing player API and follow the player's UUID-backed score.
+MobScores has no commands of its own. It records credit for configured entity types damaged directly by a player or by a projectile fired by a player. Other mob attribution is not currently handled. Points are awarded through ScoreKeeper's existing player API and follow the player's UUID-backed score.
## Build
diff --git a/TODO.md b/TODO.md
index e18d937..90bfdfe 100644
--- a/TODO.md
+++ b/TODO.md
@@ -17,7 +17,7 @@
| MS-13 | Done | Build the plugin with Gradle (./gradlew build) and test on a modern Paper server using the provided bash scripts.
| MS-14 | Done | Address any bugs or incompatibilities found during testing on a modern server.
| MS-15 | Done | Update README.md and CONTRIBUTING.md with new build, usage, and development instructions. _(Depends on: bugfixes)_
-| MS-16 | Ready | (Optional) Add new features, quality-of-life improvements, automated tests, or CI configuration. _(Depends on: docs update)_
+| MS-16 | Done | (Optional) Add new features, quality-of-life improvements, automated tests, or CI configuration. _(Depends on: docs update)_
| MS-17 | Done | Update MobScores to depend on the latest version of the ScoreKeeper plugin (update dependency in build.gradle and plugin.yml as needed).
| MS-18 | Ready | Test MobScores with the latest ScoreKeeper to ensure score tracking, awarding, and all integration points work as expected (including with players who have changed names).
| MS-19 | Done | Refactor MobDeathListener and PlayerConnectListener to implement Listener interface and use @EventHandler annotations instead of extending EntityListener/PlayerListener.
diff --git a/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/MobScoresPlugin.java b/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/MobScoresPlugin.java
index 47bff12..f324795 100644
--- a/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/MobScoresPlugin.java
+++ b/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/MobScoresPlugin.java
@@ -18,7 +18,6 @@ along with MobScores. If not, see .
package com.majinnaibu.minecraft.plugins.mobscores;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
@@ -29,7 +28,6 @@ import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
-import org.bukkit.entity.Zombie;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@@ -58,12 +56,9 @@ public class MobScoresPlugin extends JavaPlugin {
// Create the default config if it doesn't exist.
saveDefaultConfig();
- getConfig().set("ScoreTable", serializeScoreTable(getDefaultScoreTable()));
- saveConfig();
-
// Load our score table from config or set defaults.
if (getConfig().isConfigurationSection("ScoreTable")) {
- deserializeScoreTable(getConfig().getConfigurationSection("ScoreTable").getValues(false));
+ _scoreTable = deserializeScoreTable(getConfig().getConfigurationSection("ScoreTable").getValues(false));
} else {
_scoreTable = getDefaultScoreTable();
getConfig().set("ScoreTable", serializeScoreTable(_scoreTable));
@@ -113,7 +108,7 @@ public class MobScoresPlugin extends JavaPlugin {
}
public void claimMob(Entity entity, Player damager) {
- if(entity instanceof Zombie){
+ if (_scoreTable.containsKey(entity.getType())) {
_claimedMobs.put(entity.getUniqueId(), damager.getUniqueId());
}
}
@@ -137,14 +132,12 @@ public class MobScoresPlugin extends JavaPlugin {
}
public void sendPlayerScoreTable(Player player) {
- Iterator> i = _scoreTable.entrySet().iterator();
- Map.Entry pair = null;
- for(pair = i.next(); i.hasNext(); pair = i.next()){
- if(pair.getValue() != 0){
- EntityType type = pair.getKey();
+ for (Map.Entry entry : _scoreTable.entrySet()) {
+ if (entry.getValue() != 0) {
+ EntityType type = entry.getKey();
Component message = Component.translatable(type.translationKey())
.append(Component.text(" = "))
- .append(Component.text(String.valueOf(pair.getValue()))
+ .append(Component.text(String.valueOf(entry.getValue()))
.color(NamedTextColor.GREEN));
sendPlayerMessage(player, message);
}
diff --git a/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/listeners/MobDeathListener.java b/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/listeners/MobDeathListener.java
index 6779a84..ea3fed0 100644
--- a/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/listeners/MobDeathListener.java
+++ b/src/main/java/com/majinnaibu/minecraft/plugins/mobscores/listeners/MobDeathListener.java
@@ -19,6 +19,7 @@ package com.majinnaibu.minecraft.plugins.mobscores.listeners;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
@@ -37,12 +38,19 @@ public class MobDeathListener implements Listener {
@EventHandler
public void onEntityDamage(EntityDamageEvent event) {
- if(event instanceof EntityDamageByEntityEvent){
- EntityDamageByEntityEvent ev = (EntityDamageByEntityEvent) event;
- Entity damager = ev.getDamager();
- if(damager instanceof Player){
- _plugin.claimMob(ev.getEntity(), (Player)damager);
- }
+ if (!(event instanceof EntityDamageByEntityEvent damageEvent)) {
+ return;
+ }
+ Entity damager = damageEvent.getDamager();
+ Player creditedPlayer = null;
+ if (damager instanceof Player directPlayer) {
+ creditedPlayer = directPlayer;
+ } else if (damager instanceof Projectile projectile
+ && projectile.getShooter() instanceof Player projectileShooter) {
+ creditedPlayer = projectileShooter;
+ }
+ if (creditedPlayer != null) {
+ _plugin.claimMob(event.getEntity(), creditedPlayer);
}
}