Add configurable score change reporting

This commit is contained in:
2026-09-26 18:20:10 -07:00
parent 1773361716
commit e4bebd3908
7 changed files with 112 additions and 9 deletions

View File

@@ -22,8 +22,14 @@ public final class ScoreBucket {
private final String _singular;
private final String _plural;
private final int _initialValue;
private final ScoreReporting _reporting;
public ScoreBucket(String id, String singular, String plural, int initialValue) {
this(id, singular, plural, initialValue, ScoreReporting.NONE);
}
public ScoreBucket(
String id, String singular, String plural, int initialValue, ScoreReporting reporting) {
if (id == null || !id.matches("[A-Za-z0-9_-]+")) {
throw new IllegalArgumentException("Bucket ID must contain only letters, numbers, _ or -");
}
@@ -33,10 +39,14 @@ public final class ScoreBucket {
if (plural == null || plural.isBlank()) {
throw new IllegalArgumentException("Bucket plural label cannot be blank");
}
if (reporting == null) {
throw new IllegalArgumentException("Bucket reporting policy cannot be null");
}
_id = id;
_singular = singular;
_plural = plural;
_initialValue = initialValue;
_reporting = reporting;
}
public String getId() {
@@ -54,4 +64,8 @@ public final class ScoreBucket {
public int getInitialValue() {
return _initialValue;
}
public ScoreReporting getReporting() {
return _reporting;
}
}

View File

@@ -61,6 +61,7 @@ public class ScoreKeeperPlugin extends JavaPlugin {
scores.set(path + ".singular", bucket.getSingular());
scores.set(path + ".plural", bucket.getPlural());
scores.set(path + ".initial-value", bucket.getInitialValue());
scores.set(path + ".reporting", bucket.getReporting().name().toLowerCase());
for (var entry : _bucketScores.get(bucket.getId()).entrySet()) {
scores.set(path + ".scores." + entry.getKey(), entry.getValue());
}
@@ -129,8 +130,12 @@ public class ScoreKeeperPlugin extends JavaPlugin {
}
public void setScore(Player player, String bucketId, int score) {
requireBucket(bucketId);
ScoreBucket bucket = requireBucket(bucketId);
int oldScore = getScore(player, bucketId);
_bucketScores.get(bucketId).put(player.getUniqueId(), score);
if (oldScore != score) {
reportScoreChange(player, bucket, score);
}
}
public void subtractScore(Player player, int amount) {
@@ -142,7 +147,12 @@ public class ScoreKeeperPlugin extends JavaPlugin {
}
public ScoreBucket createBucket(String id, String singular, String plural, int initialValue) {
ScoreBucket bucket = new ScoreBucket(id, singular, plural, initialValue);
return createBucket(id, singular, plural, initialValue, ScoreReporting.NONE);
}
public ScoreBucket createBucket(
String id, String singular, String plural, int initialValue, ScoreReporting reporting) {
ScoreBucket bucket = new ScoreBucket(id, singular, plural, initialValue, reporting);
if (_buckets.containsKey(id)) {
throw new IllegalArgumentException("A score bucket with ID " + id + " already exists");
}
@@ -211,11 +221,14 @@ public class ScoreKeeperPlugin extends JavaPlugin {
_bucketScores.clear();
for (String id : bucketSection.getKeys(false)) {
try {
ScoreReporting reporting =
parseReporting(bucketSection.getString(id + ".reporting", "none"), id);
createBucket(
id,
bucketSection.getString(id + ".singular", id),
bucketSection.getString(id + ".plural", id),
bucketSection.getInt(id + ".initial-value"));
bucketSection.getInt(id + ".initial-value"),
reporting);
} catch (IllegalArgumentException ex) {
logWarning("Ignoring invalid score bucket " + id + ": " + ex.getMessage());
}
@@ -266,6 +279,41 @@ public class ScoreKeeperPlugin extends JavaPlugin {
}
}
private ScoreReporting parseReporting(String value, String bucketId) {
try {
return ScoreReporting.fromString(value);
} catch (IllegalArgumentException ex) {
logWarning("Ignoring invalid reporting policy for bucket " + bucketId + "; using none.");
return ScoreReporting.NONE;
}
}
private void reportScoreChange(Player player, ScoreBucket bucket, int score) {
ScoreReporting reporting = bucket.getReporting();
if (reporting == ScoreReporting.NONE) {
return;
}
String unit = score == 1 ? bucket.getSingular() : bucket.getPlural();
String text =
player.getName() + "'s " + bucket.getId() + " score is now " + score + " " + unit + ".";
Component message = Component.text(text);
if (reporting == ScoreReporting.PLAYER) {
sendMessage(player, message);
} else if (reporting == ScoreReporting.GLOBAL) {
for (Player recipient : getServer().getOnlinePlayers()) {
sendMessage(recipient, message);
}
} else if (reporting == ScoreReporting.ADMIN) {
logInfo(text);
for (Player recipient : getServer().getOnlinePlayers()) {
if (recipient.isOp() || recipient.hasPermission("scorekeeper.admin")) {
sendMessage(recipient, message);
}
}
}
}
// endregion
// region Logging

View File

@@ -0,0 +1,38 @@
/*
This file is part of ScoreKeeper.
ScoreKeeper is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ScoreKeeper is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with ScoreKeeper. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
*/
package com.majinnaibu.minecraft.plugins.scorekeeper;
import java.util.Locale;
public enum ScoreReporting {
ADMIN,
GLOBAL,
PLAYER,
NONE;
public static ScoreReporting fromString(String value) {
if (value == null) {
throw new IllegalArgumentException("Reporting policy cannot be null");
}
try {
return valueOf(value.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Reporting must be admin, global, player or none", ex);
}
}
}

View File

@@ -19,6 +19,7 @@ package com.majinnaibu.minecraft.plugins.scorekeeper.commands;
import com.majinnaibu.minecraft.plugins.scorekeeper.ScoreBucket;
import com.majinnaibu.minecraft.plugins.scorekeeper.ScoreKeeperPlugin;
import com.majinnaibu.minecraft.plugins.scorekeeper.ScoreReporting;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -51,12 +52,14 @@ public class ScoreBucketCommand implements CommandExecutor {
return true;
}
if (args.length == 5 && args[0].equalsIgnoreCase("create")) {
if ((args.length == 5 || args.length == 6) && args[0].equalsIgnoreCase("create")) {
if (!requireAdmin(sender)) {
return true;
}
try {
_plugin.createBucket(args[1], args[2], args[3], Integer.parseInt(args[4]));
ScoreReporting reporting =
args.length == 6 ? ScoreReporting.fromString(args[5]) : ScoreReporting.NONE;
_plugin.createBucket(args[1], args[2], args[3], Integer.parseInt(args[4]), reporting);
_plugin.sendMessage(sender, Component.text("Created score bucket " + args[1] + "."));
} catch (IllegalArgumentException ex) {
sendError(sender, ex.getMessage());

View File

@@ -20,7 +20,7 @@ commands:
usage: /score-archive [playername]
score-bucket:
description: Selects or manages score buckets.
usage: /score-bucket [bucketId] | create <id> <singular> <plural> <initialValue> | <player|all> <bucketId>
usage: /score-bucket [bucketId] | create <id> <singular> <plural> <initialValue> [admin|global|player|none] | <player|all> <bucketId>
permissions:
scorekeeper.admin:
description: Allows managing score buckets.