Merge branch 'scoreboard-dev' into development

This commit is contained in:
J0nasL 2023-07-19 22:33:22 -04:00
commit d2f2ae22ce
6 changed files with 176 additions and 3 deletions

View file

@ -0,0 +1,151 @@
package io.github.J0hnL0cke.egghunt.Controller;
import java.time.temporal.ChronoUnit;
import java.time.Instant;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.bukkit.scoreboard.Criteria;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.RenderType;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.ScoreboardManager;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.LogHandler;
/**
* Handles interactions with the scoreboard api
*/
public class ScoreboardController {
private static ScoreboardController thisHandler;
private Data data;
private Configuration config;
private LogHandler logger;
private ScoreboardManager manager;
private Scoreboard board;
private Objective eggMinutes;
private Objective eggSeconds;
private Instant lastUpdate;
private static final String EGG_MINUTES_KEY = "eggOwnedMinutes";
private static final String EGG_SECONDS_KEY = "eggOwnedSeconds";
public static ScoreboardController getScoreboardHandler(Data data, Configuration configuration, LogHandler logger) {
if (thisHandler == null) {
thisHandler = new ScoreboardController(data, configuration, logger);
}
return thisHandler;
}
private ScoreboardController(Data data, Configuration config, LogHandler logger) {
this.data = data;
this.config = config;
this.logger = logger;
if (config.getKeepScore()) {
logger.log("Scorekeeping is enabled, loading scoreboard...");
loadData();
}
}
public static void saveData(LogHandler logger) {
if (thisHandler == null) {
logger.warning("ScoreboardController has not been initalized before attempting to save!");
} else {
thisHandler.updateScores();
}
}
private void loadData() {
manager = Bukkit.getScoreboardManager();
board = manager.getMainScoreboard(); //possibly switch to new board? would need to save/load independently of server
eggSeconds = getOrMakeObjective(EGG_SECONDS_KEY, "Seconds owning egg");
eggMinutes = getOrMakeObjective(EGG_MINUTES_KEY, "Minutes owning egg");
lastUpdate = Instant.now();
}
/**
* Updates the score for the current egg owner
*
* For accurate scoring, this should be updated at least every time egg ownership changes, and
* every time the plugin is enabled/disabled
* @param data
*/
public void updateScores() {
if (config.getKeepScore() && data.getEggType()!= Data.Egg_Storage_Type.DNE) {
logger.log("Updating scoreboard");
if (data.getEggType() == Data.Egg_Storage_Type.ENTITY) {
Entity eggEntity = data.getEggEntity();
if (config.getNamedEntitiesGetScore()) {
if (eggEntity.getCustomName() != null) {
incrementScoring(eggEntity.getCustomName()); //prioritize the named entity for scoring
return;
}
}
}
OfflinePlayer owner = data.getEggOwner();
if (owner != null) {
incrementScoring(owner.getName());
}
}
}
private void incrementScoring(String entityName) {
//YOU WILL REMEMBER ME! REMEMBER ME FOR
//ChronoUnit.CENTURIES
Instant newUpdate = Instant.now(); //when writing tests, switch this to using an injected Clock instance
long seconds = ChronoUnit.SECONDS.between(lastUpdate, newUpdate); //this is the floored duration in minutes
int convertedSeconds = Long.valueOf(seconds).intValue();
addScore(entityName, eggSeconds, convertedSeconds); //add to eggSeconds
int mins = Math.floorDiv(getScore(entityName, eggSeconds), 60); //convert seconds into minutes
setScore(entityName, eggMinutes, mins); //update eggMinutes
lastUpdate = newUpdate; //update lastUpdate time
}
public Objective getOrMakeObjective(String key, String displayName) {
Objective obj = board.getObjective(key);
if (obj == null) {
logger.info(String.format("No scoreboard objective \"%s\" found, creating new objective", key));
obj = board.registerNewObjective(key, Criteria.DUMMY, displayName, RenderType.INTEGER);
}
if (!obj.isModifiable()) {
String msg = "Could not modify objective \"%s\"! Make sure objective criteria is set to dummy!";
logger.warning(String.format(msg, obj.getName()));
}
return obj;
}
private void addScore(String name, Objective obj, int score) {
if (score != 0) { //avoid adding the entity to the scoreboard if adding 0
Score s = obj.getScore(name);
s.setScore(s.getScore() + score);
}
}
private void setScore(String name, Objective obj, int score) {
Score s = obj.getScore(name);
s.setScore(score);
}
private int getScore(String name, Objective obj) {
Score s = obj.getScore(name);
return s.getScore();
}
}

View file

