package com.earth2me.essentials; import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.config.EssentialsUserConfiguration; import com.earth2me.essentials.config.entities.CommandCooldown; import com.earth2me.essentials.config.entities.LazyLocation; import com.earth2me.essentials.config.holders.UserConfigHolder; import com.earth2me.essentials.userstorage.ModernUserMap; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; import com.google.common.base.Charsets; import net.ess3.api.IEssentials; import net.ess3.api.MaxMoneyException; import net.essentialsx.api.v2.services.mail.MailMessage; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.spongepowered.configurate.serialize.SerializationException; import java.io.File; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.logging.Level; import java.util.regex.Pattern; import static com.earth2me.essentials.I18n.tl; public abstract class UserData extends PlayerExtension implements IConf { protected final transient IEssentials ess; private final EssentialsUserConfiguration config; private UserConfigHolder holder; private BigDecimal money; protected UserData(final Player base, final IEssentials ess) { super(base); this.ess = ess; final File folder = new File(ess.getDataFolder(), "userdata"); if (!folder.exists() && !folder.mkdirs()) { throw new RuntimeException("Unable to create userdata folder!"); } config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, base.getUniqueId() + ".yml")); config.setSaveHook(() -> { config.setRootHolder(UserConfigHolder.class, holder); }); reloadConfig(); if (config.getUsername() == null) { config.setUsername(getLastAccountName()); } } public final void reset() { config.blockingSave(); if (!config.getFile().delete()) { ess.getLogger().warning("Unable to delete data file for " + config.getFile().getName()); } if (config.getUsername() != null) { final ModernUserMap users = (ModernUserMap) ess.getUsers(); users.invalidate(config.getUuid()); if (isNPC()) { final String name = ess.getSettings().isSafeUsermap() ? StringUtil.safeString(config.getUsername()) : config.getUsername(); users.invalidate(UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8))); } } } public final void cleanup() { config.blockingSave(); } @Override public final void reloadConfig() { config.load(); try { holder = config.getRootNode().get(UserConfigHolder.class); } catch (SerializationException e) { ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + config.getFile().getName(), e); throw new RuntimeException(e); } money = _getMoney(); } private BigDecimal _getMoney() { BigDecimal result = ess.getSettings().getStartingBalance(); final BigDecimal maxMoney = ess.getSettings().getMaxMoney(); final BigDecimal minMoney = ess.getSettings().getMinMoney(); // NPC banks are not actual player banks, as such they do not have player starting balance. if (isNPC()) { result = BigDecimal.ZERO; } if (holder.money() != null) { result = holder.money(); } if (result.compareTo(maxMoney) > 0) { result = maxMoney; } if (result.compareTo(minMoney) < 0) { result = minMoney; } holder.money(result); return holder.money(); } public BigDecimal getMoney() { return money; } public void setMoney(final BigDecimal value, final boolean throwError) throws MaxMoneyException { final BigDecimal maxMoney = ess.getSettings().getMaxMoney(); final BigDecimal minMoney = ess.getSettings().getMinMoney(); if (value.compareTo(maxMoney) > 0) { if (throwError) { throw new MaxMoneyException(); } money = maxMoney; } else { money = value; } if (money.compareTo(minMoney) < 0) { money = minMoney; } holder.money(money); stopTransaction(); } private String getHomeName(String search) { if (NumberUtil.isInt(search)) { try { search = getHomes().get(Integer.parseInt(search) - 1); } catch (final NumberFormatException | IndexOutOfBoundsException ignored) { } } return search; } public Location getHome(final String name) { final String search = getHomeName(name); final LazyLocation loc = holder.homes().get(search); return loc != null ? loc.location() : null; } public boolean hasValidHomes() { for (final LazyLocation loc : holder.homes().values()) { if (loc != null && loc.location() != null) { return true; } } return false; } public Location getHome(final Location world) { if (getHomes().isEmpty()) { return null; } for (final String home : getHomes()) { final Location loc = holder.homes().get(home).location(); if (loc != null && world.getWorld() == loc.getWorld()) { return loc; } } return holder.homes().get(getHomes().get(0)).location(); } public List getHomes() { return new ArrayList<>(holder.homes().keySet()); } public void setHome(String name, final Location loc) { //Invalid names will corrupt the yaml name = StringUtil.safeString(name); holder.homes().put(name, LazyLocation.fromLocation(loc)); config.save(); } public void delHome(final String name) throws Exception { String search = getHomeName(name); if (!holder.homes().containsKey(search)) { search = StringUtil.safeString(search); } if (holder.homes().containsKey(search)) { holder.homes().remove(search); config.save(); } else { throw new Exception(tl("invalidHome", search)); } } public boolean hasHome() { return !holder.homes().isEmpty(); } public boolean hasHome(final String name) { return holder.homes().containsKey(name); } public String getNickname() { return holder.nickname(); } public void setNickname(final String nick) { holder.nickname(nick); config.save(); } public Set getUnlimited() { return holder.unlimited(); } public boolean hasUnlimited(final ItemStack stack) { return holder.unlimited().contains(stack.getType()); } public void setUnlimited(final ItemStack stack, final boolean state) { final boolean wasUpdated; if (state) { wasUpdated = holder.unlimited().add(stack.getType()); } else { wasUpdated = holder.unlimited().remove(stack.getType()); } if (wasUpdated) { config.save(); } } public void clearAllPowertools() { holder.powertools().clear(); config.save(); } public List getPowertool(final ItemStack stack) { return getPowertool(stack.getType()); } public List getPowertool(final Material material) { return holder.powertools().get(material.name().toLowerCase(Locale.ENGLISH)); } public void setPowertool(final ItemStack stack, final List commandList) { if (commandList == null || commandList.isEmpty()) { holder.powertools().remove(stack.getType().name().toLowerCase(Locale.ENGLISH)); } else { holder.powertools().put(stack.getType().name().toLowerCase(Locale.ENGLISH), commandList); } config.save(); } public boolean hasPowerTools() { return !holder.powertools().isEmpty(); } public Location getLastLocation() { final LazyLocation lastLocation = holder.lastLocation(); return lastLocation != null ? lastLocation.location() : null; } public void setLastLocation(final Location loc) { if (loc == null || loc.getWorld() == null) { return; } holder.lastLocation(loc); config.save(); } public Location getLogoutLocation() { final LazyLocation logoutLocation = holder.logoutLocation(); return logoutLocation != null ? logoutLocation.location() : null; } public void setLogoutLocation(final Location loc) { if (loc == null || loc.getWorld() == null) { return; } holder.logoutLocation(loc); config.save(); } public long getLastTeleportTimestamp() { return holder.timestamps().lastTeleport(); } public void setLastTeleportTimestamp(final long time) { holder.timestamps().lastTeleport(time); config.save(); } public long getLastHealTimestamp() { return holder.timestamps().lastHeal(); } public void setLastHealTimestamp(final long time) { holder.timestamps().lastHeal(time); config.save(); } public String getJail() { return holder.jail(); } public void setJail(final String jail) { holder.jail(jail); config.save(); } /** * @deprecated Mails are no longer just strings, this method is therefore misleading. */ @Deprecated public List getMails() { final List list = new ArrayList<>(); if (getMailAmount() != 0) { for (MailMessage mail : getMailMessages()) { // I hate this code btw list.add(mail.isLegacy() ? mail.getMessage() : ChatColor.GOLD + "[" + ChatColor.RESET + mail.getSenderUsername() + ChatColor.GOLD + "] " + ChatColor.RESET + mail.getMessage()); } } return list; } /** * @deprecated This method does not support the new mail system and will fail at runtime. */ @Deprecated public void setMails(List mails) { throw new UnsupportedOperationException("UserData#setMails(List) is deprecated and can no longer be used. Please tell the plugin author to update this!"); } public int getMailAmount() { return holder.mail() == null ? 0 : holder.mail().size(); } public int getUnreadMailAmount() { if (holder.mail() == null || holder.mail().isEmpty()) { return 0; } int unread = 0; for (MailMessage element : holder.mail()) { if (!element.isRead()) { unread++; } } return unread; } /** * @deprecated This method does not support the new mail system and should not be used. */ @Deprecated abstract void addMail(final String mail); public ArrayList getMailMessages() { return new ArrayList<>(holder.mail()); } public void setMailList(ArrayList messages) { holder.mail(messages); config.save(); } public boolean isTeleportEnabled() { return holder.teleportEnabled(); } public void setTeleportEnabled(final boolean set) { holder.teleportEnabled(set); config.save(); } public boolean isAutoTeleportEnabled() { return holder.teleportAuto(); } public void setAutoTeleportEnabled(final boolean set) { holder.teleportAuto(set); config.save(); } @Deprecated public void setIgnoredPlayers(final List players) { final List uuids = new ArrayList<>(); for (final String player : players) { final User user = ess.getOfflineUser(player); if (user == null) { return; } uuids.add(user.getBase().getUniqueId()); } setIgnoredPlayerUUIDs(uuids); } public void setIgnoredPlayerUUIDs(final List players) { holder.ignore(players); config.save(); } @Deprecated public boolean isIgnoredPlayer(final String userName) { final IUser user = ess.getUser(userName); if (user == null || !user.getBase().isOnline()) { return false; } return isIgnoredPlayer(user); } public boolean isIgnoredPlayer(final IUser user) { return holder.ignore().contains(user.getBase().getUniqueId()) && !user.isIgnoreExempt(); } public List _getIgnoredPlayers() { return holder.ignore(); } public void setIgnoredPlayer(final IUser user, final boolean set) { final UUID uuid = user.getBase().getUniqueId(); if (set) { if (!holder.ignore().contains(uuid)) { holder.ignore().add(uuid); } } else { holder.ignore().remove(uuid); } config.save(); } public boolean isGodModeEnabled() { return holder.godMode(); } public void setGodModeEnabled(final boolean set) { holder.godMode(set); config.save(); } public boolean getMuted() { return holder.muted(); } public boolean isMuted() { return getMuted(); } public void setMuted(final boolean set) { holder.muted(set); config.save(); } public String getMuteReason() { return holder.muteReason(); } public void setMuteReason(final String reason) { holder.muteReason(reason); config.save(); } public boolean hasMuteReason() { return holder.muteReason() != null; } public long getMuteTimeout() { return holder.timestamps().mute(); } public void setMuteTimeout(final long time) { holder.timestamps().mute(time); config.save(); } public boolean isJailed() { return holder.jailed(); } public void setJailed(final boolean set) { holder.jailed(set); config.save(); } public boolean toggleJailed() { final boolean ret = !isJailed(); setJailed(ret); return ret; } public long getJailTimeout() { return holder.timestamps().jail(); } public void setJailTimeout(final long time) { holder.timestamps().jail(time); config.save(); } public long getOnlineJailedTime() { return holder.timestamps().onlineJail(); } public void setOnlineJailedTime(long onlineJailed) { holder.timestamps().onlineJail(onlineJailed); config.save(); } public long getLastLogin() { return holder.timestamps().login(); } public void setLastLogin(final long time) { holder.timestamps().login(time); if (base.getAddress() != null && base.getAddress().getAddress() != null) { holder.ipAddress(base.getAddress().getAddress().getHostAddress()); } config.save(); } public long getLastLogout() { return holder.timestamps().logout(); } public void setLastLogout(final long time) { holder.timestamps().logout(time); config.save(); } public String getLastLoginAddress() { return holder.ipAddress(); } public boolean isAfk() { return holder.afk(); } public void _setAfk(final boolean set) { holder.afk(set); config.save(); } public String getGeoLocation() { return holder.geolocation(); } public void setGeoLocation(final String geolocation) { holder.geolocation(geolocation); config.save(); } public boolean isSocialSpyEnabled() { return holder.socialSpy(); } public void setSocialSpyEnabled(final boolean status) { holder.socialSpy(status); config.save(); } public boolean isNPC() { return holder.npc(); } public void setNPC(final boolean set) { holder.npc(set); config.save(); } public String getLastAccountName() { return holder.lastAccountName(); } public void setLastAccountName(final String lastAccountName) { if (getLastAccountName() != null && !getLastAccountName().equals(lastAccountName)) { final List usernames = holder.pastUsernames(); usernames.add(0, getLastAccountName()); holder.pastUsernames(usernames); } holder.lastAccountName(lastAccountName); config.save(); } public boolean arePowerToolsEnabled() { return holder.powerToolsEnabled(); } public void setPowerToolsEnabled(final boolean set) { holder.powerToolsEnabled(set); config.save(); } public boolean togglePowerToolsEnabled() { final boolean ret = !arePowerToolsEnabled(); setPowerToolsEnabled(ret); return ret; } public long getKitTimestamp(String name) { name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH); if (holder.timestamps().kits() != null && holder.timestamps().kits().containsKey(name)) { return holder.timestamps().kits().get(name); } return 0L; } public void setKitTimestamp(String name, final long time) { name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH); holder.timestamps().kits().put(name, time); config.save(); } public List getCooldownsList() { return holder.timestamps().commandCooldowns(); } public Map getCommandCooldowns() { final Map map = new HashMap<>(); for (final CommandCooldown c : getCooldownsList()) { if (c == null || c.isIncomplete()) { // stupid solution to stupid problem continue; } map.put(c.pattern(), c.value()); } return map; } public Date getCommandCooldownExpiry(final String label) { for (CommandCooldown cooldown : getCooldownsList()) { if (cooldown == null || cooldown.isIncomplete()) { // stupid solution to stupid problem continue; } if (cooldown.pattern().matcher(label).matches()) { return new Date(cooldown.value()); } } return null; } public void addCommandCooldown(final Pattern pattern, final Date expiresAt, final boolean save) { final CommandCooldown cooldown = new CommandCooldown(); cooldown.pattern(pattern); cooldown.value(expiresAt.getTime()); if (cooldown.isIncomplete()) { return; } holder.timestamps().commandCooldowns().add(cooldown); if (save) { save(); } } public boolean clearCommandCooldown(final Pattern pattern) { if (holder.timestamps().commandCooldowns().isEmpty()) { return false; // false for no modification } if (getCooldownsList().removeIf(cooldown -> cooldown != null && !cooldown.isIncomplete() && cooldown.pattern().equals(pattern))) { save(); return true; } return false; } public boolean isAcceptingPay() { return holder.acceptingPay(); } public void setAcceptingPay(final boolean acceptingPay) { holder.acceptingPay(acceptingPay); save(); } public boolean isPromptingPayConfirm() { return holder.confirmPay() != null ? holder.confirmPay() : ess.getSettings().isConfirmCommandEnabledByDefault("pay"); } public void setPromptingPayConfirm(final boolean prompt) { holder.confirmPay(prompt); save(); } public boolean isPromptingClearConfirm() { return holder.confirmClear() != null ? holder.confirmClear() : ess.getSettings().isConfirmCommandEnabledByDefault("clearinventory"); } public void setPromptingClearConfirm(final boolean prompt) { holder.confirmClear(prompt); save(); } public boolean isLastMessageReplyRecipient() { return holder.lastMessageReplyRecipient() != null ? holder.lastMessageReplyRecipient() : ess.getSettings().isLastMessageReplyRecipient(); } public void setLastMessageReplyRecipient(final boolean enabled) { holder.lastMessageReplyRecipient(enabled); save(); } public boolean isBaltopExcludeCache() { return holder.baltopExempt(); } public void setBaltopExemptCache(boolean baltopExempt) { holder.baltopExempt(baltopExempt); config.save(); } public List getPastUsernames() { return holder.pastUsernames(); } public void addPastUsername(String username) { final List usernames = holder.pastUsernames(); usernames.add(0, username); holder.pastUsernames(usernames); config.save(); } public boolean isShouting() { if (holder.shouting() == null) { holder.shouting(ess.getSettings().isShoutDefault()); } return holder.shouting(); } public void setShouting(boolean shouting) { holder.shouting(shouting); config.save(); } public UUID getConfigUUID() { return config.getUuid(); } public void save() { config.save(); } public void startTransaction() { config.startTransaction(); } public void stopTransaction() { config.stopTransaction(); } public void setConfigProperty(String node, Object object) { setConfigPropertyRaw("info." + node, object); } public void setConfigPropertyRaw(String node, Object object) { config.setRaw(node, object); config.save(); } public Set getConfigKeys() { return ConfigurateUtil.getKeys(config.getSection("info")); } public Map getConfigMap() { return ConfigurateUtil.getRawMap(config.getSection("info")); } public Map getConfigMap(final String node) { return ConfigurateUtil.getRawMap(config.getSection("info." + node)); } }