aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/eu/olli/cowmoonication
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/olli/cowmoonication')
-rw-r--r--src/main/java/eu/olli/cowmoonication/Cowmoonication.java2
-rw-r--r--src/main/java/eu/olli/cowmoonication/command/MooCommand.java89
-rw-r--r--src/main/java/eu/olli/cowmoonication/config/MooConfig.java11
-rw-r--r--src/main/java/eu/olli/cowmoonication/friends/Friends.java4
-rw-r--r--src/main/java/eu/olli/cowmoonication/listener/ChatListener.java13
-rw-r--r--src/main/java/eu/olli/cowmoonication/util/ApiUtils.java34
-rw-r--r--src/main/java/eu/olli/cowmoonication/util/HyStalking.java123
-rw-r--r--src/main/java/eu/olli/cowmoonication/util/Utils.java5
8 files changed, 274 insertions, 7 deletions
diff --git a/src/main/java/eu/olli/cowmoonication/Cowmoonication.java b/src/main/java/eu/olli/cowmoonication/Cowmoonication.java
index 2b46e71..3f0ab44 100644
--- a/src/main/java/eu/olli/cowmoonication/Cowmoonication.java
+++ b/src/main/java/eu/olli/cowmoonication/Cowmoonication.java
@@ -25,7 +25,7 @@ import java.io.File;
updateJSON = "https://raw.githubusercontent.com/cow-mc/Cowmoonication/master/update.json")
public class Cowmoonication {
public static final String MODID = "cowmoonication";
- public static final String VERSION = "1.8.9-0.2.0";
+ public static final String VERSION = "1.8.9-0.3.0";
public static final String MODNAME = "Cowmoonication";
private File modsDir;
private MooConfig config;
diff --git a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java
index 22d510a..e933c30 100644
--- a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java
+++ b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java
@@ -3,6 +3,9 @@ package eu.olli.cowmoonication.command;
import eu.olli.cowmoonication.Cowmoonication;
import eu.olli.cowmoonication.config.MooConfig;
import eu.olli.cowmoonication.config.MooGuiConfig;
+import eu.olli.cowmoonication.friends.Friend;
+import eu.olli.cowmoonication.util.ApiUtils;
+import eu.olli.cowmoonication.util.HyStalking;
import eu.olli.cowmoonication.util.TickDelay;
import eu.olli.cowmoonication.util.Utils;
import net.minecraft.client.Minecraft;
@@ -33,7 +36,15 @@ public class MooCommand extends CommandBase {
return;
}
// sub commands: friends
- if (args.length == 2 && args[0].equalsIgnoreCase("add")) {
+ if (args[0].equalsIgnoreCase("stalk")) {
+ if (args.length != 2) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Usage: /" + getCommandName() + " stalk <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "\"" + args[1] + "\" is not a valid player name.");
+ } else {
+ handleStalking(args[1]);
+ }
+ } else if (args.length == 2 && args[0].equalsIgnoreCase("add")) {
handleBestFriendAdd(args[1]);
} else if (args.length == 2 && args[0].equalsIgnoreCase("remove")) {
handleBestFriendRemove(args[1]);
@@ -58,6 +69,8 @@ public class MooCommand extends CommandBase {
Minecraft.getMinecraft().gameSettings.guiScale = scale;
main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u2714 New GUI scale: " + EnumChatFormatting.DARK_GREEN + scale + EnumChatFormatting.GREEN + " (previous: " + EnumChatFormatting.DARK_GREEN + currentGuiScale + EnumChatFormatting.GREEN + ")");
}
+ } else if (args[0].equalsIgnoreCase("apikey")) {
+ handleApiKey(args);
}
// sub-commands: update mod
else if (args[0].equalsIgnoreCase("update")) {
@@ -101,6 +114,75 @@ public class MooCommand extends CommandBase {
}
}
+ private void handleApiKey(String[] args) {
+ if (args.length == 1) {
+ String firstSentence;
+ EnumChatFormatting color;
+ EnumChatFormatting colorSecondary;
+ if (Utils.isValidUuid(MooConfig.moo)) {
+ firstSentence = "You already set your Hypixel API key.";
+ color = EnumChatFormatting.GREEN;
+ colorSecondary = EnumChatFormatting.DARK_GREEN;
+ } else {
+ firstSentence = "You haven't set your Hypixel API key yet.";
+ color = EnumChatFormatting.RED;
+ colorSecondary = EnumChatFormatting.DARK_RED;
+ }
+ main.getChatHelper().sendMessage(color, firstSentence + " Use " + colorSecondary + "/api new" + color + " to request a new API key from Hypixel or use " + colorSecondary + "/" + this.getCommandName() + " apikey <key>" + color + " to manually set your existing API key.");
+ } else {
+ String key = args[1];
+ if (Utils.isValidUuid(key)) {
+ MooConfig.moo = key;
+ main.getConfig().syncFromFields();
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Updated API key!");
+ } else {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "That doesn't look like a valid API key...");
+ }
+ }
+ }
+
+ private void handleStalking(String playerName) {
+ if (!Utils.isValidUuid(MooConfig.moo)) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "You haven't set your Hypixel API key yet. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key.");
+ return;
+ }
+ main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "Stalking " + EnumChatFormatting.GOLD + playerName + EnumChatFormatting.YELLOW + ". This may take a few seconds.");
+ boolean isBestFriend = main.getFriends().isBestFriend(playerName, true);
+ if (isBestFriend) {
+ Friend stalkedPlayer = main.getFriends().getBestFriend(playerName);
+ // we have the uuid already, so stalk the player
+ stalkPlayer(stalkedPlayer);
+ } else {
+ // fetch player uuid
+ ApiUtils.fetchFriendData(playerName, stalkedPlayer -> {
+ if (stalkedPlayer == null) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Sorry, could contact Mojang's API and thus couldn't stalk " + EnumChatFormatting.DARK_RED + playerName);
+ } else if (stalkedPlayer.equals(Friend.FRIEND_NOT_FOUND)) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "There is no player with the name " + EnumChatFormatting.DARK_RED + playerName + EnumChatFormatting.RED + ".");
+ } else {
+ // ... then stalk the player
+ stalkPlayer(stalkedPlayer);
+ }
+ });
+ }
+ }
+
+ private void stalkPlayer(Friend stalkedPlayer) {
+ ApiUtils.fetchPlayerStatus(stalkedPlayer, hyStalking -> {
+ if (hyStalking != null && hyStalking.isSuccess()) {
+ HyStalking.HySession session = hyStalking.getSession();
+ if (session.isOnline()) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, EnumChatFormatting.GOLD + stalkedPlayer.getName() + EnumChatFormatting.YELLOW + " is currently playing " + session.getGameType() + ": " + session.getMode() + (session.getMap() != null ? " (Map: " + session.getMap() + ")" : ""));
+ } else {
+ main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, EnumChatFormatting.GOLD + stalkedPlayer.getName() + EnumChatFormatting.YELLOW + " is currently " + EnumChatFormatting.RED + "offline" + EnumChatFormatting.YELLOW + " (or deactivated API access).");
+ }
+ } else {
+ String cause = (hyStalking != null) ? hyStalking.getCause() : null;
+ main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Something went wrong contacting the Hypixel API. Couldn't stalk " + EnumChatFormatting.DARK_RED + stalkedPlayer.getName() + EnumChatFormatting.RED + (cause != null ? " (Reason: " + EnumChatFormatting.DARK_RED + cause + EnumChatFormatting.RED + ")" : "") + ".");
+ }
+ });
+ }
+
private void handleBestFriendAdd(String username) {
if (!Utils.isValidMcName(username)) {
main.getChatHelper().sendMessage(EnumChatFormatting.RED, EnumChatFormatting.DARK_RED + username + EnumChatFormatting.RED + "? This... doesn't look like a valid username.");
@@ -147,6 +229,7 @@ public class MooCommand extends CommandBase {
public String getCommandUsage(ICommandSender sender) {
IChatComponent usage = new ChatComponentText("\u279C Cowmoonication commands:").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(true))
.appendSibling(createCmdHelpSection(1, "Friends"))
+ .appendSibling(createCmdHelpEntry("stalk", "Get info of player's status"))
.appendSibling(createCmdHelpEntry("add", "Add best friends"))
.appendSibling(createCmdHelpEntry("remove", "Remove best friends"))
.appendSibling(createCmdHelpEntry("list", "View list of best friends"))
@@ -187,8 +270,8 @@ public class MooCommand extends CommandBase {
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args,
- /* friends */ "add", "remove", "list", "nameChangeCheck", "toggle",
- /* miscellaneous */ "guiscale", "config",
+ /* friends */ "stalk", "add", "remove", "list", "nameChangeCheck", "toggle",
+ /* miscellaneous */ "config", "guiscale", "apikey",
/* update mod */ "update", "updateHelp", "version", "folder",
/* help */ "help");
}
diff --git a/src/main/java/eu/olli/cowmoonication/config/MooConfig.java b/src/main/java/eu/olli/cowmoonication/config/MooConfig.java
index d13758c..73e8bbc 100644
--- a/src/main/java/eu/olli/cowmoonication/config/MooConfig.java
+++ b/src/main/java/eu/olli/cowmoonication/config/MooConfig.java
@@ -1,6 +1,7 @@
package eu.olli.cowmoonication.config;
import eu.olli.cowmoonication.Cowmoonication;
+import eu.olli.cowmoonication.util.Utils;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
@@ -14,6 +15,7 @@ import java.util.List;
public class MooConfig {
public static boolean doUpdateCheck;
public static boolean filterFriendNotifications;
+ public static String moo;
private static Configuration cfg = null;
public MooConfig(Configuration configuration) {
@@ -47,7 +49,7 @@ public class MooConfig {
/**
* Save the Configuration variables (fields) to disk
*/
- private void syncFromFields() {
+ public void syncFromFields() {
syncConfig(false, false);
}
@@ -71,18 +73,25 @@ public class MooConfig {
final boolean FILTER_FRIEND_NOTIFICATIONS = true;
Property propFilterFriendNotify = cfg.get(Configuration.CATEGORY_CLIENT, "filterFriendNotifications", FILTER_FRIEND_NOTIFICATIONS, "Set to false to receive all login/logout messages, set to true to only get notifications of 'best friends' joining/leaving");
+ final String MOO = "";
+ Property propMoo = cfg.get(Configuration.CATEGORY_CLIENT, "moo", MOO, "The answer to life the universe and everything. Don't edit this entry manually!", Utils.VALID_UUID_PATTERN);
+ propMoo.setShowInGui(false);
+
List<String> propOrderGeneral = new ArrayList<>();
propOrderGeneral.add(propDoUpdateCheck.getName());
propOrderGeneral.add(propFilterFriendNotify.getName());
+ propOrderGeneral.add(propMoo.getName());
cfg.setCategoryPropertyOrder(Configuration.CATEGORY_CLIENT, propOrderGeneral);
if (readFieldsFromConfig) {
doUpdateCheck = propDoUpdateCheck.getBoolean(DO_UPDATE_CHECK);
filterFriendNotifications = propFilterFriendNotify.getBoolean(FILTER_FRIEND_NOTIFICATIONS);
+ moo = propMoo.getString();
}
propDoUpdateCheck.set(doUpdateCheck);
propFilterFriendNotify.set(filterFriendNotifications);
+ propMoo.set(moo);
if (cfg.hasChanged()) {
cfg.save();
diff --git a/src/main/java/eu/olli/cowmoonication/friends/Friends.java b/src/main/java/eu/olli/cowmoonication/friends/Friends.java
index e37b4a4..8c29d16 100644
--- a/src/main/java/eu/olli/cowmoonication/friends/Friends.java
+++ b/src/main/java/eu/olli/cowmoonication/friends/Friends.java
@@ -80,6 +80,10 @@ public class Friends {
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);
}
diff --git a/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java b/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java
index 42a45e0..78a8f29 100644
--- a/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java
+++ b/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java
@@ -2,6 +2,7 @@ package eu.olli.cowmoonication.listener;
import eu.olli.cowmoonication.Cowmoonication;
import eu.olli.cowmoonication.config.MooConfig;
+import eu.olli.cowmoonication.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiNewChat;
@@ -34,9 +35,9 @@ public class ChatListener {
@SubscribeEvent
public void onLogInOutMessage(ClientChatReceivedEvent e) {
- if (e.type != 2 && MooConfig.filterFriendNotifications) { // normal chat or system msg
+ if (e.type != 2) { // normal chat or system msg
String text = e.message.getUnformattedText();
- if (text.length() < 42 && // to prevent the party disbanded message from being filtered: "The party was disbanded because all invites have expired and all members have left."
+ if (MooConfig.filterFriendNotifications && text.length() < 42 && // to prevent the party disbanded message from being filtered: "The party was disbanded because all invites have expired and all members have left."
(text.endsWith(" joined.") || text.endsWith(" left.") // Hypixel
|| text.endsWith(" joined the game") || text.endsWith(" left the game."))) { // Spigot
// TODO maybe check which server thePlayer is on and check for logout pattern accordingly
@@ -48,6 +49,14 @@ public class ChatListener {
if (!isBestFriend) {
e.setCanceled(true);
}
+ } else if (text.length() == 56 && text.startsWith("Your new API key is ")) {
+ // Your new API key is 00000000-0000-0000-0000-000000000000
+ String moo = text.substring(20, 56);
+ if (Utils.isValidUuid(moo)) {
+ MooConfig.moo = moo;
+ main.getConfig().syncFromFields();
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Added updated API key in Cowmoonication config!");
+ }
}
}
}
diff --git a/src/main/java/eu/olli/cowmoonication/util/ApiUtils.java b/src/main/java/eu/olli/cowmoonication/util/ApiUtils.java
index 5ff7d5d..d408721 100644
--- a/src/main/java/eu/olli/cowmoonication/util/ApiUtils.java
+++ b/src/main/java/eu/olli/cowmoonication/util/ApiUtils.java
@@ -5,10 +5,13 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import com.mojang.util.UUIDTypeAdapter;
+import eu.olli.cowmoonication.Cowmoonication;
+import eu.olli.cowmoonication.config.MooConfig;
import eu.olli.cowmoonication.friends.Friend;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -21,6 +24,7 @@ public class ApiUtils {
public static final String UUID_NOT_FOUND = "UUID-NOT-FOUND";
private static final String NAME_TO_UUID_URL = "https://api.mojang.com/users/profiles/minecraft/";
private static final String UUID_TO_NAME_URL = "https://api.mojang.com/user/profiles/%s/names";
+ private static final String STALKING_URL = "https://api.hypixel.net/status?key=%s&uuid=%s";
private static ExecutorService pool = Executors.newCachedThreadPool();
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).registerTypeAdapter(Friend.class, new Friend.FriendCreator()).create();
@@ -67,4 +71,34 @@ public class ApiUtils {
}
return null;
}
+
+ public static void fetchPlayerStatus(Friend friend, Consumer<HyStalking> action) {
+ pool.execute(() -> action.accept(stalkPlayer(friend)));
+ }
+
+ private static HyStalking stalkPlayer(Friend friend) {
+ try {
+ HttpURLConnection connection = (HttpURLConnection) new URL(String.format(STALKING_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid()))).openConnection();
+ connection.setReadTimeout(5000);
+ connection.addRequestProperty("User-Agent", "Forge Mod " + Cowmoonication.MODNAME + "/" + Cowmoonication.VERSION + " (https://github.com/cow-mc/Cowmoonication/)");
+
+ connection.getResponseCode();
+ if (connection.getResponseCode() == 204) {
+ return null;
+ } else { // various possible http status code: 200, 403, 422
+ BufferedReader reader;
+ InputStream errorStream = connection.getErrorStream();
+ if (errorStream != null) {
+ reader = new BufferedReader(new InputStreamReader(errorStream));
+ } else {
+ reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ }
+
+ return gson.fromJson(reader, HyStalking.class);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
}
diff --git a/src/main/java/eu/olli/cowmoonication/util/HyStalking.java b/src/main/java/eu/olli/cowmoonication/util/HyStalking.java
new file mode 100644
index 0000000..a46e1b5
--- /dev/null
+++ b/src/main/java/eu/olli/cowmoonication/util/HyStalking.java
@@ -0,0 +1,123 @@
+package eu.olli.cowmoonication.util;
+
+import org.apache.commons.lang3.text.WordUtils;
+
+public class HyStalking {
+ private boolean success;
+ private String cause;
+ private HySession session;
+
+ public HyStalking() {
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public String getCause() {
+ return cause;
+ }
+
+ public HySession getSession() {
+ return session;
+ }
+
+ public static class HySession {
+ private boolean online;
+ private String gameType;
+ private String mode;
+ private String map;
+
+ public HySession() {
+ }
+
+ public boolean isOnline() {
+ return online;
+ }
+
+ public String getGameType() {
+ String cleanGameType;
+ try {
+ cleanGameType = GameType.valueOf(gameType).getCleanName();
+ } catch (IllegalArgumentException e) {
+ // no matching game type found
+ cleanGameType = WordUtils.capitalizeFully(gameType.replace('_', ' '));
+ }
+ return cleanGameType;
+ }
+
+ public String getMode() {
+ // list partially taken from https://api.hypixel.net/gameCounts?key=MOO
+ switch (mode) {
+ // SkyBlock related
+ case "dynamic":
+ return "Private Island";
+ case "hub":
+ return "Hub";
+ case "combat_1":
+ return "Spider's Den";
+ case "combat_2":
+ return "Blazing Fortress";
+ case "combat_3":
+ return "The End";
+ case "farming_1":
+ return "The Barn";
+ case "farming_2":
+ return "Mushroom Desert";
+ case "foraging_1":
+ return "The Park";
+ case "mining_1":
+ return "Gold Mine";
+ case "mining_2":
+ return "Deep Caverns";
+ default:
+ return WordUtils.capitalizeFully(mode.replace('_', ' '));
+ }
+ }
+
+ public String getMap() {
+ return map;
+ }
+
+ // TODO replace with api request: https://github.com/HypixelDev/PublicAPI/blob/master/Documentation/misc/GameType.md
+ public enum GameType {
+ QUAKECRAFT("Quakecraft"),
+ WALLS("Walls"),
+ PAINTBALL("Paintball"),
+ SURVIVAL_GAMES("Blitz Survival Games"),
+ TNTGAMES("The TNT Games"),
+ VAMPIREZ("VampireZ"),
+ WALLS3("Mega Walls"),
+ ARCADE("Arcade"),
+ ARENA("Arena Brawl"),
+ UHC("UHC Champions"),
+ MCGO("Cops and Crims"),
+ BATTLEGROUND("Warlords"),
+ SUPER_SMASH("Smash Heroes"),
+ GINGERBREAD("Turbo Kart Racers"),
+ HOUSING("Housing"),
+ SKYWARS("SkyWars"),
+ TRUE_COMBAT("Crazy Walls"),
+ SPEED_UHC("Speed UHC"),
+ SKYCLASH("SkyClash"),
+ LEGACY("Classic Games"),
+ PROTOTYPE("Prototype"),
+ BEDWARS("Bed Wars"),
+ MURDER_MYSTERY("Murder Mystery"),
+ BUILD_BATTLE("Build Battle"),
+ DUELS("Duels"),
+ SKYBLOCK("SkyBlock"),
+ PIT("Pit");
+
+ private final String cleanName;
+
+ GameType(String cleanName) {
+ this.cleanName = cleanName;
+ }
+
+ public String getCleanName() {
+ return cleanName;
+ }
+ }
+ }
+}
diff --git a/src/main/java/eu/olli/cowmoonication/util/Utils.java b/src/main/java/eu/olli/cowmoonication/util/Utils.java
index 0b890f0..ec96bf1 100644
--- a/src/main/java/eu/olli/cowmoonication/util/Utils.java
+++ b/src/main/java/eu/olli/cowmoonication/util/Utils.java
@@ -3,11 +3,16 @@ package eu.olli.cowmoonication.util;
import java.util.regex.Pattern;
public final class Utils {
+ public static final Pattern VALID_UUID_PATTERN = Pattern.compile("^(\\w{8})-(\\w{4})-(\\w{4})-(\\w{4})-(\\w{12})$");
private static final Pattern VALID_USERNAME = Pattern.compile("^[\\w]{1,16}$");
private Utils() {
}
+ public static boolean isValidUuid(String uuid) {
+ return VALID_UUID_PATTERN.matcher(uuid).matches();
+ }
+
public static boolean isValidMcName(String username) {
return VALID_USERNAME.matcher(username).matches();
}