@ -18,6 +18,8 @@ public class Configuration {
private boolean dropEnderchestedEgg; /** whether an existing egg already in an ender chest should be forced out or stuck there */
private boolean canPackageEgg; /** whether the egg can be stored in a shulker box or bundle */
private boolean tagOwner; /** whether to apply a tag to the owner of the egg */
private boolean keepScore; /** whether to create and increment a scoreboard for time holding the egg */
private boolean namedEntitiesGetScore; /** whether entities with custom names are counted on the scoreboard when holding the egg */
private World endWorld; /** the name of the world that counts as the end on this server */
private String ownerTagName; /** the name of the tag to apply to the owner, if enabled */
@ -42,6 +44,8 @@ public class Configuration {
dropEnderchestedEgg = fileDao.readBool("drop_enderchested_egg");
canPackageEgg = fileDao.readBool("can_package_egg");
tagOwner = fileDao.readBool("tag_owner");
keepScore = fileDao.readBool("keep_score");
namedEntitiesGetScore = fileDao.readBool("named_entities_keep_score");
ownerTagName = fileDao.read("owner_tag_name", null);
endWorld = Bukkit.getServer().getWorld(fileDao.read("end", DEFAULT_END));
@ -79,11 +83,18 @@ public class Configuration {
return false; //canPackageEgg; TODO implement checks for this
}
public boolean getTagOwner() {
return tagOwner;
}
public boolean getKeepScore() {
return keepScore;
}
public boolean getNamedEntitiesGetScore() {
return namedEntitiesGetScore;
}
public String getOwnerTagName(){
return ownerTagName;
}

View file

@ -14,6 +14,7 @@ import org.bukkit.inventory.InventoryHolder;
import io.github.J0hnL0cke.egghunt.Controller.Announcement;
import io.github.J0hnL0cke.egghunt.Controller.EggController;
import io.github.J0hnL0cke.egghunt.Controller.ScoreboardController;
import io.github.J0hnL0cke.egghunt.Persistence.DataFileDAO;
/**
@ -221,6 +222,8 @@ public class Data {
}
public void saveData() {
ScoreboardController.saveData(logger);
dataDao.writeUUID("owner", owner);
dataDao.writeLocation("block", serializeBlock(block));
dataDao.writeUUID("entity", serializeEntity(entity));
@ -244,6 +247,7 @@ public class Data {
private void setEggOwner(UUID playerUUID, Configuration config) {
if (!playerUUID.equals(owner)) { //only update if the egg has actually changed posession
ScoreboardController.saveData(logger);
UUID oldOwner = owner;
owner = playerUUID; //set new owner
String ownerName = Bukkit.getOfflinePlayer(owner).getName();
@ -270,6 +274,7 @@ public class Data {
}
public void resetEggOwner(boolean announce, Configuration config) {
ScoreboardController.saveData(logger);
if (owner != null) {
Player oldOwner = Bukkit.getPlayer(owner);
if (announce) { //TODO move announcements somewhere else?

View file

@ -143,7 +143,9 @@ public class Egg {
if (entity instanceof LivingEntity) {
LivingEntity mob = (((LivingEntity) entity));
EntityEquipment inv = mob.getEquipment();
if (Egg.hasEgg(inv.getArmorContents())) { //TODO check if includes main/offhand
if (Egg.hasEgg(inv.getArmorContents())) {
return true;
} else if (Egg.hasEgg(inv.getItemInMainHand()) || Egg.hasEgg(inv.getItemInOffHand())) {
return true;
}
}

View file

@ -13,6 +13,7 @@ import io.github.J0hnL0cke.egghunt.Controller.CommandHandler;
import io.github.J0hnL0cke.egghunt.Controller.EggController;
import io.github.J0hnL0cke.egghunt.Controller.EggDestroyListener;
import io.github.J0hnL0cke.egghunt.Controller.MiscListener;
import io.github.J0hnL0cke.egghunt.Controller.ScoreboardController;
import io.github.J0hnL0cke.egghunt.Controller.EventScheduler;
import io.github.J0hnL0cke.egghunt.Controller.InventoryListener;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
@ -45,6 +46,7 @@ public final class egghunt extends JavaPlugin {
logger.setDebug(config.getDebugEnabled());
//create controller instances
ScoreboardController scoreboardController = ScoreboardController.getScoreboardHandler(data, config, logger);
MiscListener miscListener = new MiscListener(logger, config, data);
InventoryListener inventoryListener = new InventoryListener(logger, config, data);
EggDestroyListener destroyListener = new EggDestroyListener(logger, config, data);

View file

@ -1,5 +1,5 @@
#If enabled, logs extra debugging information to the console. This information will appear in logs regardless of debug setting.
debug: false
debug: true
#Name of your end world, usually to "world_the_end" on spigot
end: world_the_end
@ -13,11 +13,13 @@ egg_inv: false
resp_egg: true
#Whether the egg respawns immediately (true) or after a new dragon is spawned and killed (false) after the egg is destroyed
resp_imm: false
#Whether to drop any eggs that players have in their ender chest onto the ground.
#Setting this to false will prevent the player from removing that egg from their ender chest.
drop_enderchested_egg: false
#Whether to apply an entity tag to the egg owner (works like `/tag <playerName> add <tagName>`)
#Tag is updated when egg ownership changes and on player login
tag_owner: true
#The name of the tag to apply. Selected like: `/tell @a[tag=<tagName>] <message>`
#If changing this while the egg is claimed, remove the old tag by running `/tag <playerName> remove <oldTagName>`