More formatting, IMC

master
Chikachi 2017-06-25 01:21:54 +02:00
parent a07cb77db2
commit 2f065a6997
No known key found for this signature in database
GPG Key ID: 0136086A0AC09F5E
12 changed files with 481 additions and 37 deletions

22
format_discord.txt Normal file
View File

@ -0,0 +1,22 @@
*italics*
**bold**
***bold italics***
~~strikeout~~
__underline__
__*underline italics*__
__**underline bold**__
__***underline bold italics***__
§nMinecraft Formatting
§r§00 §11 §22 §33
§44 §55 §66 §77
§88 §99 §aa §bb
§cc §dd §ee §ff
§rk §kMinecraft
§rl §lMinecraft
§rm §mMinecraft
§rn §nMinecraft
§ro §oMinecraft
§rr §rMinecraft

View File

@ -18,18 +18,23 @@ import chikachi.discord.command.CommandDiscord;
import chikachi.discord.core.CoreConstants;
import chikachi.discord.core.CoreProxy;
import chikachi.discord.core.DiscordClient;
import chikachi.discord.core.Patterns;
import chikachi.discord.listener.DiscordListener;
import chikachi.discord.listener.MinecraftListener;
import net.minecraft.server.MinecraftServer;
import com.google.common.base.Joiner;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Mod(modid = CoreConstants.MODID, name = CoreConstants.MODNAME, version = CoreConstants.VERSION, serverSideOnly = true, acceptableRemoteVersions = "*")
public class DiscordIntegration {
@Mod.Instance
public static DiscordIntegration instance;
static MinecraftServer minecraftServer;
private static CoreProxy coreProxy = new CoreProxy();
@ -37,17 +42,143 @@ public class DiscordIntegration {
public void onPreInit(FMLPreInitializationEvent event) {
coreProxy.onPreInit(event.getModConfigurationDirectory());
char softReset = '\ufffd';
Patterns.addDiscordToMinecraftPattern(Patterns.strikeThroughPattern, TextFormatting.STRIKETHROUGH + "$1" + softReset);
Patterns.addDiscordToMinecraftPattern(Patterns.underlinePattern, TextFormatting.UNDERLINE + "$1" + softReset);
Patterns.addDiscordToMinecraftPattern(Patterns.italicMePattern, TextFormatting.ITALIC + "$1" + softReset);
Patterns.addDiscordToMinecraftPattern(Patterns.italicPattern, TextFormatting.ITALIC + "$1" + softReset);
Patterns.addDiscordToMinecraftPattern(Patterns.boldPattern, TextFormatting.BOLD + "$1" + softReset);
Patterns.addDiscordToMinecraftPattern(Patterns.multiCodePattern, "$1");
Patterns.addDiscordToMinecraftPattern(Patterns.singleCodePattern, "$1");
Patterns.addMinecraftFormattingPattern(Pattern.compile("(?i)(([\u00a7&]([0-9A-FK-OR]))|" + softReset + ")"), new Patterns.ReplacementCallback() {
private ArrayList<TextFormatting> layers = new ArrayList<>();
@Override
public String pre(String text) {
return text;
}
@Override
public String replace(ArrayList<String> groups) {
if (groups.get(0).charAt(0) == softReset) {
if (layers.size() > 0) {
layers.remove(layers.size() - 1);
return TextFormatting.RESET + Joiner.on("").join(layers.stream().map(TextFormatting::toString).collect(Collectors.toList()));
}
return TextFormatting.RESET.toString();
}
String modifier = String.valueOf('\u00a7') + groups.get(2).substring(1);
for (TextFormatting textFormatting : TextFormatting.values()) {
if (modifier.equalsIgnoreCase(textFormatting.toString())) {
layers.add(textFormatting);
}
}
return modifier;
}
@Override
public String post(String text) {
layers.clear();
return text;
}
});
Patterns.addDiscordFormattingPattern(Pattern.compile("(?i)(\u00a7[0-9A-FK-OR])"), new Patterns.ReplacementCallback() {
private boolean bold = false;
private boolean italic = false;
private boolean underline = false;
private boolean strikethrough = false;
@Override
public String pre(String text) {
return text;
}
@Override
public String replace(ArrayList<String> groups) {
String modifier = groups.get(0);
for (TextFormatting textFormatting : TextFormatting.values()) {
if (modifier.equalsIgnoreCase(textFormatting.toString())) {
if (textFormatting.equals(TextFormatting.BOLD)) {
bold = true;
modifier = "**";
} else if (textFormatting.equals(TextFormatting.ITALIC)) {
italic = true;
modifier = "*";
} else if (textFormatting.equals(TextFormatting.UNDERLINE)) {
underline = true;
modifier = "__";
} else if (textFormatting.equals(TextFormatting.STRIKETHROUGH)) {
strikethrough = true;
modifier = "~~";
} else if (textFormatting.equals(TextFormatting.RESET)) {
modifier = "";
if (bold) {
bold = false;
modifier += "**";
}
if (italic) {
italic = false;
modifier += "*";
}
if (underline) {
underline = false;
modifier += "__";
}
if (strikethrough) {
strikethrough = false;
modifier += "~~";
}
} else {
modifier = "";
}
break;
}
}
return modifier;
}
@Override
public String post(String text) {
if (bold) {
text += "**";
}
if (italic) {
text += "*";
}
if (underline) {
text += "__";
}
if (strikethrough) {
text += "~~";
}
bold = false;
italic = false;
underline = false;
strikethrough = false;
return text;
}
});
MinecraftForge.EVENT_BUS.register(new MinecraftListener());
}
@Mod.EventHandler
public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
minecraftServer = event.getServer();
}
@Mod.EventHandler
public void onServerStarting(FMLServerStartingEvent event) {
coreProxy.onServerStarting();
DiscordClient.getInstance().addEventListner(new DiscordListener());
event.registerServerCommand(new CommandDiscord());
@ -67,4 +198,9 @@ public class DiscordIntegration {
public void onServerStopped(FMLServerStoppedEvent event) {
coreProxy.onServerStopped();
}
@Mod.EventHandler
public void imcReceived(FMLInterModComms.IMCEvent event) {
event.getMessages().forEach(IMCHandler::onMessageReceived);
}
}

View File

@ -14,6 +14,9 @@
package chikachi.discord;
import chikachi.discord.core.DiscordClient;
import chikachi.discord.core.Message;
import chikachi.discord.core.config.types.MessageConfig;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.event.FMLInterModComms;
@ -23,6 +26,24 @@ import java.util.List;
public class IMCHandler {
private static List<String> registeredIMCMods = new ArrayList<>();
private static NBTTagCompound getErrorNBT(String method, String message) {
NBTTagCompound error = new NBTTagCompound();
error.setString("method", method);
error.setString("message", message);
return error;
}
public static void onMessageReceived(FMLInterModComms.IMCMessage imcMessage) {
String modId = imcMessage.getSender();
if (imcMessage.isStringMessage()) {
onMessageReceived(modId, imcMessage.key, imcMessage.getStringValue());
} else if (imcMessage.isNBTMessage()) {
onMessageReceived(modId, imcMessage.key, imcMessage.getNBTValue());
}
}
@SuppressWarnings("UnusedParameters")
public static void onMessageReceived(String modId, String key, String message) {
if (key.equalsIgnoreCase("registerListener")) {
@ -33,6 +54,13 @@ public class IMCHandler {
));
registeredIMCMods.add(modId);
} else {
FMLInterModComms.sendRuntimeMessage(
DiscordIntegration.instance,
modId,
"error",
getErrorNBT("registerListener", "Already registered")
);
}
} else if (key.equalsIgnoreCase("unregisterListener")) {
if (registeredIMCMods.contains(modId)) {
@ -42,22 +70,55 @@ public class IMCHandler {
));
registeredIMCMods.remove(modId);
} else {
FMLInterModComms.sendRuntimeMessage(
DiscordIntegration.instance,
modId,
"error",
getErrorNBT("registerListener", "Already unregistered")
);
}
}
}
public static void onMessageReceived(String modId, String key, NBTTagCompound message) {
if (key.equalsIgnoreCase("sendMessage")) {
if (message.hasKey("message")) {
/*new IMCMessageEvent(
if (!message.hasKey("message") || message.getString("message").trim().length() == 0) {
FMLInterModComms.sendRuntimeMessage(
DiscordIntegration.instance,
modId,
null,
message.getString("message")
).emit();*/
"error",
getErrorNBT("sendMessage", "Missing message")
);
return;
}
if (!message.hasKey("channel") || message.getLong("channel") == 0) {
FMLInterModComms.sendRuntimeMessage(
DiscordIntegration.instance,
modId,
"error",
getErrorNBT("sendMessage", "Missing channel")
);
return;
}
DiscordClient.getInstance().broadcast(
new Message(
modId,
new MessageConfig(
message.getString("message")
)
),
message.getLong("channel")
);
}
}
public static boolean haveListeners() {
return registeredIMCMods.size() > 0;
}
public static List<String> getRegisteredIMCMods() {
return registeredIMCMods;
}

