From b393636cb3f7e05ef8b34804eeb06357f1b9cfbe Mon Sep 17 00:00:00 2001 From: Cow Date: Tue, 28 Jul 2020 00:12:36 +0200 Subject: Renamed package to match cowtipper.de --- .../cowtipper/cowlection/handler/DungeonCache.java | 52 ++++++ .../cowlection/handler/FriendsHandler.java | 176 +++++++++++++++++++++ .../cowtipper/cowlection/handler/PlayerCache.java | 47 ++++++ 3 files changed, 275 insertions(+) create mode 100644 src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java create mode 100644 src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java create mode 100644 src/main/java/de/cowtipper/cowlection/handler/PlayerCache.java (limited to 'src/main/java/de/cowtipper/cowlection/handler') diff --git a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java new file mode 100644 index 0000000..7cef4cd --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java @@ -0,0 +1,52 @@ +package de.cowtipper.cowlection.handler; + +import de.cowtipper.cowlection.Cowlection; +import de.cowtipper.cowlection.util.TickDelay; +import net.minecraft.util.EnumChatFormatting; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class DungeonCache { + private boolean isInDungeon; + private final Map deathCounter; + private final Cowlection main; + + public DungeonCache(Cowlection main) { + this.main = main; + deathCounter = new HashMap<>(); + } + + public void onDungeonEntered() { + isInDungeon = true; + deathCounter.clear(); + } + + public void onDungeonLeft() { + isInDungeon = false; + deathCounter.clear(); + } + + public void addDeath(String playerName) { + int previousPlayerDeaths = deathCounter.getOrDefault(playerName, 0); + deathCounter.put(playerName, previousPlayerDeaths + 1); + + new TickDelay(this::sendDeathCounts, 1); + } + + public boolean isInDungeon() { + return isInDungeon; + } + + public void sendDeathCounts() { + if (deathCounter.isEmpty()) { + main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "☠ Deaths: " + EnumChatFormatting.WHITE + "none \\o/"); + } else { + String deaths = deathCounter.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).map(deathEntry -> " " + EnumChatFormatting.WHITE + deathEntry.getKey() + ": " + EnumChatFormatting.LIGHT_PURPLE + deathEntry.getValue()) + .collect(Collectors.joining("\n")); + main.getChatHelper().sendMessage(EnumChatFormatting.RED, "☠ " + EnumChatFormatting.BOLD + "Deaths:\n" + deaths); + } + } +} diff --git a/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java b/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java new file mode 100644 index 0000000..ae1467a --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java @@ -0,0 +1,176 @@ +package de.cowtipper.cowlection.handler; + +import com.google.gson.JsonParseException; +import com.google.gson.reflect.TypeToken; +import de.cowtipper.cowlection.Cowlection; +import de.cowtipper.cowlection.command.exception.ApiContactException; +import de.cowtipper.cowlection.command.exception.MooCommandException; +import de.cowtipper.cowlection.data.Friend; +import de.cowtipper.cowlection.util.ApiUtils; +import de.cowtipper.cowlection.util.GsonUtils; +import io.netty.util.internal.ConcurrentSet; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.event.ClickEvent; +import net.minecraft.event.HoverEvent; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatStyle; +import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class FriendsHandler { + private static final long UPDATE_FREQUENCY_DEFAULT = TimeUnit.HOURS.toMillis(10); + private final Cowlection main; + private final Set bestFriends = new ConcurrentSet<>(); + private final File bestFriendsFile; + private final AtomicInteger bestFriendQueue = new AtomicInteger(); + + public FriendsHandler(Cowlection main, File friendsFile) { + this.main = main; + this.bestFriendsFile = friendsFile; + loadBestFriends(); + updateBestFriends(); + } + + public boolean isBestFriend(String playerName, boolean ignoreCase) { + if (ignoreCase) { + return bestFriends.stream().map(Friend::getName).anyMatch(playerName::equalsIgnoreCase); + } else { + return bestFriends.stream().map(Friend::getName).anyMatch(playerName::equals); + } + } + + public void addBestFriend(String name) { + if (name.isEmpty()) { + return; + } + + ApiUtils.fetchFriendData(name, friend -> { + if (friend == null) { + throw new ApiContactException("Mojang", "didn't add " + name + " as a best friend."); + } else if (friend.equals(Friend.FRIEND_NOT_FOUND)) { + throw new PlayerNotFoundException("There is no player with the name " + EnumChatFormatting.DARK_RED + name + EnumChatFormatting.RED + "."); + } else { + boolean added = bestFriends.add(friend); + if (added) { + main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Added " + EnumChatFormatting.DARK_GREEN + friend.getName() + EnumChatFormatting.GREEN + " as best friend."); + saveBestFriends(); + } + } + }); + } + + public boolean removeBestFriend(String name) { + boolean removed = bestFriends.removeIf(friend -> friend.getName().equalsIgnoreCase(name)); + if (removed) { + saveBestFriends(); + } + return removed; + } + + public Set getBestFriends() { + return bestFriends.stream().map(Friend::getName).collect(Collectors.toCollection(TreeSet::new)); + } + + public Friend getBestFriend(String name) { + return bestFriends.stream().filter(friend -> friend.getName().equalsIgnoreCase(name)).findFirst().orElse(Friend.FRIEND_NOT_FOUND); + } + + private Friend getBestFriend(UUID uuid) { + return bestFriends.stream().filter(friend -> friend.getUuid().equals(uuid)).findFirst().orElse(Friend.FRIEND_NOT_FOUND); + } + + public void updateBestFriends() { + bestFriends.stream().filter(friend -> System.currentTimeMillis() - friend.getLastChecked() > UPDATE_FREQUENCY_DEFAULT) + .forEach(friend1 -> { + bestFriendQueue.incrementAndGet(); + updateBestFriend(friend1, false); + }); + } + + public void updateBestFriend(Friend friend, boolean isCommandTriggered) { + ApiUtils.fetchCurrentName(friend, newName -> { + if (newName == null) { + // skipping friend, something went wrong with API request + if (isCommandTriggered) { + throw new ApiContactException("Mojang", "couldn't check " + EnumChatFormatting.DARK_RED + friend.getName() + EnumChatFormatting.RED + " (possible) new player name"); + } + } else if (newName.equals(ApiUtils.UUID_NOT_FOUND)) { + throw new PlayerNotFoundException("How did you manage to get a unique id on your best friends list that has no name attached to it?"); + } else if (newName.equals(friend.getName())) { + // name hasn't changed, only updating lastChecked timestamp + Friend bestFriend = getBestFriend(friend.getUuid()); + if (!bestFriend.equals(Friend.FRIEND_NOT_FOUND)) { + bestFriend.setLastChecked(System.currentTimeMillis()); + if (isCommandTriggered) { + throw new MooCommandException(friend.getName() + " hasn't changed his name"); + } + } + } else { + // name has changed + main.getChatHelper().sendMessage(new ChatComponentText("Your best friend " + EnumChatFormatting.DARK_GREEN + friend.getName() + EnumChatFormatting.GREEN + " changed the name to " + EnumChatFormatting.DARK_GREEN + newName + EnumChatFormatting.GREEN + ".").setChatStyle(new ChatStyle() + .setColor(EnumChatFormatting.GREEN) + .setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://namemc.com/search?q=" + newName)) + .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "View " + EnumChatFormatting.GOLD + newName + EnumChatFormatting.YELLOW + "'s name history on namemc.com"))))); + + Friend bestFriend = getBestFriend(friend.getUuid()); + if (!bestFriend.equals(Friend.FRIEND_NOT_FOUND)) { + bestFriend.setName(newName); + bestFriend.setLastChecked(System.currentTimeMillis()); + } + } + if (isCommandTriggered) { + saveBestFriends(); + } else { + int remainingFriendsToCheck = bestFriendQueue.decrementAndGet(); + if (remainingFriendsToCheck == 0) { + // we're done with checking for name changes, save updates to file! + saveBestFriends(); + } + } + }); + } + + public synchronized void saveBestFriends() { + try { + String bestFriendsJsonZoned = GsonUtils.toJson(this.bestFriends); + FileUtils.writeStringToFile(this.bestFriendsFile, bestFriendsJsonZoned, StandardCharsets.UTF_8); + } catch (IOException e) { + main.getLogger().error("Couldn't save best friends", e); + } + } + + private void loadBestFriends() { + try { + boolean createdNewFile = this.bestFriendsFile.createNewFile(); + + this.bestFriends.clear(); + if (!createdNewFile) { + String bestFriendsData = FileUtils.readFileToString(this.bestFriendsFile, StandardCharsets.UTF_8); + if (bestFriendsData.length() > 0) { + this.bestFriends.addAll(parseJson(bestFriendsData)); + } + } + } catch (IOException e) { + main.getLogger().error("Couldn't read best friends file " + this.bestFriendsFile, e); + } catch (JsonParseException e) { + main.getLogger().error("Couldn't parse best friends file " + this.bestFriendsFile, e); + } + } + + private Set parseJson(String bestFriendsData) { + Type collectionType = new TypeToken>() { + }.getType(); + return GsonUtils.fromJson(bestFriendsData, collectionType); + } +} diff --git a/src/main/java/de/cowtipper/cowlection/handler/PlayerCache.java b/src/main/java/de/cowtipper/cowlection/handler/PlayerCache.java new file mode 100644 index 0000000..2206473 --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/handler/PlayerCache.java @@ -0,0 +1,47 @@ +package de.cowtipper.cowlection.handler; + +import com.google.common.collect.EvictingQueue; +import de.cowtipper.cowlection.Cowlection; + +import java.util.SortedSet; +import java.util.TreeSet; + +public class PlayerCache { + @SuppressWarnings("UnstableApiUsage") + private final EvictingQueue nameCache = EvictingQueue.create(50); + @SuppressWarnings("UnstableApiUsage") + private final EvictingQueue bestFriendCache = EvictingQueue.create(50); + private final Cowlection main; + + public PlayerCache(Cowlection main) { + this.main = main; + } + + public void add(String name) { + // remove old entry (if exists) to 'push' name to the end of the queue + nameCache.remove(name); + nameCache.add(name); + } + + public void addBestFriend(String name) { + // remove old entry (if exists) to 'push' name to the end of the queue + bestFriendCache.remove(name); + bestFriendCache.add(name); + } + + public void removeBestFriend(String name) { + bestFriendCache.remove(name); + } + + public SortedSet getAllNamesSorted() { + SortedSet nameList = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + nameList.addAll(bestFriendCache); + nameList.addAll(nameCache); + return nameList; + } + + public void clearAllCaches() { + nameCache.clear(); + bestFriendCache.clear(); + } +} -- cgit