EggHuntPlugin/src/main/java/io/github/J0hnL0cke/egghunt/Model/Data.java

416 lines
14 KiB
Java

package io.github.J0hnL0cke.egghunt.Model;
import java.time.LocalDateTime;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
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;
/**
* Retrieves and stores this plugin's data
*/
public class Data {
private DataFileDAO dataDao;
private LogHandler logger;
public enum Egg_Storage_Type {
ENTITY,
BLOCK,
DNE, //egg does not exist
}
private Location approxLocation;
private UUID owner;
private Egg_Storage_Type storedAs;
private Block block;
private Entity entity;
private UUID entityFallback;
private static final String BUG_STR = "THIS MAY BE A BUG! Please report it at https://github.com/HyperSMP/EggHuntPlugin/issues";
public Data(DataFileDAO dataDao, LogHandler logger) {
this.dataDao = dataDao;
this.logger = logger;
loadData();
}
public Location getEggLocation() {
if (storedAs == Egg_Storage_Type.DNE) {
return null;
} else if (storedAs == Egg_Storage_Type.BLOCK) {
return block.getLocation();
} else if (storedAs == Egg_Storage_Type.ENTITY) {
return entity.getLocation();
}
return null;
}
/**
* Returns the current storage type for the dragon egg
* When getting the corresponding entity or block, that object is guaranteed to be non-null
*/
public Egg_Storage_Type getEggType() {
if ((storedAs == Egg_Storage_Type.BLOCK && block == null)
|| (storedAs == Egg_Storage_Type.ENTITY && entity == null)) {
//make sure object is non-null
String msg = String.format(
"Unable to find egg! storedAs = %s but corresponding object is null!\nResetting storedAs to prevent further errors",
storedAs.toString());
resetEggLocation();
logger.warning(msg);
}
return storedAs;
}
/**
* Returns the entity currently associated with the dragon egg
* This should only be used after checking the egg is stored as an entity
* The provided entity should (but is not guaranteed to) contain the egg
*/
public Entity getEggEntity() {
return entity;
}
/**
* Returns the block currently associated with the dragon egg
* This should only be used after checking the egg is stored as a block
* The provided block should (but is not guaranteed to) contain the egg
*/
public Block getEggBlock() {
return block;
}
public OfflinePlayer getEggOwner() {
if (owner == null) {
return null;
}
return Bukkit.getOfflinePlayer(owner);
}
private Location serializeBlock(Block block) {
if (block == null) {
return null;
} else {
return block.getLocation();
}
}
private Block deserializeBlock(Location loc) {
if (loc == null) {
return null;
} else {
return loc.getBlock();
}
}
private UUID serializeEntity(Entity entity) {
if (entity == null) {
return null;
}
return entity.getUniqueId();
}
private Entity deserializeEntity(UUID uuid, Location loc) {
if (uuid == null) {
return null;
}
if (approxLocation == null) {
logger.warning("Approximate location is null! Unable to find egg entity.");
return null;
}
boolean chunkLoaded = approxLocation.getChunk().load();
if (!chunkLoaded) {
logger.warning("Failed to load chunk with egg entity!");
}
return Bukkit.getEntity(entityFallback);
}
private UUID deserializeUUID(String uuid) {
if (uuid == null) {
return null;
}
return UUID.fromString(uuid);
}
private void validateData() {
logger.log("Data loaded. Validating loaded data...");
//make sure data was properly loaded
switch (storedAs) {
case BLOCK:
if (block == null) {
logger.warning("Could not locate egg block!");
resetEggLocation();
} else if (!Egg.hasEgg(block)) {
logger.warning("Saved egg block does not actually contain the egg! Was the egg moved while the plugin was disabled?");
logger.warning(BUG_STR);
} else {
log("Successfully found dragon egg block.");
}
break;
case ENTITY:
if (entity == null) {
logger.warning("Could not locate the egg entity!");
resetEggLocation();
} else if (!Egg.hasEgg(entity)) {
logger.warning("Saved egg entity does not actually contain the egg! Was the egg moved while the plugin was disabled?");
logger.warning(BUG_STR);
} else {
log("Successfully found dragon egg entity.");
}
break;
case DNE:
log("Dragon egg has not been claimed.");
}
if (owner != null) {
OfflinePlayer p = Bukkit.getOfflinePlayer(owner);
if (p == null) {
logger.warning("Could not find player with the saved UUID! Resetting egg owner to prevent errors.");
logger.warning(BUG_STR);
resetEggOwner(false, null);
}
}
if (entity == null && storedAs.equals(Egg_Storage_Type.ENTITY)) {
logger.warning("Could not locate the egg entity!");
resetEggLocation();
} else if (block == null && storedAs.equals(Egg_Storage_Type.BLOCK)) {
logger.warning("Could not locate egg block!");
resetEggLocation();
} else if (storedAs.equals(Egg_Storage_Type.DNE)) {
log("Dragon egg has not been claimed.");
} else {
log("Successfully found dragon egg.");
}
}
public void loadData() {
owner = dataDao.readUUID("owner", null);
block = deserializeBlock(dataDao.readLocation("block", null));
entityFallback = deserializeUUID(dataDao.read("entity", String.class, null));
approxLocation = dataDao.readLocation("lastLocation", null);
entity = deserializeEntity(entityFallback, approxLocation);
String storageString = dataDao.read("storedAs", String.class, null);
if (storageString == null) {
logger.warning("Could not correctly load egg location data! Was this plugin's data folder deleted?\n" +
"If this is the first time this plugin has run, it is safe to ignore this warning.");
storedAs = Egg_Storage_Type.DNE;
saveData();
} else {
storedAs = Egg_Storage_Type.valueOf(storageString);
validateData();
}
}
public void saveData() {
ScoreboardController.saveData(logger);
dataDao.writeUUID("owner", owner);
dataDao.writeLocation("block", serializeBlock(block));
dataDao.writeUUID("entity", serializeEntity(entity));
if (storedAs.equals(Egg_Storage_Type.ENTITY)) {
approxLocation = entity.getLocation(); //update latest entity location
//this is important for getting entity when server restarts
}
dataDao.writeLocation("lastLocation", approxLocation);
dataDao.writeString("storedAs", storedAs.name());
//save timestamp
dataDao.writeString("writeTime", LocalDateTime.now().toString());
//write to file
dataDao.save();
}
public void setEggOwner(Player player, Configuration config) {
setEggOwner(player.getUniqueId(), config);
}
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();
String msg;
//if the old owner is online, remove their scoreboard tag
if (oldOwner != null) {
EggController.updateOwnerTag(Bukkit.getPlayer(oldOwner), this, config);
String oldOwnerName = Bukkit.getOfflinePlayer(oldOwner).getName();
msg = String.format("%s has stolen the dragon egg from %s!", ownerName, oldOwnerName);
} else {
msg = String.format("%s has claimed the dragon egg!", ownerName);
}
Announcement.announce(msg, logger);
Player p = Bukkit.getPlayer(playerUUID);
if (p != null) { //make sure player is online
Announcement.ShowEggEffects(p);
EggController.updateOwnerTag(p, this, config); //update the scoreboard tag of the new owner
}
}
}
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?
String ownerName = Bukkit.getOfflinePlayer(owner).getName();
Announcement.announce(String.format("%s no longer owns the dragon egg", ownerName), logger);
}
log("Egg owner reset");
owner = null;
if (config != null) {
EggController.updateOwnerTag(oldOwner, this, config); //update tag after setting owner to null
}
}
}
public void resetEggLocation() {
log("Egg location reset");
block = null;
entity = null;
storedAs = Egg_Storage_Type.DNE;
}
public void updateEggLocation(Block block) {
approxLocation = block.getLocation();
this.block = block;
entity = null;
storedAs = Egg_Storage_Type.BLOCK;
log("The egg is "+getEggHolderString());
}
public void updateEggLocation(Entity holderEntity) {
approxLocation = holderEntity.getLocation();
entity = holderEntity;
block = null;
storedAs = Egg_Storage_Type.ENTITY;
log("The egg is "+getEggHolderString());
}
/**
* likely to be called when a generic inventory is the most info given for what picked up an item, like on hopper collect event
* if more info is available (such as Entity or Block instance), better to pass that instead, although this should still work
*/
public void updateEggLocation(Inventory inv) {
if (inv.getHolder() instanceof Entity){
// Hopper minecart, llama, or some other entity has the egg
for (Entity e : inv.getLocation().getChunk().getEntities()) {
//search all entities in the world
if (e instanceof InventoryHolder) {
if (inv.getHolder().equals((InventoryHolder) e)) {
//if they are this inventory's holder, this is the entity to target
updateEggLocation(e);
return;
}
}
}
logger.warning("Could not find the correct InventoryHolder entity for this Inventory! Are you using custom inventories?");
logger.warning(BUG_STR);
} else {
// Block contains the egg
updateEggLocation(inv.getLocation().getBlock());
}
}
/**
* Gives a human-readable string describing where the dragon egg is
* Will always start with "is <x>" unless the message is "does not exist"
*/
public String getEggHolderString() {
Egg_Storage_Type type = getEggType();
String storageMsg;
if (type == Egg_Storage_Type.DNE) { //egg does not exist
storageMsg = "does not exist";
} else { //egg exists
if (type == Egg_Storage_Type.BLOCK) {
Block eggBlock = getEggBlock();
if (Egg.isOnlyEgg(eggBlock)) { //egg is an egg block
storageMsg = "is a block";
} else { //egg is in a block
//inside a container, so provide the name of the container
storageMsg = String.format("is inside of a(n) %s", eggBlock.getType().toString());
}
} else { //egg is in an entity
Entity eggEntity = getEggEntity();
switch (eggEntity.getType()) {
case PLAYER:
storageMsg = String.format("is in the inventory of %s", entity.getName());
break;
case FALLING_BLOCK:
storageMsg = String.format("is a falling block");
break;
case ITEM:
storageMsg = String.format("is a dropped item");
break;
case ITEM_FRAME:
case GLOW_ITEM_FRAME:
storageMsg = String.format("is an item frame");
break;
case ARMOR_STAND:
storageMsg = String.format("is held by an armor stand");
break;
default:
//stored in the inventory of a non-player entity (zombie, hopper minecart, etc)
if (entity.getCustomName() != null) {
storageMsg = String.format("is held by a(n) %s named \"%s\"",
entity.getType().toString(),
entity.getName());
} else {
storageMsg = String.format("is held by a(n) %s", entity.getType().toString());
}
}
}
}
return storageMsg;
}
private void log(String msg) {
logger.log(msg);
}
}