View File

@ -14,6 +14,7 @@
package chikachi.discord.command;
import chikachi.discord.core.DiscordClient;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
@ -58,16 +59,23 @@ public class CommandDiscord extends CommandBase {
String commandName = argsList.remove(0).toLowerCase();
switch (commandName) {
case "config":
SubCommandConfig.execute(sender, argsList);
break;
case "connect":
DiscordClient.getInstance().connect(true);
break;
case "disconnect":
DiscordClient.getInstance().disconnect(true);
break;
case "online":
SubCommandOnline.execute(sender);
break;
case "tps":
SubCommandTps.execute(sender, argsList);
break;
case "config":
SubCommandConfig.execute(sender, argsList);
break;
case "unstuck":
SubCommandUnstuck.execute(sender, argsList);
break;
default:
sender.sendMessage(new TextComponentString("Unknown command"));
@ -85,7 +93,7 @@ public class CommandDiscord extends CommandBase {
int position = args.length;
if (position == 1) {
return getListOfStringsMatchingLastWord(args, "online", "tps", "config", "unstuck");
return getListOfStringsMatchingLastWord(args, "config", "connect", "disconnect", "online", "tps", "unstuck");
} else if (position == 2) {
if (args[0].equalsIgnoreCase("config")) {
return getListOfStringsMatchingLastWord(args, "load", "reload", "save");

View File

@ -0,0 +1,104 @@
/*
* Copyright (C) 2017 Chikachi
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*/
package chikachi.discord.command;
import chikachi.discord.DiscordFakePlayer;
import chikachi.discord.DiscordTeleporter;
import com.mojang.authlib.GameProfile;
import net.minecraft.block.state.IBlockState;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.IPlayerFileData;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.common.FMLCommonHandler;
import java.util.ArrayList;
public class SubCommandUnstuck {
public static void execute(ICommandSender sender, ArrayList<String> args) {
if (args.size() == 0) {
sender.sendMessage(new TextComponentString("Missing user"));
return;
}
String username = args.remove(0);
if (username.length() == 0) {
sender.sendMessage(new TextComponentString("Missing user"));
return;
}
WorldServer overworld = DimensionManager.getWorld(0);
BlockPos spawnpoint = overworld.getSpawnPoint();
IBlockState blockState = overworld.getBlockState(spawnpoint);
while (blockState.getBlock().isOpaqueCube(blockState)) {
spawnpoint = spawnpoint.up(2);
blockState = overworld.getBlockState(spawnpoint);
}
double x = spawnpoint.getX() + 0.5;
double y = spawnpoint.getY();
double z = spawnpoint.getZ() + 0.5;
MinecraftServer minecraftServer = FMLCommonHandler.instance().getMinecraftServerInstance();
EntityPlayerMP player = minecraftServer.getPlayerList().getPlayerByUsername(username);
if (player != null) {
int fromDimension = player.dimension;
if (fromDimension != 0) {
minecraftServer.getPlayerList().transferPlayerToDimension(player, 0, new DiscordTeleporter(overworld));
if (fromDimension == 1 && player.isEntityAlive()) {
overworld.spawnEntity(player);
overworld.updateEntityWithOptionalForce(player, true);
}
}
player.setPositionAndUpdate(x, y, z);
} else {
GameProfile playerProfile = minecraftServer.getPlayerProfileCache().getGameProfileForUsername(username);
if (playerProfile == null || !playerProfile.isComplete()) {
sender.sendMessage(new TextComponentString("Player not found"));
return;
}
DiscordFakePlayer fakePlayer = new DiscordFakePlayer(minecraftServer.worlds[0], playerProfile);
IPlayerFileData saveHandler = minecraftServer.worlds[0].getSaveHandler().getPlayerNBTManager();
NBTTagCompound playerData = saveHandler.readPlayerData(fakePlayer);
//noinspection ConstantConditions
if (playerData == null) {
sender.sendMessage(new TextComponentString("Player not found on server"));
return;
}
fakePlayer.posX = x;
fakePlayer.posY = y;
fakePlayer.posZ = z;
fakePlayer.dimension = 0;
saveHandler.writePlayerData(fakePlayer);
}
sender.sendMessage(new TextComponentString("Player sent to spawn"));
}
}

View File

@ -15,8 +15,6 @@
package chikachi.discord.core;
import chikachi.discord.core.config.Configuration;
import chikachi.discord.core.config.discord.DiscordChannelConfig;
import chikachi.discord.core.config.discord.DiscordConfig;
import chikachi.discord.core.config.minecraft.MinecraftConfig;
import chikachi.discord.core.config.types.MessageConfig;
import net.dv8tion.jda.core.AccountType;
@ -25,10 +23,11 @@ import net.dv8tion.jda.core.JDABuilder;
import net.dv8tion.jda.core.entities.SelfUser;
import net.dv8tion.jda.core.entities.TextChannel;
import net.dv8tion.jda.core.events.ReadyEvent;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
import net.dv8tion.jda.core.hooks.ListenerAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DiscordClient extends ListenerAdapter {
private static DiscordClient instance;
@ -68,15 +67,23 @@ public class DiscordClient extends ListenerAdapter {
}
public void connect() {
connect(false);
}
public void connect(boolean noMessage) {
if (this.jda != null) {
CoreLogger.Log("Is already connected", true);
if (noMessage) {
CoreLogger.Log("Is already connected", true);
}
return;
}
String token = Configuration.getConfig().discord.token;
if (token == null || token.isEmpty()) {
CoreLogger.Log("Missing token", true);
if (noMessage) {
CoreLogger.Log("Missing token", true);
}
return;
}
@ -121,7 +128,7 @@ public class DiscordClient extends ListenerAdapter {
disconnect(false);
}
void disconnect(boolean noMessage) {
public void disconnect(boolean noMessage) {
if (this.jda == null) {
if (!noMessage) {
CoreLogger.Log("Is already disconnected", true);
@ -144,13 +151,21 @@ public class DiscordClient extends ListenerAdapter {
return this.jda.getSelfUser();
}
public void broadcast(MessageConfig message, ArrayList<Long> channels) {
public void broadcast(MessageConfig message, Long... channels) {
broadcast(message, Arrays.asList(channels));
}
public void broadcast(MessageConfig message, List<Long> channels) {
if (channels == null || channels.size() == 0) return;
broadcast(new Message(message), channels);
}
public void broadcast(Message message, ArrayList<Long> channels) {
public void broadcast(Message message, Long... channels) {
broadcast(message, Arrays.asList(channels));
}
public void broadcast(Message message, List<Long> channels) {
if (channels == null || channels.size() == 0) return;
for (Long channelId : channels) {

View File

@ -132,7 +132,7 @@ public class Message {
}
}
return message;
return Patterns.minecraftToDiscord(message);
}
public String getUnformattedText() {

View File

@ -14,22 +14,109 @@
package chikachi.discord.core;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Patterns {
public static final Pattern everyonePattern = Pattern.compile("(^|\\W)@everyone\\b");
public static final Pattern herePattern = Pattern.compile("(^|\\W)@here\\b");
public static final Pattern mcFormattingPattern = Pattern.compile("§.(^|\\s)(^|.)");
public static final Pattern customFormattingPattern = Pattern.compile("&([0-9a-fA-F])");
public static final Pattern boldPattern = Pattern.compile("\\*\\*(.*)\\*\\*");
public static final Pattern underlinePattern = Pattern.compile("__(.*)__");
public static final Pattern italicPattern = Pattern.compile("\\*(.*)\\*");
public static final Pattern italicMePattern = Pattern.compile("_(.*)_");
public static final Pattern lineThroughPattern = Pattern.compile("~~(.*)~~");
public static final Pattern strikeThroughPattern = Pattern.compile("~~(.*)~~");
public static final Pattern singleCodePattern = Pattern.compile("`(.*)`");
public static final Pattern multiCodePattern = Pattern.compile("```(.*)```");
public static final Pattern tagPattern = Pattern.compile("@([^\\s]+)");
private static final HashMap<Pattern, String> discordToMinecraftPatterns = new HashMap<>();
private static final HashMap<Pattern, String> minecraftToDiscordPatterns = new HashMap<>();
private static final HashMap<Pattern, ReplacementCallback> minecraftFormattingPatterns = new HashMap<>();
private static final HashMap<Pattern, ReplacementCallback> discordFormattingPatterns = new HashMap<>();
public interface ReplacementCallback {
String pre(String text);
String replace(ArrayList<String> groups);
String post(String text);
}
public static void addDiscordToMinecraftPattern(Pattern pattern, String replacement) {
discordToMinecraftPatterns.put(pattern, replacement);
}
public static void addMinecraftToDiscordPattern(Pattern pattern, String replacement) {
minecraftToDiscordPatterns.put(pattern, replacement);
}
public static void addMinecraftFormattingPattern(Pattern pattern, ReplacementCallback replacement) {
minecraftFormattingPatterns.put(pattern, replacement);
}
public static void addDiscordFormattingPattern(Pattern pattern, ReplacementCallback replacement) {
discordFormattingPatterns.put(pattern, replacement);
}
public static String discordToMinecraft(String content) {
if (content == null) {
return "";
}
for (Map.Entry<Pattern, String> entry : discordToMinecraftPatterns.entrySet()) {
content = entry.getKey().matcher(content).replaceAll(entry.getValue());
}
for (Map.Entry<Pattern, ReplacementCallback> entry : minecraftFormattingPatterns.entrySet()) {
content = executeReplacement(content, entry);
}
return content;
}
public static String minecraftToDiscord(String content) {
if (content == null) {
return "";
}
for (Map.Entry<Pattern, String> entry : minecraftToDiscordPatterns.entrySet()) {
content = entry.getKey().matcher(content).replaceAll(entry.getValue());
}
for (Map.Entry<Pattern, ReplacementCallback> entry : discordFormattingPatterns.entrySet()) {
content = executeReplacement(content, entry);
}
return content;
}
@NotNull
private static String executeReplacement(String content, Map.Entry<Pattern, ReplacementCallback> entry) {
ReplacementCallback replacer = entry.getValue();
content = replacer.pre(content);
Matcher matcher = entry.getKey().matcher(content);
if (matcher.find()) {
StringBuffer sb = new StringBuffer();
do {
ArrayList<String> groups = new ArrayList<>();
for (int i = 0, j = matcher.groupCount(); i < j; i++) {
groups.add(matcher.group(i));
}
matcher.appendReplacement(sb, replacer.replace(groups));
} while (matcher.find());
matcher.appendTail(sb);
content = replacer.post(sb.toString());
}
return content;
}
}

View File

@ -50,7 +50,7 @@ public class WebhookMessage {
if (this.avatar_url != null) {
json.put("avatar_url", this.avatar_url);
}
json.put("content", this.content);
json.put("content", Patterns.minecraftToDiscord(this.content));
new RestAction<Void>(jda, route, json) {
protected void handleResponse(Response response, Request<Void> request) {

View File

@ -23,7 +23,7 @@ public class DiscordChannelGenericConfig {
@Since(3.0)
public String commandPrefix;
@Since(3.0)
public boolean canExecuteCommands = false;
public Boolean canExecuteCommands;
@Since(3.0)
public DimensionConfigType relayChat;
@Since(3.0)
@ -36,6 +36,10 @@ public class DiscordChannelGenericConfig {
if (this.commandPrefix == null) {
this.commandPrefix = "!";
}
if (this.canExecuteCommands == null) {
this.canExecuteCommands = false;
}
}
if (this.relayChat == null) {

View File

@ -15,13 +15,13 @@
package chikachi.discord.listener;
import chikachi.discord.DiscordCommandSender;
import chikachi.discord.DiscordIntegration;
import chikachi.discord.IMCHandler;
import chikachi.discord.core.DiscordClient;
import chikachi.discord.core.Message;
import chikachi.discord.core.config.discord.CommandConfig;
import chikachi.discord.core.Patterns;
import chikachi.discord.core.config.ConfigWrapper;
import chikachi.discord.core.config.Configuration;
import chikachi.discord.core.config.discord.CommandConfig;
import chikachi.discord.core.config.discord.DiscordChannelGenericConfig;
import chikachi.discord.core.config.discord.DiscordConfig;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
@ -31,7 +31,6 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.event.FMLInterModComms;
import java.util.ArrayList;
import java.util.Arrays;
@ -78,8 +77,7 @@ public class DiscordListener extends ListenerAdapter {
String content = event.getMessage().getContent().trim();
List<String> listenerMods = IMCHandler.getRegisteredIMCMods();
if (listenerMods.size() > 0) {
if (IMCHandler.haveListeners()) {
NBTTagCompound eventTagCompound = new NBTTagCompound();
eventTagCompound.setString("type", "chat");
@ -90,9 +88,7 @@ public class DiscordListener extends ListenerAdapter {
eventTagCompound.setTag("user", userTagComponent);
eventTagCompound.setString("message", content);
for (String listenerMod : listenerMods) {
FMLInterModComms.sendRuntimeMessage(DiscordIntegration.instance, listenerMod, "event", eventTagCompound);
}
IMCHandler.emitMessage("event", eventTagCompound);
}
String prefix = channelConfig.commandPrefix != null ? channelConfig.commandPrefix : discordConfig.channels.generic.commandPrefix;
@ -127,9 +123,18 @@ public class DiscordListener extends ListenerAdapter {
}
HashMap<String, String> arguments = new HashMap<>();
arguments.put("MESSAGE", event.getMessage().getContent());
arguments.put(
"MESSAGE",
Patterns.discordToMinecraft(
event.getMessage().getContent()
)
);
Message message = new Message(event.getAuthor().getName(), config.discord.channels.generic.messages.chatMessage, arguments);
Message message = new Message(
event.getAuthor().getName(),
config.discord.channels.generic.messages.chatMessage,
arguments
);
for (EntityPlayerMP player : players) {
player.sendMessage(new TextComponentString(message.getFormattedText()));
}

View File

@ -14,6 +14,7 @@
package chikachi.discord.listener;
import chikachi.discord.IMCHandler;
import chikachi.discord.core.DiscordClient;
import chikachi.discord.core.Message;
import chikachi.discord.core.config.Configuration;
@ -26,6 +27,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.stats.Achievement;
import net.minecraft.stats.StatisticsManagerServer;
import net.minecraft.util.text.translation.I18n;