2019-08-25 14:07:06 +00:00
|
|
|
package me.mrCookieSlime.Slimefun.api;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Iterator;
|
2019-10-16 23:08:14 +00:00
|
|
|
import java.util.LinkedList;
|
2019-08-29 13:13:40 +00:00
|
|
|
import java.util.List;
|
2019-08-25 14:07:06 +00:00
|
|
|
import java.util.Map;
|
2019-08-25 15:35:19 +00:00
|
|
|
import java.util.Optional;
|
2019-08-25 14:07:06 +00:00
|
|
|
import java.util.Set;
|
|
|
|
import java.util.UUID;
|
2019-10-11 21:48:46 +00:00
|
|
|
import java.util.function.Consumer;
|
2019-08-25 15:35:19 +00:00
|
|
|
import java.util.stream.IntStream;
|
|
|
|
|
2019-10-01 00:57:58 +00:00
|
|
|
import org.bukkit.Bukkit;
|
2019-08-25 15:35:19 +00:00
|
|
|
import org.bukkit.ChatColor;
|
2019-10-01 00:57:58 +00:00
|
|
|
import org.bukkit.OfflinePlayer;
|
|
|
|
import org.bukkit.command.CommandSender;
|
2019-10-11 22:56:51 +00:00
|
|
|
import org.bukkit.entity.Player;
|
2019-08-25 15:35:19 +00:00
|
|
|
import org.bukkit.inventory.ItemStack;
|
2019-08-25 14:07:06 +00:00
|
|
|
|
2019-12-11 22:13:51 +00:00
|
|
|
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
2019-08-31 09:36:45 +00:00
|
|
|
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
2019-08-25 14:07:06 +00:00
|
|
|
import me.mrCookieSlime.Slimefun.Objects.Research;
|
2019-08-26 17:13:56 +00:00
|
|
|
import me.mrCookieSlime.Slimefun.api.inventory.BackpackInventory;
|
2019-08-25 14:07:06 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A class that can store a Player's Research Profile for caching
|
|
|
|
*
|
|
|
|
* @author TheBusyBiscuit
|
|
|
|
*
|
|
|
|
*/
|
2019-08-27 14:26:35 +00:00
|
|
|
public final class PlayerProfile {
|
2019-12-26 18:56:58 +00:00
|
|
|
|
|
|
|
private final UUID uuid;
|
|
|
|
private final String name;
|
|
|
|
private final Config cfg;
|
2019-08-25 14:07:06 +00:00
|
|
|
|
|
|
|
private boolean dirty = false;
|
|
|
|
private boolean markedForDeletion = false;
|
|
|
|
|
2019-10-05 18:44:11 +00:00
|
|
|
private final Set<Research> researches = new HashSet<>();
|
|
|
|
private final Map<Integer, BackpackInventory> backpacks = new HashMap<>();
|
2019-10-16 23:08:14 +00:00
|
|
|
private final LinkedList<Object> guideHistory = new LinkedList<>();
|
|
|
|
|
2019-10-05 18:44:11 +00:00
|
|
|
private final HashedArmorpiece[] armor = {
|
2019-10-06 17:32:55 +00:00
|
|
|
new HashedArmorpiece(),
|
|
|
|
new HashedArmorpiece(),
|
|
|
|
new HashedArmorpiece(),
|
|
|
|
new HashedArmorpiece()
|
2019-10-05 18:44:11 +00:00
|
|
|
};
|
2019-08-25 14:07:06 +00:00
|
|
|
|
2019-10-01 00:57:58 +00:00
|
|
|
private PlayerProfile(OfflinePlayer p) {
|
|
|
|
this.uuid = p.getUniqueId();
|
|
|
|
this.name = p.getName();
|
2019-10-11 21:48:46 +00:00
|
|
|
|
2019-10-01 00:57:58 +00:00
|
|
|
cfg = new Config(new File("data-storage/Slimefun/Players/" + uuid.toString() + ".yml"));
|
2019-10-11 21:48:46 +00:00
|
|
|
|
2019-12-22 22:00:05 +00:00
|
|
|
for (Research research : Research.list()) {
|
2019-10-01 00:57:58 +00:00
|
|
|
if (cfg.contains("researches." + research.getID())) researches.add(research);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-25 14:07:06 +00:00
|
|
|
private PlayerProfile(UUID uuid) {
|
2019-10-11 21:48:46 +00:00
|
|
|
this(Bukkit.getOfflinePlayer(uuid));
|
2019-08-25 14:07:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-05 18:44:11 +00:00
|
|
|
public HashedArmorpiece[] getArmor() {
|
|
|
|
return armor;
|
|
|
|
}
|
|
|
|
|
2019-08-26 17:13:56 +00:00
|
|
|
public Config getConfig() {
|
2019-08-25 15:35:19 +00:00
|
|
|
return cfg;
|
|
|
|
}
|
|
|
|
|
2019-08-25 14:07:06 +00:00
|
|
|
public UUID getUUID() {
|
|
|
|
return uuid;
|
|
|
|
}
|
|
|
|
|
2019-08-25 20:21:06 +00:00
|
|
|
/**
|
|
|
|
* This method returns whether the Player has logged off.
|
|
|
|
* If this is true, then the Profile can be removed from RAM.
|
|
|
|
*
|
|
|
|
* @return Whether the Profile is marked for deletion
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public boolean isMarkedForDeletion() {
|
|
|
|
return markedForDeletion;
|
|
|
|
}
|
|
|
|
|
2019-08-25 20:21:06 +00:00
|
|
|
/**
|
|
|
|
* This method returns whether the Profile has unsaved changes
|
|
|
|
*
|
|
|
|
* @return Whether there are unsaved changes
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public boolean isDirty() {
|
|
|
|
return dirty;
|
|
|
|
}
|
|
|
|
|
2019-08-25 20:21:06 +00:00
|
|
|
/**
|
|
|
|
* This method will save the Player's Researches and Backpacks to the hard drive
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public void save() {
|
2019-12-22 22:00:05 +00:00
|
|
|
for (BackpackInventory backpack : backpacks.values()) {
|
2019-08-25 15:35:19 +00:00
|
|
|
backpack.save();
|
|
|
|
}
|
|
|
|
|
2019-08-25 14:07:06 +00:00
|
|
|
cfg.save();
|
|
|
|
dirty = false;
|
|
|
|
}
|
|
|
|
|
2019-08-25 20:21:06 +00:00
|
|
|
/**
|
|
|
|
* This method sets the Player's "researched" status for this Research.
|
|
|
|
* Use the boolean to unlock or lock the Research
|
|
|
|
*
|
|
|
|
* @param research The Research that should be unlocked or locked
|
|
|
|
* @param unlock Whether the Research should be unlocked or locked
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public void setResearched(Research research, boolean unlock) {
|
|
|
|
dirty = true;
|
|
|
|
|
|
|
|
if (unlock) {
|
|
|
|
cfg.setValue("researches." + research.getID(), true);
|
|
|
|
researches.add(research);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cfg.setValue("researches." + research.getID(), null);
|
|
|
|
researches.remove(research);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-25 20:21:06 +00:00
|
|
|
/**
|
|
|
|
* This method returns whether the Player has unlocked the given Research
|
|
|
|
*
|
|
|
|
* @param research The Research that is being queried
|
|
|
|
* @return Whether this Research has been unlocked
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public boolean hasUnlocked(Research research) {
|
|
|
|
return !research.isEnabled() || researches.contains(research);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-08-25 15:35:19 +00:00
|
|
|
* This Method will return all Researches that this Player has unlocked
|
2019-08-25 14:07:06 +00:00
|
|
|
*
|
|
|
|
* @return A Hashset<Research> of all Researches this Player has unlocked
|
|
|
|
*/
|
|
|
|
public Set<Research> getResearches() {
|
|
|
|
return researches;
|
|
|
|
}
|
2019-08-25 15:35:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Call this method if the Player has left.
|
|
|
|
* The profile can then be removed from RAM.
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public void markForDeletion() {
|
|
|
|
this.markedForDeletion = true;
|
|
|
|
}
|
|
|
|
|
2019-08-25 15:35:19 +00:00
|
|
|
/**
|
|
|
|
* Call this method if this Profile has unsaved changes.
|
|
|
|
*/
|
|
|
|
public void markDirty() {
|
|
|
|
this.dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public BackpackInventory createBackpack(int size) {
|
|
|
|
IntStream stream = IntStream.iterate(0, i -> i + 1).filter(i -> !cfg.contains("backpacks." + i + ".size"));
|
|
|
|
int id = stream.findFirst().getAsInt();
|
|
|
|
|
|
|
|
BackpackInventory backpack = new BackpackInventory(this, id, size);
|
|
|
|
backpacks.put(id, backpack);
|
|
|
|
|
|
|
|
return backpack;
|
|
|
|
}
|
|
|
|
|
|
|
|
public BackpackInventory getBackpack(int id) {
|
|
|
|
BackpackInventory backpack = backpacks.get(id);
|
|
|
|
|
|
|
|
if (backpack != null) return backpack;
|
|
|
|
else {
|
|
|
|
backpack = new BackpackInventory(this, id);
|
|
|
|
backpacks.put(id, backpack);
|
|
|
|
return backpack;
|
|
|
|
}
|
|
|
|
}
|
2019-08-25 20:39:59 +00:00
|
|
|
|
|
|
|
public String getTitle() {
|
2019-08-31 09:36:45 +00:00
|
|
|
List<String> titles = SlimefunPlugin.getSettings().researchesTitles;
|
2019-11-24 13:11:34 +00:00
|
|
|
|
|
|
|
float fraction = (float) researches.size() / Research.list().size();
|
|
|
|
int index = (int) (fraction * (titles.size() -1));
|
|
|
|
|
2019-08-29 13:13:40 +00:00
|
|
|
return titles.get(index);
|
2019-08-25 20:39:59 +00:00
|
|
|
}
|
2019-08-25 15:35:19 +00:00
|
|
|
|
2019-10-01 00:57:58 +00:00
|
|
|
public void sendStats(CommandSender sender) {
|
|
|
|
Set<Research> researched = getResearches();
|
|
|
|
int levels = researched.stream().mapToInt(Research::getCost).sum();
|
|
|
|
|
|
|
|
String progress = String.valueOf(Math.round(((researched.size() * 100.0F) / Research.list().size()) * 100.0F) / 100.0F);
|
|
|
|
if (Float.parseFloat(progress) < 16.0F) progress = "&4" + progress + " &r% ";
|
|
|
|
else if (Float.parseFloat(progress) < 32.0F) progress = "&c" + progress + " &r% ";
|
|
|
|
else if (Float.parseFloat(progress) < 48.0F) progress = "&6" + progress + " &r% ";
|
|
|
|
else if (Float.parseFloat(progress) < 64.0F) progress = "&e" + progress + " &r% ";
|
|
|
|
else if (Float.parseFloat(progress) < 80.0F) progress = "&2" + progress + " &r% ";
|
|
|
|
else progress = "&a" + progress + " &r% ";
|
|
|
|
|
|
|
|
sender.sendMessage("");
|
|
|
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Statistics for Player: &b" + name));
|
|
|
|
sender.sendMessage("");
|
|
|
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Title: &b" + getTitle()));
|
|
|
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Research Progress: " + progress + "&e(" + researched.size() + " / " + Research.list().size() + ")"));
|
|
|
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Total XP Levels spent: &b" + levels));
|
|
|
|
}
|
2019-10-11 22:56:51 +00:00
|
|
|
|
|
|
|
public Player getPlayer() {
|
|
|
|
return Bukkit.getPlayer(getUUID());
|
|
|
|
}
|
2019-10-16 23:08:14 +00:00
|
|
|
|
|
|
|
public LinkedList<Object> getGuideHistory() {
|
|
|
|
return guideHistory;
|
|
|
|
}
|
2019-10-29 08:13:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This is now deprecated, use {@link #fromUUID(UUID, Consumer)} instead
|
|
|
|
*
|
|
|
|
* @param uuid The UUID of the profile you are trying to retrieve.
|
|
|
|
* @return The PlayerProfile of this player
|
|
|
|
*/
|
2019-08-25 14:07:06 +00:00
|
|
|
public static PlayerProfile fromUUID(UUID uuid) {
|
2019-08-31 09:36:45 +00:00
|
|
|
PlayerProfile profile = SlimefunPlugin.getUtilities().profiles.get(uuid);
|
2019-08-25 14:07:06 +00:00
|
|
|
|
|
|
|
if (profile == null) {
|
|
|
|
profile = new PlayerProfile(uuid);
|
2019-08-31 09:36:45 +00:00
|
|
|
SlimefunPlugin.getUtilities().profiles.put(uuid, profile);
|
2019-08-25 14:07:06 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
profile.markedForDeletion = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return profile;
|
|
|
|
}
|
2019-10-29 08:13:32 +00:00
|
|
|
|
|
|
|
public static boolean fromUUID(UUID uuid, Consumer<PlayerProfile> callback) {
|
|
|
|
PlayerProfile profile = SlimefunPlugin.getUtilities().profiles.get(uuid);
|
|
|
|
|
|
|
|
if (profile != null) {
|
|
|
|
callback.accept(profile);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
|
|
|
|
PlayerProfile pp = new PlayerProfile(uuid);
|
|
|
|
SlimefunPlugin.getUtilities().profiles.put(uuid, pp);
|
|
|
|
callback.accept(pp);
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
2019-10-11 21:48:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This is now deprecated, use {@link #get(OfflinePlayer, Consumer)} instead
|
|
|
|
*
|
|
|
|
* @param p The player's profile you wish to retrieve
|
|
|
|
* @return The PlayerProfile of this player
|
|
|
|
*/
|
2019-10-01 00:57:58 +00:00
|
|
|
public static PlayerProfile get(OfflinePlayer p) {
|
|
|
|
PlayerProfile profile = SlimefunPlugin.getUtilities().profiles.get(p.getUniqueId());
|
|
|
|
|
|
|
|
if (profile == null) {
|
|
|
|
profile = new PlayerProfile(p);
|
|
|
|
SlimefunPlugin.getUtilities().profiles.put(p.getUniqueId(), profile);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
profile.markedForDeletion = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return profile;
|
|
|
|
}
|
2019-08-25 14:07:06 +00:00
|
|
|
|
2019-10-11 22:56:51 +00:00
|
|
|
/**
|
|
|
|
* Get the PlayerProfile for a player asynchronously.
|
|
|
|
*
|
|
|
|
* @param p The player who's profile to retrieve
|
|
|
|
* @param callback The callback with the PlayerProfile
|
|
|
|
* @return If the player was cached or not.
|
|
|
|
*/
|
|
|
|
public static boolean get(OfflinePlayer p, Consumer<PlayerProfile> callback) {
|
2019-10-11 21:48:46 +00:00
|
|
|
PlayerProfile profile = SlimefunPlugin.getUtilities().profiles.get(p.getUniqueId());
|
2019-12-22 22:00:05 +00:00
|
|
|
|
2019-10-11 21:48:46 +00:00
|
|
|
if (profile != null) {
|
|
|
|
callback.accept(profile);
|
2019-10-11 22:56:51 +00:00
|
|
|
return true;
|
2019-10-11 21:48:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
|
|
|
|
PlayerProfile pp = new PlayerProfile(p);
|
|
|
|
SlimefunPlugin.getUtilities().profiles.put(p.getUniqueId(), pp);
|
|
|
|
callback.accept(pp);
|
|
|
|
});
|
2019-10-11 22:56:51 +00:00
|
|
|
return false;
|
2019-10-11 21:48:46 +00:00
|
|
|
}
|
|
|
|
|
2019-08-25 14:07:06 +00:00
|
|
|
public static boolean isLoaded(UUID uuid) {
|
2019-08-31 09:36:45 +00:00
|
|
|
return SlimefunPlugin.getUtilities().profiles.containsKey(uuid);
|
2019-08-25 14:07:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 23:08:14 +00:00
|
|
|
public static Optional<PlayerProfile> find(OfflinePlayer p) {
|
|
|
|
return Optional.ofNullable(SlimefunPlugin.getUtilities().profiles.get(p.getUniqueId()));
|
|
|
|
}
|
|
|
|
|
2019-08-25 14:07:06 +00:00
|
|
|
public static Iterator<PlayerProfile> iterator() {
|
2019-08-31 09:36:45 +00:00
|
|
|
return SlimefunPlugin.getUtilities().profiles.values().iterator();
|
2019-08-25 14:07:06 +00:00
|
|
|
}
|
2019-08-25 15:35:19 +00:00
|
|
|
|
|
|
|
public static BackpackInventory getBackpack(ItemStack item) {
|
|
|
|
if (item == null || !item.hasItemMeta() || !item.getItemMeta().hasLore()) return null;
|
|
|
|
|
|
|
|
Optional<Integer> id = Optional.empty();
|
|
|
|
String uuid = "";
|
|
|
|
|
2019-12-22 22:00:05 +00:00
|
|
|
for (String line : item.getItemMeta().getLore()) {
|
2019-08-25 15:35:19 +00:00
|
|
|
if (line.startsWith(ChatColor.translateAlternateColorCodes('&', "&7ID: ")) && line.contains("#")) {
|
|
|
|
try {
|
|
|
|
id = Optional.of(Integer.parseInt(line.split("#")[1]));
|
|
|
|
uuid = line.split("#")[0].replace(ChatColor.translateAlternateColorCodes('&', "&7ID: "), "");
|
|
|
|
} catch(NumberFormatException x) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id.isPresent()) {
|
|
|
|
return PlayerProfile.fromUUID(UUID.fromString(uuid)).getBackpack(id.get());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2019-09-04 07:54:24 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "PlayerProfile {" + uuid + "}";
|
|
|
|
}
|
2019-08-25 14:07:06 +00:00
|
|
|
|
|
|
|
}
|