Merge branch 'dev' (#54)

# Conflicts:
#	pom.xml
This commit is contained in:
Norbi Peti 2018-06-15 18:49:21 +02:00
commit b3259239e5
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
44 changed files with 820 additions and 501 deletions

2
.gitignore vendored Normal file → Executable file
View file

@ -131,7 +131,7 @@ publish/
*.publishproj *.publishproj
# NuGet Packages Directory # NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line ## TO!DO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/ #packages/
# Windows Azure Build Output # Windows Azure Build Output

0
.travis.yml Normal file → Executable file
View file

0
License.md Normal file → Executable file
View file

0
README.md Normal file → Executable file
View file

2
deploy.sh Normal file → Executable file
View file

@ -6,5 +6,5 @@ if [ $1 = 'production' ]; then
echo Production mode echo Production mode
echo $UPLOAD_KEY > upload_key echo $UPLOAD_KEY > upload_key
chmod 400 upload_key chmod 400 upload_key
yes | scp -B -i upload_key -o StrictHostKeyChecking=no $FILENAME travis@server.figytuna.com:/minecraft/main/plugins yes | scp -B -i upload_key -o StrictHostKeyChecking=no $FILENAME travis@server.figytuna.com:/minecraft/main/pluginupdates
fi fi

17
pom.xml Normal file → Executable file
View file

@ -58,7 +58,7 @@
<exclude>org.spigotmc:spigot-api</exclude> <exclude>org.spigotmc:spigot-api</exclude>
<exclude>com.github.TBMCPlugins.ButtonCore:ButtonCore</exclude> <exclude>com.github.TBMCPlugins.ButtonCore:ButtonCore</exclude>
<exclude>net.ess3:Essentials</exclude> <exclude>net.ess3:Essentials</exclude>
</excludes> <!-- TODO: http://stackoverflow.com/questions/28458058/maven-shade-plugin-exclude-a-dependency-and-all-its-transitive-dependencies --> </excludes> <!-- http://stackoverflow.com/questions/28458058/maven-shade-plugin-exclude-a-dependency-and-all-its-transitive-dependencies -->
</artifactSet> </artifactSet>
</configuration> </configuration>
</execution> </execution>
@ -151,11 +151,11 @@
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.discord4j/Discord4J --> <!-- https://mvnrepository.com/artifact/com.discord4j/Discord4J -->
<dependency> <dependency>
<groupId>com.discord4j</groupId> <groupId>com.discord4j</groupId>
<artifactId>Discord4J</artifactId> <artifactId>Discord4J</artifactId>
<version>2.10.1</version> <version>2.10.1</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 --> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
<dependency> <dependency>
@ -179,6 +179,7 @@
<groupId>net.ess3</groupId> <groupId>net.ess3</groupId>
<artifactId>Essentials</artifactId> <artifactId>Essentials</artifactId>
<version>2.13.1</version> <version>2.13.1</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.xaanit</groupId> <groupId>com.github.xaanit</groupId>
@ -211,6 +212,10 @@
<version>2.6</version> <version>2.6</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -1,19 +1,18 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.awt.Color;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.discordplugin.listeners.MCChatListener;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import sx.blah.discord.api.internal.json.objects.EmbedObject; import sx.blah.discord.api.internal.json.objects.EmbedObject;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.EmbedBuilder;
import java.awt.*;
import java.util.Arrays;
import java.util.stream.Collectors;
public class ChromaBot { public class ChromaBot {
/** /**
* May be null if it's not initialized. Initialization happens after the server is done loading (using {@link BukkitScheduler#runTaskAsynchronously(org.bukkit.plugin.Plugin, Runnable)}) * May be null if it's not initialized. Initialization happens after the server is done loading (using {@link BukkitScheduler#runTaskAsynchronously(org.bukkit.plugin.Plugin, Runnable)})
@ -47,7 +46,7 @@ public class ChromaBot {
} }
/** /**
* Send a message to the chat channel and private chats. * Send a message to the chat channels and private chats.
* *
* @param message * @param message
* The message to send, duh * The message to send, duh
@ -73,7 +72,7 @@ public class ChromaBot {
} }
/** /**
* Send a fancy message to the chat channel. This will show a bold text with a colored line. * Send a fancy message to the chat channels. This will show a bold text with a colored line.
* *
* @param message * @param message
* The message to send, duh * The message to send, duh
@ -86,7 +85,7 @@ public class ChromaBot {
} }
/** /**
* Send a fancy message to the chat channel. This will show a bold text with a colored line. * Send a fancy message to the chat channels. This will show a bold text with a colored line.
* *
* @param message * @param message
* The message to send, duh * The message to send, duh
@ -101,7 +100,7 @@ public class ChromaBot {
} }
/** /**
* Send a fancy message to the chat channel. This will show a bold text with a colored line. * Send a fancy message to the chat channels. This will show a bold text with a colored line.
* *
* @param message * @param message
* The message to send, duh * The message to send, duh
@ -118,7 +117,7 @@ public class ChromaBot {
} }
/** /**
* Send a message to the chat channel. This will show a bold text with a colored line. * Send a message to the chat channels. This will show a bold text with a colored line.
* *
* @param message * @param message
* The message to send, duh * The message to send, duh

39
src/main/java/buttondevteam/discordplugin/DPUtils.java Normal file → Executable file
View file

@ -1,10 +1,15 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import buttondevteam.lib.TBMCCoreAPI;
import org.bukkit.Bukkit;
import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.EmbedBuilder;
import sx.blah.discord.util.RequestBuffer; import sx.blah.discord.util.RequestBuffer;
import sx.blah.discord.util.RequestBuffer.IRequest; import sx.blah.discord.util.RequestBuffer.IRequest;
import sx.blah.discord.util.RequestBuffer.IVoidRequest; import sx.blah.discord.util.RequestBuffer.IVoidRequest;
import javax.annotation.Nullable;
import java.util.concurrent.TimeUnit;
public final class DPUtils { public final class DPUtils {
public static EmbedBuilder embedWithHead(EmbedBuilder builder, String playername) { public static EmbedBuilder embedWithHead(EmbedBuilder builder, String playername) {
@ -33,13 +38,33 @@ public final class DPUtils {
/** /**
* Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode. * Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode.
*/ */
public static <T> T perform(IRequest<T> action) { @Nullable
if (DiscordPlugin.SafeMode) public static <T> T perform(IRequest<T> action, long timeout, TimeUnit unit) {
return null; if (DiscordPlugin.SafeMode)
// if (Thread.currentThread() == DiscordPlugin.mainThread) - TODO: Ignore shutdown message <-- return null;
// throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag."); if (Thread.currentThread() == DiscordPlugin.mainThread) // TODO: Ignore shutdown message <--
return RequestBuffer.request(action).get(); // Let the pros handle this // throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag.");
} Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!");
try {
return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this
} catch (Exception e) {
TBMCCoreAPI.SendException("Couldn't perform Discord action!", e);
return null;
}
}
/**
* Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode.
*/
@Nullable
public static <T> T perform(IRequest<T> action) {
if (DiscordPlugin.SafeMode)
return null;
if (Thread.currentThread() == DiscordPlugin.mainThread) // TODO: Ignore shutdown message <--
// throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag.");
Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!");
return RequestBuffer.request(action).get(); // Let the pros handle this
}
/** /**
* Performs Discord actions, retrying when ratelimited. * Performs Discord actions, retrying when ratelimited.

View file

@ -1,13 +1,13 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.util.UUID;
import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer; import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer;
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import lombok.Getter; import lombok.Getter;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.UUID;
public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer<DiscordConnectedPlayer> { public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer<DiscordConnectedPlayer> {
private static int nextEntityId = 10000; private static int nextEntityId = 10000;
private @Getter VanillaCommandListener<DiscordConnectedPlayer> vanillaCmdListener; private @Getter VanillaCommandListener<DiscordConnectedPlayer> vanillaCmdListener;

View file

View file

@ -1,13 +1,7 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.net.InetSocketAddress; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import java.util.Collection; import lombok.Getter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.advancement.Advancement; import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress; import org.bukkit.advancement.AdvancementProgress;
@ -24,18 +18,20 @@ import org.bukkit.inventory.*;
import org.bukkit.inventory.InventoryView.Property; import org.bukkit.inventory.InventoryView.Property;
import org.bukkit.map.MapView; import org.bukkit.map.MapView;
import org.bukkit.metadata.MetadataValue; import org.bukkit.metadata.MetadataValue;
import org.bukkit.permissions.*; import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import lombok.Getter;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.net.InetSocketAddress;
import java.util.*;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer<DiscordPlayerSender> { public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer<DiscordPlayerSender> {

View file

@ -1,8 +1,10 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import buttondevteam.discordplugin.commands.DiscordCommandBase;
import buttondevteam.discordplugin.listeners.*; import buttondevteam.discordplugin.listeners.*;
import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Channel;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import com.google.common.io.Files; import com.google.common.io.Files;
@ -30,8 +32,9 @@ import sx.blah.discord.util.RequestBuffer;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> { public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
@ -60,7 +63,6 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
plugin = this; plugin = this;
lastannouncementtime = getConfig().getLong("lastannouncementtime"); lastannouncementtime = getConfig().getLong("lastannouncementtime");
lastseentime = getConfig().getLong("lastseentime"); lastseentime = getConfig().getLong("lastseentime");
GameRoles = (List<String>) getConfig().getList("gameroles", new ArrayList<String>());
ClientBuilder cb = new ClientBuilder(); ClientBuilder cb = new ClientBuilder();
cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8));
dc = cb.login(); dc = cb.login();
@ -77,6 +79,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
public static IChannel genchannel; public static IChannel genchannel;
public static IChannel chatchannel; public static IChannel chatchannel;
public static IChannel botroomchannel; public static IChannel botroomchannel;
public static IChannel modlogchannel;
/** /**
* Don't send messages, just receive, the same channel is used when testing * Don't send messages, just receive, the same channel is used when testing
*/ */
@ -109,6 +112,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
officechannel = devServer.getChannelByID(219626707458457603L); // developers-office officechannel = devServer.getChannelByID(219626707458457603L); // developers-office
updatechannel = devServer.getChannelByID(233724163519414272L); // server-updates updatechannel = devServer.getChannelByID(233724163519414272L); // server-updates
devofficechannel = officechannel; // developers-office devofficechannel = officechannel; // developers-office
modlogchannel = mainServer.getChannelByID(283840717275791360L); // modlog
dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft"); dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft");
} else { } else {
botchannel = devServer.getChannelByID(239519012529111040L); // bot-room botchannel = devServer.getChannelByID(239519012529111040L); // bot-room
@ -119,6 +123,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
officechannel = devServer.getChannelByID(219626707458457603L); // developers-office officechannel = devServer.getChannelByID(219626707458457603L); // developers-office
updatechannel = botchannel; updatechannel = botchannel;
devofficechannel = botchannel;// bot-room devofficechannel = botchannel;// bot-room
modlogchannel = botchannel; // bot-room
dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing");
} }
if (botchannel == null || annchannel == null || genchannel == null || botroomchannel == null if (botchannel == null || annchannel == null || genchannel == null || botroomchannel == null
@ -129,6 +134,27 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
task.cancel(); task.cancel();
if (!sent) { if (!sent) {
new ChromaBot(this).updatePlayerList(); new ChromaBot(this).updatePlayerList();
GameRoles = mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList());
val chcons = getConfig().getConfigurationSection("chcons");
if (chcons != null) {
val chconkeys = chcons.getKeys(false);
for (val chconkey : chconkeys) {
val chcon = chcons.getConfigurationSection(chconkey);
val mcch = Channel.getChannels().stream().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny();
val ch = dc.getChannelByID(chcon.getLong("chid"));
val did = chcon.getLong("did");
val dp = DiscordPlayer.getUser(Long.toString(did), DiscordPlayer.class);
val user = dc.fetchUser(did);
val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"));
val groupid = chcon.getString("groupid");
if (!mcch.isPresent() || ch == null || user == null || groupid == null)
continue;
MCChatListener.addCustomChat(ch, groupid, mcch.get(), dp, user, dcp);
}
}
DiscordCommandBase.registerCommands();
if (getConfig().getBoolean("serverup", false)) { if (getConfig().getBoolean("serverup", false)) {
ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.YELLOW) ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.YELLOW)
.withTitle("Server recovered from a crash - chat connected.").build()); .withTitle("Server recovered from a crash - chat connected.").build());
@ -199,6 +225,14 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
} }
} }
public boolean isGameRole(IRole r) {
if (r.getGuild().getLongID() != mainServer.getLongID())
return false; //Only allow on the main server
val rc = new Color(149, 165, 166, 0);
return r.getColor().equals(rc)
&& r.getPosition() < mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role
}
/** /**
* Always true, except when running "stop" from console * Always true, except when running "stop" from console
*/ */
@ -211,8 +245,20 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
MCListener.callEventExcludingSome(new PlayerQuitEvent(entry.getValue(), "")); MCListener.callEventExcludingSome(new PlayerQuitEvent(entry.getValue(), ""));
getConfig().set("lastannouncementtime", lastannouncementtime); getConfig().set("lastannouncementtime", lastannouncementtime);
getConfig().set("lastseentime", lastseentime); getConfig().set("lastseentime", lastseentime);
getConfig().set("gameroles", GameRoles);
getConfig().set("serverup", false); getConfig().set("serverup", false);
val chcons = MCChatListener.getCustomChats();
val chconsc = getConfig().createSection("chcons");
for (val chcon : chcons) {
val chconc = chconsc.createSection(chcon.channel.getStringID());
chconc.set("mcchid", chcon.mcchannel.ID);
chconc.set("chid", chcon.channel.getLongID());
chconc.set("did", chcon.user.getLongID());
chconc.set("mcuid", chcon.dcp.getUniqueId().toString());
chconc.set("mcname", chcon.dcp.getName());
chconc.set("groupid", chcon.groupID);
}
saveConfig(); saveConfig();
MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannelWait(ch, "", MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannelWait(ch, "",
new EmbedBuilder().withColor(Restart ? Color.ORANGE : Color.RED) new EmbedBuilder().withColor(Restart ? Color.ORANGE : Color.RED)
@ -225,10 +271,11 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
+ (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ")
+ "asked *politely* to leave the server for a bit.") + "asked *politely* to leave the server for a bit.")
: "") : "")
.build())); .build(), 5, TimeUnit.SECONDS));
ChromaBot.getInstance().updatePlayerList(); ChromaBot.getInstance().updatePlayerList();
try { try {
SafeMode = true; // Stop interacting with Discord SafeMode = true; // Stop interacting with Discord
MCChatListener.stop();
ChromaBot.delete(); ChromaBot.delete();
dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing
dc.logout(); dc.logout();
@ -323,7 +370,15 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
return sendMessageToChannel(channel, message, embed, true); return sendMessageToChannel(channel, message, embed, true);
} }
public static IMessage sendMessageToChannelWait(IChannel channel, String message, EmbedObject embed, long timeout, TimeUnit unit) {
return sendMessageToChannel(channel, message, embed, true, timeout, unit);
}
private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait) { private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait) {
return sendMessageToChannel(channel, message, embed, wait, -1, null);
}
private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait, long timeout, TimeUnit unit) {
if (message.length() > 1980) { if (message.length() > 1980) {
message = message.substring(0, 1980); message = message.substring(0, 1980);
Bukkit.getLogger() Bukkit.getLogger()
@ -337,10 +392,16 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
final String content = message; final String content = message;
RequestBuffer.IRequest<IMessage> r = () -> embed == null ? channel.sendMessage(content) RequestBuffer.IRequest<IMessage> r = () -> embed == null ? channel.sendMessage(content)
: channel.sendMessage(content, embed, false); : channel.sendMessage(content, embed, false);
if (wait) if (wait) {
return DPUtils.perform(r); if (unit != null)
else { return DPUtils.perform(r, timeout, unit);
DPUtils.performNoWait(r); else
return DPUtils.perform(r);
} else {
if (unit != null)
plugin.getLogger().warning("Tried to set timeout for non-waiting call.");
else
DPUtils.performNoWait(r);
return null; return null;
} }
} catch (Exception e) { } catch (Exception e) {

View file

View file

@ -1,15 +1,18 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.util.Set;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.permissions.*; import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.Set;
public class DiscordSender extends DiscordSenderBase implements CommandSender { public class DiscordSender extends DiscordSenderBase implements CommandSender {
private PermissibleBase perm = new PermissibleBase(this); private PermissibleBase perm = new PermissibleBase(this);

View file

@ -1,20 +1,19 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.Channel;
import buttondevteam.lib.chat.IDiscordSender; import buttondevteam.lib.chat.IDiscordSender;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.Arrays;
import java.util.stream.Collectors;
public abstract class DiscordSenderBase implements IDiscordSender { public abstract class DiscordSenderBase implements IDiscordSender {
/** /**
* May be null. * May be null.

View file

View file

@ -1,8 +1,7 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import org.bukkit.entity.Player;
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import org.bukkit.entity.Player;
public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player { public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player {
VanillaCommandListener<T> getVanillaCmdListener(); VanillaCommandListener<T> getVanillaCmdListener();

View file

@ -1,10 +1,10 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import java.lang.reflect.Field; import buttondevteam.discordplugin.listeners.MCChatListener;
import java.lang.reflect.Modifier; import buttondevteam.lib.TBMCCoreAPI;
import java.util.List; import com.mojang.authlib.GameProfile;
import java.util.UUID; import lombok.val;
import net.minecraft.server.v1_12_R1.*;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
@ -12,33 +12,10 @@ import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.objenesis.ObjenesisStd; import org.objenesis.ObjenesisStd;
import com.mojang.authlib.GameProfile; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import buttondevteam.discordplugin.listeners.MCChatListener; import java.util.List;
import buttondevteam.lib.TBMCCoreAPI; import java.util.UUID;
import lombok.val;
import net.minecraft.server.v1_12_R1.AdvancementDataPlayer;
import net.minecraft.server.v1_12_R1.ChatMessageType;
import net.minecraft.server.v1_12_R1.DedicatedPlayerList;
import net.minecraft.server.v1_12_R1.DedicatedServer;
import net.minecraft.server.v1_12_R1.Entity;
import net.minecraft.server.v1_12_R1.EntityHuman;
import net.minecraft.server.v1_12_R1.EntityPlayer;
import net.minecraft.server.v1_12_R1.GameProfileBanList;
import net.minecraft.server.v1_12_R1.IChatBaseComponent;
import net.minecraft.server.v1_12_R1.IpBanList;
import net.minecraft.server.v1_12_R1.LoginListener;
import net.minecraft.server.v1_12_R1.MinecraftServer;
import net.minecraft.server.v1_12_R1.NBTTagCompound;
import net.minecraft.server.v1_12_R1.NetworkManager;
import net.minecraft.server.v1_12_R1.OpList;
import net.minecraft.server.v1_12_R1.Packet;
import net.minecraft.server.v1_12_R1.PacketPlayOutChat;
import net.minecraft.server.v1_12_R1.ScoreboardServer;
import net.minecraft.server.v1_12_R1.ServerStatisticManager;
import net.minecraft.server.v1_12_R1.WhiteList;
import net.minecraft.server.v1_12_R1.World;
import net.minecraft.server.v1_12_R1.WorldServer;
public class PlayerListWatcher extends DedicatedPlayerList { public class PlayerListWatcher extends DedicatedPlayerList {
private DedicatedPlayerList plist; private DedicatedPlayerList plist;

View file

@ -0,0 +1,83 @@
package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DiscordConnectedPlayer;
import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.listeners.MCChatListener;
import buttondevteam.lib.TBMCChannelConnectFakeEvent;
import buttondevteam.lib.chat.Channel;
import buttondevteam.lib.player.TBMCPlayer;
import lombok.val;
import org.bukkit.Bukkit;
import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.Permissions;
import sx.blah.discord.util.PermissionUtils;
import java.util.Arrays;
public class ChannelconCommand extends DiscordCommandBase {
@Override
public String getCommandName() {
return "channelcon";
}
@Override
public boolean run(IMessage message, String args) {
if (args.length() == 0)
return false;
if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) {
message.reply("you need to have manage permissions for this channel!");
return true;
}
if (MCChatListener.hasCustomChat(message.getChannel())) {
if (args.equalsIgnoreCase("remove")) {
if (MCChatListener.removeCustomChat(message.getChannel()))
message.reply("channel connection removed.");
else
message.reply("wait what, couldn't remove channel connection.");
return true;
}
message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.");
return true;
}
val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args) || (ch.IDs != null && Arrays.stream(ch.IDs).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny();
if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /.");
return true;
}
val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class);
val chp = dp.getAs(TBMCPlayer.class);
if (chp == null) {
message.reply("you need to connect your Minecraft account. On our server in #bot do /connect <MCname>");
return true;
}
DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName());
val ev = new TBMCChannelConnectFakeEvent(dcp, chan.get());
//Using a fake player with no login/logout, should be fine for this event
String groupid = ev.getGroupID(ev.getSender()); //We're not trying to send in a specific group, we want to know which group the user belongs to (so not getGroupID())
if (groupid == null) {
message.reply("sorry, that didn't work. You cannot use that Minecraft channel.");
return true;
}
if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) {
message.reply("sorry, this MC chat is already connected to a different channel, multiple channels are not supported atm.");
return true;
}
MCChatListener.addCustomChat(message.getChannel(), groupid, ev.getChannel(), dp, message.getAuthor(), dcp);
message.reply("alright, connection made to group `" + groupid + "`!");
return true;
}
@Override
public String[] getHelpText() {
return new String[]{ //
"---- Channel connect ---", //
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
"You also need to have your Minecraft account connected. In #bot use /connect <mcname>.", //
"Call this command from the channel you want to use. Usage: @ChromaBot channelcon <mcchannel>", //
"To remove a connection use @ChromaBot channelcon remove in the channel.", //
"Mentioning the bot is needed in this case because the / prefix only works in #bot.", //
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot&permissions=268509264>" //
};
}
}

View file

@ -1,16 +1,14 @@
package buttondevteam.discordplugin.commands; package buttondevteam.discordplugin.commands;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import com.google.common.collect.HashBiMap;
import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.common.collect.HashBiMap;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
public class ConnectCommand extends DiscordCommandBase { public class ConnectCommand extends DiscordCommandBase {
@ -27,15 +25,13 @@ public class ConnectCommand extends DiscordCommandBase {
public static HashBiMap<String, String> WaitingToConnect = HashBiMap.create(); public static HashBiMap<String, String> WaitingToConnect = HashBiMap.create();
@Override @Override
public void run(IMessage message, String args) { public boolean run(IMessage message, String args) {
if (args.length() == 0) { if (args.length() == 0)
DiscordPlugin.sendMessageToChannel(message.getChannel(), "Usage: connect <Minecraftname>"); return true;
return;
}
if (args.contains(" ")) { if (args.contains(" ")) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Too many arguments.\nUsage: connect <Minecraftname>"); "Too many arguments.\nUsage: connect <Minecraftname>");
return; return true;
} }
if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
@ -46,13 +42,13 @@ public class ConnectCommand extends DiscordCommandBase {
OfflinePlayer p = Bukkit.getOfflinePlayer(args); OfflinePlayer p = Bukkit.getOfflinePlayer(args);
if (p == null) { if (p == null) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found"); DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found");
return; return true;
} }
try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) {
DiscordPlayer dp = pl.getAs(DiscordPlayer.class); DiscordPlayer dp = pl.getAs(DiscordPlayer.class);
if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) { if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected.");
return; return true;
} }
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e); TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e);
@ -60,11 +56,12 @@ public class ConnectCommand extends DiscordCommandBase {
} }
WaitingToConnect.put(p.getName(), message.getAuthor().getStringID()); WaitingToConnect.put(p.getName(), message.getAuthor().getStringID());
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Pending connection - accept connection in Minecraft from the account " + args "Alright! Now accept the connection in Minecraft from the account " + args
+ " before the server gets restarted. You can also adjust the Minecraft name you want to connect to with the same command."); + " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command.");
if (p.isOnline()) if (p.isOnline())
((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#" ((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#"
+ message.getAuthor().getDiscriminator() + " do /discord accept"); + message.getAuthor().getDiscriminator() + " do /discord accept");
return true;
} }
@Override @Override

View file

@ -0,0 +1,26 @@
package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.listeners.CommandListener;
import sx.blah.discord.handle.obj.IMessage;
public class DebugCommand extends DiscordCommandBase {
@Override
public String getCommandName() {
return "debug";
}
@Override
public boolean run(IMessage message, String args) {
if (message.getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L)))
message.reply("Debug " + (CommandListener.debug() ? "enabled" : "disabled"));
else
message.reply("You need to be a moderator to use this command.");
return true;
}
@Override
public String[] getHelpText() {
return new String[]{"Switches debug mode."};
}
}

View file

@ -1,29 +1,36 @@
package buttondevteam.discordplugin.commands; package buttondevteam.discordplugin.commands;
import java.util.HashMap;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
import java.util.Arrays;
import java.util.HashMap;
import java.util.stream.Collectors;
import static buttondevteam.discordplugin.listeners.CommandListener.debug;
public abstract class DiscordCommandBase { public abstract class DiscordCommandBase {
public abstract String getCommandName(); public abstract String getCommandName();
public abstract void run(IMessage message, String args); public abstract boolean run(IMessage message, String args);
public abstract String[] getHelpText(); public abstract String[] getHelpText();
static final HashMap<String, DiscordCommandBase> commands = new HashMap<String, DiscordCommandBase>(); static final HashMap<String, DiscordCommandBase> commands = new HashMap<String, DiscordCommandBase>();
static { public static void registerCommands() {
commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? commands.put("connect", new ConnectCommand()); // TODO: API for adding commands?
commands.put("userinfo", new UserinfoCommand()); commands.put("userinfo", new UserinfoCommand());
commands.put("help", new HelpCommand()); commands.put("help", new HelpCommand());
commands.put("role", new RoleCommand()); commands.put("role", new RoleCommand());
commands.put("mcchat", new MCChatCommand()); commands.put("mcchat", new MCChatCommand());
commands.put("channelcon", new ChannelconCommand());
commands.put("debug", new DebugCommand());
} }
public static void runCommand(String cmd, String args, IMessage message) { public static void runCommand(String cmd, String args, IMessage message) {
debug("F"); //Not sure if needed
DiscordCommandBase command = commands.get(cmd); DiscordCommandBase command = commands.get(cmd);
if (command == null) { if (command == null) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
@ -32,12 +39,19 @@ public abstract class DiscordCommandBase {
+ "help' for help"); + "help' for help");
return; return;
} }
debug("G");
try { try {
command.run(message, args); if (!command.run(message, args))
DiscordPlugin.sendMessageToChannel(message.getChannel(), Arrays.stream(command.getHelpText()).collect(Collectors.joining("\n")));
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while executing command " + cmd + "!", e); TBMCCoreAPI.SendException("An error occured while executing command " + cmd + "!", e);
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"An internal error occured while executing this command. For more technical details see the server-issues channel on the dev Discord."); "An internal error occured while executing this command. For more technical details see the server-issues channel on the dev Discord.");
} }
debug("H");
}
protected String[] splitargs(String args) {
return args.split("\\s+");
} }
} }

View file

@ -1,11 +1,11 @@
package buttondevteam.discordplugin.commands; package buttondevteam.discordplugin.commands;
import java.util.Arrays;
import java.util.stream.Collectors;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
import java.util.Arrays;
import java.util.stream.Collectors;
public class HelpCommand extends DiscordCommandBase { public class HelpCommand extends DiscordCommandBase {
@Override @Override
@ -14,7 +14,7 @@ public class HelpCommand extends DiscordCommandBase {
} }
@Override @Override
public void run(IMessage message, String args) { public boolean run(IMessage message, String args) {
DiscordCommandBase argdc; DiscordCommandBase argdc;
if (args.length() == 0) if (args.length() == 0)
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
@ -24,6 +24,7 @@ public class HelpCommand extends DiscordCommandBase {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
(argdc = DiscordCommandBase.commands.get(args)) == null ? "Command not found: " + args (argdc = DiscordCommandBase.commands.get(args)) == null ? "Command not found: " + args
: Arrays.stream(argdc.getHelpText()).collect(Collectors.joining("\n"))); : Arrays.stream(argdc.getHelpText()).collect(Collectors.joining("\n")));
return true;
} }
@Override @Override

View file

@ -14,23 +14,23 @@ public class MCChatCommand extends DiscordCommandBase {
} }
@Override @Override
public void run(IMessage message, String args) { public boolean run(IMessage message, String args) {
if (!message.getChannel().isPrivate()) { if (!message.getChannel().isPrivate()) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"This command can only be issued in a direct message with the bot."); "This command can only be issued in a direct message with the bot.");
return; return true;
} }
try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) { try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) {
boolean mcchat = !user.isMinecraftChatEnabled(); boolean mcchat = !user.isMinecraftChatEnabled();
MCChatListener.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); MCChatListener.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user);
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Minecraft chat " + (mcchat // "Minecraft chat " + (mcchat //
? "enabled. Use '" + message.getClient().getOurUser().mention() ? "enabled. Use '/mcchat' again to turn it off." //
+ " mcchat' (with the mention) to disable." //
: "disabled.")); : "disabled."));
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e); TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e);
} }
return true;
} }
@Override @Override

View file

@ -6,115 +6,88 @@ import buttondevteam.lib.TBMCCoreAPI;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.IRole;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class RoleCommand extends DiscordCommandBase { public class RoleCommand extends DiscordCommandBase {
@Override @Override
public String getCommandName() { public String getCommandName() {
return "role"; return "role";
} }
@Override @Override
public void run(IMessage message, String args) { public boolean run(IMessage message, String args) {
final String usagemsg = "Subcommands: add, remove, list"; if (args.length() == 0)
if (args.length() == 0) { return false;
DiscordPlugin.sendMessageToChannel(message.getChannel(), usagemsg); String[] argsa = splitargs(args);
return; if (argsa[0].equalsIgnoreCase("add")) {
} final IRole role = checkAndGetRole(message, argsa, "This command adds a game role to your account.");
String[] argsa = args.split(" "); if (role == null)
if (argsa[0].equalsIgnoreCase("add")) { return true;
final IRole role = checkAndGetRole(message, argsa, "This command adds a game role to your account."); try {
if (role == null) DPUtils.perform(() -> message.getAuthor().addRole(role));
return; DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added game role.");
try { } catch (Exception e) {
DPUtils.perform(() -> message.getAuthor().addRole(role)); TBMCCoreAPI.SendException("Error while adding role!", e);
DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added game role."); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while adding the role.");
} catch (Exception e) { }
TBMCCoreAPI.SendException("Error while adding role!", e); } else if (argsa[0].equalsIgnoreCase("remove")) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while adding the role."); final IRole role = checkAndGetRole(message, argsa, "This command removes a game role from your account.");
} if (role == null)
} else if (argsa[0].equalsIgnoreCase("remove")) { return true;
final IRole role = checkAndGetRole(message, argsa, "This command removes a game role from your account."); try {
if (role == null) DPUtils.perform(() -> message.getAuthor().removeRole(role));
return; DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed game role.");
try { } catch (Exception e) {
DPUtils.perform(() -> message.getAuthor().removeRole(role)); TBMCCoreAPI.SendException("Error while removing role!", e);
DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed game role."); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while removing the role.");
} catch (Exception e) { }
TBMCCoreAPI.SendException("Error while removing role!", e); } else if (argsa[0].equalsIgnoreCase("list")) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while removing the role."); listRoles(message);
} } else return false;
} else if (argsa[0].equalsIgnoreCase("list")) { return true;
DiscordPlugin.sendMessageToChannel(message.getChannel(), }
"List of game roles:\n" + DiscordPlugin.GameRoles.stream().collect(Collectors.joining("\n")));
} else if (argsa[0].equalsIgnoreCase("admin") && argsa.length > 1 && argsa[1].equalsIgnoreCase("addrole")) {
if (message.getAuthor().getRolesForGuild(DiscordPlugin.mainServer).stream()
.noneMatch(r -> r.getLongID() == 126030201472811008L)) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"You need to be a moderator to use this command.");
return;
}
if (argsa.length < 3) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Add a role to the game role list.\nUsage: " + argsa[0] + " <rolename>");
return;
}
String rolename = Arrays.stream(argsa).skip(2).collect(Collectors.joining(" "));
final List<IRole> roles = (TBMCCoreAPI.IsTestServer() ? DiscordPlugin.devServer : DiscordPlugin.mainServer)
.getRolesByName(rolename);
if (roles.size() == 0) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "That role cannot be found on Discord.");
return;
}
if (roles.size() > 1) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"There are more roles with this name. Why are there more roles with this name?");
return;
}
DiscordPlugin.GameRoles.add(roles.get(0).getName());
DiscordPlugin.sendMessageToChannel(message.getChannel(), "Game role added.");
}
}
private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) { private void listRoles(IMessage message) {
if (argsa.length < 2) { DiscordPlugin.sendMessageToChannel(message.getChannel(),
DiscordPlugin.sendMessageToChannel(message.getChannel(), usage + "\nUsage: " + argsa[0] + " <rolename>"); "List of game roles:\n" + DiscordPlugin.GameRoles.stream().sorted().collect(Collectors.joining("\n")));
return null; }
}
String rolename = argsa[1];
for (int i = 2; i < argsa.length; i++)
rolename += " " + argsa[i];
if (!DiscordPlugin.GameRoles.contains(rolename)) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"That game role cannot be found.\nList of game roles:\n"
+ DiscordPlugin.GameRoles.stream().collect(Collectors.joining("\n")));
return null;
}
final List<IRole> roles = (TBMCCoreAPI.IsTestServer() ? DiscordPlugin.devServer : DiscordPlugin.mainServer)
.getRolesByName(rolename);
if (roles.size() == 0) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"The specified role cannot be found on Discord! Removing from the list.");
DiscordPlugin.GameRoles.remove(rolename);
return null;
}
if (roles.size() > 1) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"There are more roles with this name. Why are there more roles with this name?");
return null;
}
return roles.get(0);
}
@Override private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) {
public String[] getHelpText() { if (argsa.length < 2) {
return new String[] { // DiscordPlugin.sendMessageToChannel(message.getChannel(), usage + "\nUsage: " + argsa[0] + " <rolename>");
"Add or remove game roles from yourself.", // return null;
"Usage: role add|remove <name> or role list", // }
"Mods can use role addrole <name> to add a role as a game role" }; String rolename = argsa[1];
} for (int i = 2; i < argsa.length; i++)
rolename += " " + argsa[i];
if (!DiscordPlugin.GameRoles.contains(rolename)) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "That game role cannot be found.");
listRoles(message);
return null;
}
final List<IRole> roles = DiscordPlugin.mainServer.getRolesByName(rolename);
if (roles.size() == 0) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"The specified role cannot be found on Discord! Removing from the list.");
DiscordPlugin.GameRoles.remove(rolename);
return null;
}
if (roles.size() > 1) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"There are more roles with this name. Why are there more roles with this name?");
return null;
}
return roles.get(0);
}
@Override
public String[] getHelpText() {
return new String[]{ //
"Add or remove game roles from yourself.", //
"Usage: role add|remove <name> or role list", //
};
}
} }

View file

@ -1,8 +1,5 @@
package buttondevteam.discordplugin.commands; package buttondevteam.discordplugin.commands;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
@ -11,6 +8,10 @@ import buttondevteam.lib.player.ChromaGamerBase.InfoTarget;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class UserinfoCommand extends DiscordCommandBase { public class UserinfoCommand extends DiscordCommandBase {
@Override @Override
@ -19,12 +20,7 @@ public class UserinfoCommand extends DiscordCommandBase {
} }
@Override @Override
public void run(IMessage message, String args) { public boolean run(IMessage message, String args) {
if (args.contains(" ")) {
DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Too many arguments.\nUsage: userinfo [username/nickname[#tag]/ping]\nExamples:\nuserinfo ChromaBot\nuserinfo ChromaBot#6338\nuserinfo @ChromaBot#6338");
return;
}
IUser target = null; IUser target = null;
if (args.length() == 0) if (args.length() == 0)
target = message.getAuthor(); target = message.getAuthor();
@ -39,7 +35,7 @@ public class UserinfoCommand extends DiscordCommandBase {
if (targets.size() == 0) { if (targets.size() == 0) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"The user cannot be found (by name): " + args); "The user cannot be found (by name): " + args);
return; return true;
} }
for (IUser ptarget : targets) { for (IUser ptarget : targets) {
if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) {
@ -51,19 +47,19 @@ public class UserinfoCommand extends DiscordCommandBase {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"The user cannot be found (by discriminator): " + args + "(Found " + targets.size() "The user cannot be found (by discriminator): " + args + "(Found " + targets.size()
+ " users with the name.)"); + " users with the name.)");
return; return true;
} }
} else { } else {
final List<IUser> targets = getUsers(message, args); final List<IUser> targets = getUsers(message, args);
if (targets.size() == 0) { if (targets.size() == 0) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"The user cannot be found on Discord: " + args); "The user cannot be found on Discord: " + args);
return; return true;
} }
if (targets.size() > 1) { if (targets.size() > 1) {
DiscordPlugin.sendMessageToChannel(message.getChannel(), DiscordPlugin.sendMessageToChannel(message.getChannel(),
"Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping."); "Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping.");
return; return true;
} }
target = targets.get(0); target = targets.get(0);
} }
@ -76,6 +72,7 @@ public class UserinfoCommand extends DiscordCommandBase {
DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while getting the user!"); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while getting the user!");
TBMCCoreAPI.SendException("Error while getting info about " + target.getName() + "!", e); TBMCCoreAPI.SendException("Error while getting info about " + target.getName() + "!", e);
} }
return true;
} }
private List<IUser> getUsers(IMessage message, String args) { private List<IUser> getUsers(IMessage message, String args) {
@ -93,7 +90,8 @@ public class UserinfoCommand extends DiscordCommandBase {
return new String[] { // return new String[] { //
"---- User information ----", // "---- User information ----", //
"Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", // "Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", //
"Usage: userinfo <Discordname>" // "If used without args, shows your info.", //
"Usage: userinfo [username/nickname[#tag]/ping]\nExamples:\nuserinfo ChromaBot\nuserinfo ChromaBot#6338\nuserinfo @ChromaBot#6338" //
}; };
} }

View file

@ -1,12 +1,11 @@
package buttondevteam.discordplugin.listeners; package buttondevteam.discordplugin.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DPUtils;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.PluginUpdater; import buttondevteam.lib.PluginUpdater;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class AutoUpdaterListener implements Listener { public class AutoUpdaterListener implements Listener {
@EventHandler @EventHandler

View file

@ -5,9 +5,13 @@ import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.commands.DiscordCommandBase;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit;
import sx.blah.discord.api.events.IListener; import sx.blah.discord.api.events.IListener;
import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent;
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
import sx.blah.discord.handle.impl.events.guild.role.RoleCreateEvent;
import sx.blah.discord.handle.impl.events.guild.role.RoleDeleteEvent;
import sx.blah.discord.handle.impl.events.guild.role.RoleUpdateEvent;
import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent; import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
@ -22,158 +26,202 @@ import java.util.concurrent.TimeUnit;
public class CommandListener { public class CommandListener {
private static final String[] serverReadyStrings = new String[] { "In one week from now", // Ali private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali
"Between now and the heat-death of the universe.", // Ghostise "Between now and the heat-death of the universe.", // Ghostise
"Soon™", "Ask again this time next month", // Ghostise "Soon™", "Ask again this time next month", // Ghostise
"In about 3 seconds", // Nicolai "In about 3 seconds", // Nicolai
"After we finish 8 plugins", // Ali "After we finish 8 plugins", // Ali
"Tomorrow.", // Ali "Tomorrow.", // Ali
"After one tiiiny feature", // Ali "After one tiiiny feature", // Ali
"Next commit", // Ali "Next commit", // Ali
"After we finish strangling Towny", // Ali "After we finish strangling Towny", // Ali
"When we kill every *fucking* bug", // Ali "When we kill every *fucking* bug", // Ali
"Once the server stops screaming.", // Ali "Once the server stops screaming.", // Ali
"After HL3 comes out", // Ali "After HL3 comes out", // Ali
"Next time you ask", // Ali "Next time you ask", // Ali
"When will *you* be open?" // Ali "When will *you* be open?" // Ali
}; };
private static final String[] serverReadyQuestions = new String[] { "when will the server be open", private static final String[] serverReadyQuestions = new String[]{"when will the server be open",
"when will the server be ready", "when will the server be done", "when will the server be complete", "when will the server be ready", "when will the server be done", "when will the server be complete",
"when will the server be finished", "when's the server ready", "when's the server open", "when will the server be finished", "when's the server ready", "when's the server open",
"Vhen vill ze server be open?" }; "Vhen vill ze server be open?"};
private static final Random serverReadyRandom = new Random(); private static final Random serverReadyRandom = new Random();
private static final ArrayList<Short> usableServerReadyStrings = new ArrayList<Short>(serverReadyStrings.length) { private static final ArrayList<Short> usableServerReadyStrings = new ArrayList<Short>(serverReadyStrings.length) {
private static final long serialVersionUID = 2213771460909848770L; private static final long serialVersionUID = 2213771460909848770L;
{
createUsableServerReadyStrings(this);
}
};
private static void createUsableServerReadyStrings(ArrayList<Short> list) { {
for (short i = 0; i < serverReadyStrings.length; i++) createUsableServerReadyStrings(this);
list.add(i); }
} };
private static long lasttime = 0; private static void createUsableServerReadyStrings(ArrayList<Short> list) {
for (short i = 0; i < serverReadyStrings.length; i++)
list.add(i);
}
public static IListener<?>[] getListeners() { private static long lasttime = 0;
return new IListener[] { new IListener<MentionEvent>() {
@Override
public void handle(MentionEvent event) {
if (DiscordPlugin.SafeMode)
return;
if (event.getMessage().getAuthor().isBot())
return;
final IChannel channel = event.getMessage().getChannel();
if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))
return;
if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID()))
return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel
event.getMessage().getChannel().setTypingStatus(true); // Fun
runCommand(event.getMessage(), true);
}
}, new IListener<MessageReceivedEvent>() {
@Override
public void handle(MessageReceivedEvent event) {
if (DiscordPlugin.SafeMode)
return;
final String msglowercase = event.getMessage().getContent().toLowerCase();
if (!TBMCCoreAPI.IsTestServer()
&& Arrays.stream(serverReadyQuestions).anyMatch(s -> msglowercase.contains(s))) {
int next;
if (usableServerReadyStrings.size() == 0)
createUsableServerReadyStrings(usableServerReadyStrings);
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]);
return;
}
if (!event.getMessage().getChannel().isPrivate()) //
return;
if (DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class)
.isMinecraftChatEnabled())
if (!event.getMessage().getContent().equalsIgnoreCase("mcchat"))
return;
if (event.getMessage().getAuthor().isBot())
return;
runCommand(event.getMessage(), false);
}
}, new IListener<sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent>() {
@Override
public void handle(PresenceUpdateEvent event) {
if (DiscordPlugin.SafeMode)
return;
val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0);
if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE)
&& !event.getNewPresence().getStatus().equals(StatusType.OFFLINE)
&& event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream()
.anyMatch(r -> r.getLongID() == devrole.getLongID())
&& DiscordPlugin.devServer.getUsersByRole(devrole).stream()
.noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE))
&& lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())
&& Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!",
new EmbedBuilder()
.withImage(
"https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
.build());
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime());
}
}
} };
}
/** public static IListener<?>[] getListeners() {
* Runs a ChromaBot command. return new IListener[]{new IListener<MentionEvent>() {
@Override
public void handle(MentionEvent event) {
if (DiscordPlugin.SafeMode)
return;
if (event.getMessage().getAuthor().isBot())
return;
final IChannel channel = event.getMessage().getChannel();
if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID())
&& (!event.getMessage().getContent().contains("channelcon") || MCChatListener.hasCustomChat(channel))) //Allow channelcon in other servers but avoid double handling when it's enabled
return;
if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID()))
return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel
event.getMessage().getChannel().setTypingStatus(true); // Fun
runCommand(event.getMessage(), true);
}
}, new IListener<MessageReceivedEvent>() {
@Override
public void handle(MessageReceivedEvent event) {
if (DiscordPlugin.SafeMode)
return;
final String msglowercase = event.getMessage().getContent().toLowerCase();
if (!TBMCCoreAPI.IsTestServer()
&& Arrays.stream(serverReadyQuestions).anyMatch(s -> msglowercase.contains(s))) {
int next;
if (usableServerReadyStrings.size() == 0)
createUsableServerReadyStrings(usableServerReadyStrings);
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]);
return;
}
if (!event.getMessage().getChannel().isPrivate()
&& !(event.getMessage().getContent().startsWith("/")
&& event.getChannel().getStringID().equals(DiscordPlugin.botchannel.getStringID()))) //
return;
if (DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class)
.isMinecraftChatEnabled())
if (!event.getMessage().getContent().equalsIgnoreCase("mcchat"))
return;
if (event.getMessage().getAuthor().isBot())
return;
runCommand(event.getMessage(), false);
}
}, new IListener<sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent>() {
@Override
public void handle(PresenceUpdateEvent event) {
if (DiscordPlugin.SafeMode)
return;
val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0);
if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE)
&& !event.getNewPresence().getStatus().equals(StatusType.OFFLINE)
&& event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream()
.anyMatch(r -> r.getLongID() == devrole.getLongID())
&& DiscordPlugin.devServer.getUsersByRole(devrole).stream()
.noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE))
&& lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())
&& Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!",
new EmbedBuilder()
.withImage(
"https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
.build());
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime());
}
}
}, (IListener<RoleCreateEvent>) event -> {
Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> {
if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole()))
return; //Deleted or not a game role
DiscordPlugin.GameRoles.add(event.getRole().getName());
DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default.");
}, 100);
}, (IListener<RoleDeleteEvent>) event -> {
if (DiscordPlugin.GameRoles.remove(event.getRole().getName()))
DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role.");
}, (IListener<RoleUpdateEvent>) event -> { //Role update event
if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) {
if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName()))
DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed.");
} else {
boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role
DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color
if (removed)
DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + ".");
else
DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color.");
}
}};
}
/**
* Runs a ChromaBot command.
* *
* @param message * @param message The Discord message
* The Discord message * @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message
* @param mentionedonly * @return Whether it ran the command (always true if mentionedonly is false)
* Only run the command if ChromaBot is mentioned at the start of the message */
* @return Whether it ran the command (always true if mentionedonly is false) public static boolean runCommand(IMessage message, boolean mentionedonly) {
*/ debug("A");
public static boolean runCommand(IMessage message, boolean mentionedonly) { if (DiscordPlugin.SafeMode)
if (DiscordPlugin.SafeMode) return true;
return true; debug("B");
final StringBuilder cmdwithargs = new StringBuilder(message.getContent()); final StringBuilder cmdwithargs = new StringBuilder(message.getContent());
final String mention = DiscordPlugin.dc.getOurUser().mention(false); final String mention = DiscordPlugin.dc.getOurUser().mention(false);
final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true);
boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); boolean gotmention = checkanddeletemention(cmdwithargs, mention, message);
gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention; gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention;
for (String mentionRole : (Iterable<String>) message.getRoleMentions().stream().filter(r -> DiscordPlugin.dc.getOurUser().hasRole(r)).map(r -> r.mention())::iterator) for (String mentionRole : (Iterable<String>) message.getRoleMentions().stream().filter(r -> DiscordPlugin.dc.getOurUser().hasRole(r)).map(r -> r.mention())::iterator)
gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions
if (mentionedonly && !gotmention) { debug("C");
message.getChannel().setTypingStatus(false); if (mentionedonly && !gotmention) {
return false; message.getChannel().setTypingStatus(false);
} return false;
message.getChannel().setTypingStatus(true); }
int index = cmdwithargs.indexOf(" "); debug("D");
String cmd; message.getChannel().setTypingStatus(true);
String args; String cmdwithargsString = cmdwithargs.toString().trim(); //Remove spaces between mention and command
if (index == -1) { int index = cmdwithargsString.indexOf(" ");
cmd = cmdwithargs.toString(); String cmd;
args = ""; String args;
} else { if (index == -1) {
cmd = cmdwithargs.substring(0, index); cmd = cmdwithargsString;
args = cmdwithargs.substring(index + 1); args = "";
} } else {
DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message); cmd = cmdwithargsString.substring(0, index);
message.getChannel().setTypingStatus(false); args = cmdwithargsString.substring(index + 1).trim(); //In case there are multiple spaces
return true; }
} debug("E");
DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message);
message.getChannel().setTypingStatus(false);
return true;
}
private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { private static boolean debug = false;
if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text
if (cmdwithargs.length() > mention.length() + 1) public static void debug(String debug) {
cmdwithargs = cmdwithargs.delete(0, if (CommandListener.debug) //Debug
cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length()); System.out.println(debug);
else }
cmdwithargs.replace(0, cmdwithargs.length(), "help");
else public static boolean debug() {
return false; return debug = !debug;
if (cmdwithargs.length() == 0) }
cmdwithargs.replace(0, cmdwithargs.length(), "help");
return true; private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) {
} if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text
if (cmdwithargs.length() > mention.length() + 1)
cmdwithargs = cmdwithargs.delete(0,
cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length());
else
cmdwithargs.replace(0, cmdwithargs.length(), "help");
else {
if (cmdwithargs.length() > 0 && cmdwithargs.charAt(0) == '/')
cmdwithargs.deleteCharAt(0); //Don't treat / as mention, mentions can be used in public mcchat
return false;
}
if (cmdwithargs.length() == 0)
cmdwithargs.replace(0, cmdwithargs.length(), "help");
return true;
}
} }

View file

@ -1,9 +1,9 @@
package buttondevteam.discordplugin.listeners; package buttondevteam.discordplugin.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCDebugMessageEvent; import buttondevteam.lib.TBMCDebugMessageEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class DebugMessageListener implements Listener{ public class DebugMessageListener implements Listener{
@EventHandler @EventHandler

View file

@ -23,8 +23,8 @@ public class ExceptionListener implements Listener {
return; return;
if (lastthrown.stream() if (lastthrown.stream()
.anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace()) .anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace())
&& e.getException().getMessage() == null ? ex.getMessage() == null && (e.getException().getMessage() == null ? ex.getMessage() == null
: e.getException().getMessage().equals(ex.getMessage())) // e.Exception.Message==ex.Message : e.getException().getMessage().equals(ex.getMessage()))) // e.Exception.Message==ex.Message
&& lastsourcemsg.contains(e.getSourceMessage())) && lastsourcemsg.contains(e.getSourceMessage()))
return; return;
SendException(e.getException(), e.getSourceMessage()); SendException(e.getException(), e.getSourceMessage());

View file

@ -10,6 +10,8 @@ import buttondevteam.lib.chat.Channel;
import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.ChatRoom;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import com.vdurmont.emoji.EmojiParser;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -33,9 +35,10 @@ import sx.blah.discord.util.MissingPermissionsException;
import java.awt.*; import java.awt.*;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -45,6 +48,7 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
private BukkitTask sendtask; private BukkitTask sendtask;
private LinkedBlockingQueue<AbstractMap.SimpleEntry<TBMCChatEvent, Instant>> sendevents = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<AbstractMap.SimpleEntry<TBMCChatEvent, Instant>> sendevents = new LinkedBlockingQueue<>();
private Runnable sendrunnable; private Runnable sendrunnable;
private static Thread sendthread;
@EventHandler // Minecraft @EventHandler // Minecraft
public void onMCChat(TBMCChatEvent ev) { public void onMCChat(TBMCChatEvent ev) {
@ -54,8 +58,10 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (sendtask != null) if (sendtask != null)
return; return;
sendrunnable = () -> { sendrunnable = () -> {
sendthread = Thread.currentThread();
processMCToDiscord(); processMCToDiscord();
sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down
sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable);
}; };
sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable);
} }
@ -117,27 +123,41 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
} }
}; };
// Checks if the given channel is different than where the message was sent from // Checks if the given channel is different than where the message was sent from
// Or if it was from MC
Predicate<IChannel> isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) Predicate<IChannel> isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase)
|| ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID();
if ((e.getChannel() == Channel.GlobalChat || e.getChannel().ID.equals("rp")) if ((e.getChannel() == Channel.GlobalChat || e.getChannel().ID.equals("rp"))
&& isdifferentchannel.test(DiscordPlugin.chatchannel)) && (e.isFromcmd() || isdifferentchannel.test(DiscordPlugin.chatchannel)))
doit.accept(lastmsgdata == null doit.accept(lastmsgdata == null
? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null, null) ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null, null)
: lastmsgdata); : lastmsgdata);
for (LastMsgData data : lastmsgPerUser) { for (LastMsgData data : lastmsgPerUser) {
if (data.dp.isMinecraftChatEnabled() && isdifferentchannel.test(data.channel) if (data.dp.isMinecraftChatEnabled() && (e.isFromcmd() || isdifferentchannel.test(data.channel))
&& e.shouldSendTo(getSender(data.channel, data.user, data.dp))) && e.shouldSendTo(getSender(data.channel, data.user)))
doit.accept(data); doit.accept(data);
} }
val iterator = lastmsgCustom.iterator();
while (iterator.hasNext()) { //TODO: Add cmd to fix mcchat
val lmd = iterator.next();
if ((e.isFromcmd() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord
&& e.getChannel().ID.equals(lmd.mcchannel.ID)) //If it's from a command, the command msg has been deleted, so we need to send it
if (e.shouldSendTo(lmd.dcp) && e.getGroupID().equals(lmd.groupID)) //Check original user's permissions
doit.accept(lmd);
else {
iterator.remove(); //If the user no longer has permission, remove the connection
DiscordPlugin.sendMessageToChannel(lmd.channel, "The user no longer has permission to view the channel, connection removed.");
}
}
} catch (Exception ex) { } catch (Exception ex) {
TBMCCoreAPI.SendException("Error while sending message to Discord!", ex); TBMCCoreAPI.SendException("Error while sending message to Discord!", ex);
} }
} }
@RequiredArgsConstructor @RequiredArgsConstructor
private static class LastMsgData { public static class LastMsgData {
public IMessage message; public IMessage message;
public long time; public long time;
public String content; public String content;
@ -147,6 +167,20 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
public final DiscordPlayer dp; public final DiscordPlayer dp;
} }
public static class CustomLMD extends LastMsgData {
public final String groupID;
public final Channel mcchannel;
public final DiscordConnectedPlayer dcp;
public CustomLMD(@NonNull IChannel channel, @NonNull IUser user, @NonNull DiscordPlayer dp,
@NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp) {
super(channel, user, dp);
groupID = groupid;
this.mcchannel = mcchannel;
this.dcp = dcp;
}
}
@EventHandler @EventHandler
public void onChatPreprocess(TBMCChatPreprocessEvent event) { public void onChatPreprocess(TBMCChatPreprocessEvent event) {
int start = -1; int start = -1;
@ -168,7 +202,7 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
} }
private static final String[] UnconnectedCmds = new String[]{"list", "u", "shrug", "tableflip", "unflip", "mwiki", private static final String[] UnconnectedCmds = new String[]{"list", "u", "shrug", "tableflip", "unflip", "mwiki",
"yeehaw"}; "yeehaw", "lenny", "rp", "plugins"};
private static LastMsgData lastmsgdata; private static LastMsgData lastmsgdata;
private static short lastlist = 0; private static short lastlist = 0;
@ -177,6 +211,10 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
* Used for messages in PMs (mcchat). * Used for messages in PMs (mcchat).
*/ */
private static ArrayList<LastMsgData> lastmsgPerUser = new ArrayList<LastMsgData>(); private static ArrayList<LastMsgData> lastmsgPerUser = new ArrayList<LastMsgData>();
/**
* Used for town or nation chats or anything else
*/
private static ArrayList<CustomLMD> lastmsgCustom = new ArrayList<>();
public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) { public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) {
TBMCPlayer mcp = dp.getAs(TBMCPlayer.class); TBMCPlayer mcp = dp.getAs(TBMCPlayer.class);
@ -220,6 +258,27 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
.anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did)); .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did));
} }
public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, DiscordPlayer dp, IUser user, DiscordConnectedPlayer dcp) {
val lmd = new CustomLMD(channel, user, dp, groupid, mcchannel, dcp);
lastmsgCustom.add(lmd);
}
public static boolean hasCustomChat(IChannel channel) {
return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID());
}
public static CustomLMD getCustomChat(IChannel channel) {
return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null);
}
public static boolean removeCustomChat(IChannel channel) {
return lastmsgCustom.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID());
}
public static List<CustomLMD> getCustomChats() {
return Collections.unmodifiableList(lastmsgCustom);
}
/** /**
* May contain P&lt;DiscordID&gt; as key for public chat * May contain P&lt;DiscordID&gt; as key for public chat
*/ */
@ -242,6 +301,12 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
data.message = null; // Since only private channels are stored, only those will work anyways data.message = null; // Since only private channels are stored, only those will work anyways
} }
public static void resetLastMessageCustom(IChannel channel) {
for (LastMsgData data : lastmsgCustom)
if (data.channel.getLongID() == channel.getLongID())
data.message = null;
}
/** /**
* This overload sends it to the global chat. * This overload sends it to the global chat.
*/ */
@ -258,37 +323,50 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
action.accept(DiscordPlugin.chatchannel); action.accept(DiscordPlugin.chatchannel);
for (LastMsgData data : lastmsgPerUser) for (LastMsgData data : lastmsgPerUser)
action.accept(data.channel); action.accept(data.channel);
lastmsgCustom.forEach(cc -> action.accept(cc.channel));
} }
private static void forAllowedMCChat(Consumer<IChannel> action, TBMCSystemChatEvent event) { private static void forAllowedMCChat(Consumer<IChannel> action, TBMCSystemChatEvent event) {
if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) if (Channel.GlobalChat.ID.equals(event.getChannel().ID))
action.accept(DiscordPlugin.chatchannel); action.accept(DiscordPlugin.chatchannel);
for (LastMsgData data : lastmsgPerUser) for (LastMsgData data : lastmsgPerUser)
if (event.shouldSendTo(getSender(data.channel, data.user, data.dp))) if (event.shouldSendTo(getSender(data.channel, data.user)))
action.accept(data.channel); action.accept(data.channel);
lastmsgCustom.stream().filter(data -> event.shouldSendTo(data.dcp))
.map(data -> data.channel).forEach(action);
}
public static void stop() {
if (sendthread != null) sendthread.interrupt();
if (recthread != null) recthread.interrupt();
} }
private BukkitTask rectask; private BukkitTask rectask;
private LinkedBlockingQueue<MessageReceivedEvent> recevents = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<MessageReceivedEvent> recevents = new LinkedBlockingQueue<>();
private IMessage lastmsgfromd; // Last message sent by a Discord user, used for clearing checkmarks private IMessage lastmsgfromd; // Last message sent by a Discord user, used for clearing checkmarks
private Runnable recrun; private Runnable recrun;
private static Thread recthread;
@Override // Discord @Override // Discord
public void handle(MessageReceivedEvent ev) { public void handle(MessageReceivedEvent ev) {
if (DiscordPlugin.SafeMode) if (DiscordPlugin.SafeMode)
return; return;
val author = ev.getMessage().getAuthor(); val author = ev.getMessage().getAuthor();
if (!ev.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID())
&& !(ev.getMessage().getChannel().isPrivate() && isMinecraftChatEnabled(author.getStringID())))
return;
if (author.isBot()) if (author.isBot())
return; return;
final boolean hasCustomChat = hasCustomChat(ev.getChannel());
if (!ev.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID())
&& !(ev.getMessage().getChannel().isPrivate() && isMinecraftChatEnabled(author.getStringID()))
&& !hasCustomChat)
return;
if (ev.getMessage().getContent().equalsIgnoreCase("mcchat")) if (ev.getMessage().getContent().equalsIgnoreCase("mcchat"))
return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommandListener) return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommandListener)
if (CommandListener.runCommand(ev.getMessage(), true)) if (CommandListener.runCommand(ev.getMessage(), true))
return; return;
if (!ev.getMessage().getChannel().isPrivate()) if (!ev.getMessage().getChannel().isPrivate())
resetLastMessage(); resetLastMessage();
else if (hasCustomChat)
resetLastMessageCustom(ev.getChannel());
else else
resetLastMessage(ev.getMessage().getChannel()); resetLastMessage(ev.getMessage().getChannel());
lastlist++; lastlist++;
@ -296,8 +374,10 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (rectask != null) if (rectask != null)
return; return;
recrun = () -> { //Don't return in a while loop next time recrun = () -> { //Don't return in a while loop next time
recthread = Thread.currentThread();
processDiscordToMC(); processDiscordToMC();
rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down
rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing
}; };
rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing
} }
@ -315,7 +395,7 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
val user = DiscordPlayer.getUser(sender.getStringID(), DiscordPlayer.class); val user = DiscordPlayer.getUser(sender.getStringID(), DiscordPlayer.class);
String dmessage = event.getMessage().getContent(); String dmessage = event.getMessage().getContent();
try { try {
final DiscordSenderBase dsender = getSender(event.getMessage().getChannel(), sender, user); final DiscordSenderBase dsender = getSender(event.getMessage().getChannel(), sender);
for (IUser u : event.getMessage().getMentions()) { for (IUser u : event.getMessage().getMentions()) {
dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting
@ -323,11 +403,15 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName()));
} }
BiConsumer<Channel, String> sendChatMessage = (channel, msg) -> // dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?)
TBMCChatAPI.SendChatMessage(channel, dsender, dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
Function<String, String> getChatMessage = msg -> //
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
.getAttachments().stream().map(a -> a.getUrl()).collect(Collectors.joining("\n")) .getAttachments().stream().map(a -> a.getUrl()).collect(Collectors.joining("\n"))
: "")); : "");
CustomLMD clmd = getCustomChat(event.getChannel());
boolean react = false; boolean react = false;
@ -336,40 +420,46 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate())
event.getMessage().delete(); event.getMessage().delete();
}); });
final String cmd = dmessage.substring(1).toLowerCase(); //preprocessChat(dsender, dmessage); - Same is done below
final String cmdlowercased = dmessage.substring(1).toLowerCase();
if (dsender instanceof DiscordSender && Arrays.stream(UnconnectedCmds) if (dsender instanceof DiscordSender && Arrays.stream(UnconnectedCmds)
.noneMatch(s -> cmd.equals(s) || cmd.startsWith(s + " "))) { .noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) {
// Command not whitelisted // Command not whitelisted
dsender.sendMessage("Sorry, you can only access these commands:\n" dsender.sendMessage("Sorry, you can only access these commands:\n"
+ Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc) + Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc)
.collect(Collectors.joining(", ")) .collect(Collectors.joining(", "))
+ (user.getConnectedID(TBMCPlayer.class) == null + (user.getConnectedID(TBMCPlayer.class) == null
? "\nTo access your commands, first please connect your accounts, using @ChromaBot connect in " ? "\nTo access your commands, first please connect your accounts, using /connect in "
+ DiscordPlugin.botchannel.mention() + DiscordPlugin.botchannel.mention()
+ "\nThen you can access all of your regular commands (even offline) in private chat: DM me `mcchat`!" + "\nThen y"
: "\nYou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!")); : "\nY")
+ "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!");
return; return;
} }
if (lastlist > 5) { if (lastlist > 5) {
ListC = 0; ListC = 0;
lastlist = 0; lastlist = 0;
} }
if (cmd.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already if (cmdlowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
{ {
dsender.sendMessage("Stop it. You know the answer."); dsender.sendMessage("Stop it. You know the answer.");
lastlist = 0; lastlist = 0;
} else { } else {
int spi = cmd.indexOf(' '); int spi = cmdlowercased.indexOf(' ');
final String topcmd = spi == -1 ? cmd : cmd.substring(0, spi); final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi);
Optional<Channel> ch = Channel.getChannels().stream() Optional<Channel> ch = Channel.getChannels().stream()
.filter(c -> c.ID.equalsIgnoreCase(topcmd)).findAny(); .filter(c -> c.ID.equalsIgnoreCase(topcmd)
|| (c.IDs != null && c.IDs.length > 0
&& Arrays.stream(c.IDs).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny();
if (!ch.isPresent()) if (!ch.isPresent())
Bukkit.getScheduler().runTask(DiscordPlugin.plugin, Bukkit.getScheduler().runTask(DiscordPlugin.plugin,
() -> VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd)); () -> {
VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmdlowercased);
Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased);
});
else { else {
Channel chc = ch.get(); Channel chc = ch.get();
if (!chc.ID.equals(Channel.GlobalChat.ID) if (!chc.ID.equals(Channel.GlobalChat.ID) && !chc.ID.equals("rp") && !event.getMessage().getChannel().isPrivate())
&& !event.getMessage().getChannel().isPrivate())
dsender.sendMessage( dsender.sendMessage(
"You can only talk in global in the public chat. DM `mcchat` to enable private chat to talk in the other channels."); "You can only talk in global in the public chat. DM `mcchat` to enable private chat to talk in the other channels.");
else { else {
@ -387,7 +477,11 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
dsender.sendMessage("You're now talking in: " dsender.sendMessage("You're now talking in: "
+ DPUtils.sanitizeString(dsender.getMcchannel().DisplayName)); + DPUtils.sanitizeString(dsender.getMcchannel().DisplayName));
} else { // Send single message } else { // Send single message
sendChatMessage.accept(chc, cmd.substring(spi + 1)); final String msg = event.getMessage().getContent().substring(spi + 2);
if (clmd == null)
TBMCChatAPI.SendChatMessage(chc, dsender, getChatMessage.apply(msg), true);
else
TBMCChatAPI.SendChatMessageDontCheckSender(chc, dsender, getChatMessage.apply(msg), true, clmd.dcp);
react = true; react = true;
} }
} }
@ -396,21 +490,20 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
lastlistp = (short) Bukkit.getOnlinePlayers().size(); lastlistp = (short) Bukkit.getOnlinePlayers().size();
} else {// Not a command } else {// Not a command
if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0
&& !event.getChannel().isPrivate()) && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage())
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, 0, TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, 0, "everyone",
(dsender instanceof Player ? ((Player) dsender).getDisplayName() (dsender instanceof Player ? ((Player) dsender).getDisplayName()
: dsender.getName()) + " pinned a message on Discord."); : dsender.getName()) + " pinned a message on Discord.");
else { else {
sendChatMessage.accept(dsender.getMcchannel(), dmessage); if (clmd != null)
TBMCChatAPI.SendChatMessageDontCheckSender(clmd.mcchannel, dsender, getChatMessage.apply(dmessage), false, clmd.dcp);
else
TBMCChatAPI.SendChatMessage(dsender.getMcchannel(), dsender, getChatMessage.apply(dmessage));
react = true; react = true;
} }
} }
if (react) { if (react) {
try { try {
/*
* System.out.println("Got message: " + m.getContent() + " with embeds: " + m.getEmbeds().stream().map(e -> e.getTitle() + " " + e.getDescription())
* .collect(Collectors.joining("\n")));
*/
if (lastmsgfromd != null) { if (lastmsgfromd != null) {
DPUtils.perform(() -> lastmsgfromd.removeReaction(DiscordPlugin.dc.getOurUser(), DPUtils.perform(() -> lastmsgfromd.removeReaction(DiscordPlugin.dc.getOurUser(),
DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time
@ -426,10 +519,46 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
} }
} }
private boolean preprocessChat(DiscordSenderBase dsender, String dmessage) {
if (dmessage.length() < 2)
return false;
int index = dmessage.indexOf(" ");
String cmd;
if (index == -1) { // Only the command is run
cmd = dmessage;
for (Channel channel : Channel.getChannels()) {
if (cmd.equalsIgnoreCase(channel.ID) || (channel.IDs != null && Arrays.stream(channel.IDs).anyMatch(cmd::equalsIgnoreCase))) {
Channel oldch = dsender.getMcchannel();
if (oldch instanceof ChatRoom)
((ChatRoom) oldch).leaveRoom(dsender);
if (oldch.equals(channel))
dsender.setMcchannel(Channel.GlobalChat);
else {
dsender.setMcchannel(channel);
if (channel instanceof ChatRoom)
((ChatRoom) channel).joinRoom(dsender);
}
dsender.sendMessage("You are now talking in: " + dsender.getMcchannel().DisplayName);
return true;
}
}
} else { // We have arguments
cmd = dmessage.substring(0, index);
for (Channel channel : Channel.getChannels()) {
if (cmd.equalsIgnoreCase(channel.ID) || (channel.IDs != null && Arrays.stream(channel.IDs).anyMatch(cmd::equalsIgnoreCase))) {
TBMCChatAPI.SendChatMessage(channel, dsender, dmessage.substring(index + 1));
return true;
}
}
// TODO: Target selectors
}
return false;
}
/** /**
* This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc.
*/ */
private static DiscordSenderBase getSender(IChannel channel, final IUser author, DiscordPlayer dp) { private static DiscordSenderBase getSender(IChannel channel, final IUser author) {
val key = (channel.isPrivate() ? "" : "P") + author.getStringID(); val key = (channel.isPrivate() ? "" : "P") + author.getStringID();
return Stream.<Supplier<Optional<DiscordSenderBase>>>of( // https://stackoverflow.com/a/28833677/2703239 return Stream.<Supplier<Optional<DiscordSenderBase>>>of( // https://stackoverflow.com/a/28833677/2703239
() -> Optional.ofNullable(OnlineSenders.get(key)), // Find first non-null () -> Optional.ofNullable(OnlineSenders.get(key)), // Find first non-null

View file

@ -45,26 +45,28 @@ public class MCListener implements Listener {
public void onPlayerJoin(TBMCPlayerJoinEvent e) { public void onPlayerJoin(TBMCPlayerJoinEvent e) {
if (e.getPlayer() instanceof DiscordConnectedPlayer) if (e.getPlayer() instanceof DiscordConnectedPlayer)
return; // Don't show the joined message for the fake player return; // Don't show the joined message for the fake player
final Player p = e.getPlayer(); Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); final Player p = e.getPlayer();
if (dp != null) { DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class);
val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); if (dp != null) {
MCChatListener.OnlineSenders.put(dp.getDiscordID(), val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); MCChatListener.OnlineSenders.put(dp.getDiscordID(),
MCChatListener.OnlineSenders.put("P" + dp.getDiscordID(), new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p));
new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); MCChatListener.OnlineSenders.put("P" + dp.getDiscordID(),
} new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p));
if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { }
IUser user = DiscordPlugin.dc if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) {
.getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); IUser user = DiscordPlugin.dc
p.sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get())));
+ " do /discord accept"); p.sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator()
p.sendMessage("§bIf it wasn't you, do /discord decline"); + " do /discord accept");
} p.sendMessage("§bIf it wasn't you, do /discord decline");
if (!DiscordPlugin.hooked) }
MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " joined the game"); if (!DiscordPlugin.hooked)
MCChatListener.ListC = 0; MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " joined the game");
ChromaBot.getInstance().updatePlayerList(); MCChatListener.ListC = 0;
ChromaBot.getInstance().updatePlayerList();
});
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
@ -93,7 +95,7 @@ public class MCListener implements Listener {
if (DiscordPlugin.SafeMode) if (DiscordPlugin.SafeMode)
return; return;
DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class); DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class);
if (dp == null || dp.getDiscordID() == null || dp.getDiscordID() == "") if (dp == null || dp.getDiscordID() == null || dp.getDiscordID().equals(""))
return; return;
IUser user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); IUser user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
e.addInfo("Discord tag: " + user.getName() + "#" + user.getDiscriminator()); e.addInfo("Discord tag: " + user.getName() + "#" + user.getDiscriminator());

View file

@ -1,7 +1,5 @@
package buttondevteam.discordplugin.mccommands; package buttondevteam.discordplugin.mccommands;
import org.bukkit.entity.Player;
import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.discordplugin.commands.ConnectCommand;
import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.discordplugin.listeners.MCChatListener;
@ -9,6 +7,7 @@ import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import org.bukkit.entity.Player;
@CommandClass(modOnly = false, path = "accept") @CommandClass(modOnly = false, path = "accept")
public class AcceptMCCommand extends DiscordMCCommandBase { public class AcceptMCCommand extends DiscordMCCommandBase {
@ -18,7 +17,7 @@ public class AcceptMCCommand extends DiscordMCCommandBase {
return new String[] { // return new String[] { //
"§6---- Accept Discord connection ----", // "§6---- Accept Discord connection ----", //
"Accept a pending connection between your Discord and Minecraft account.", // "Accept a pending connection between your Discord and Minecraft account.", //
"To start the connection process, do §b@ChromaBot connect <MCname>§r in the #bot channel on Discord", // "To start the connection process, do §b/connect <MCname>§r in the #bot channel on Discord", //
"Usage: /" + alias + " accept" // "Usage: /" + alias + " accept" //
}; };
} }

View file

@ -1,9 +1,8 @@
package buttondevteam.discordplugin.mccommands; package buttondevteam.discordplugin.mccommands;
import org.bukkit.entity.Player;
import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.discordplugin.commands.ConnectCommand;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import org.bukkit.entity.Player;
@CommandClass(modOnly = false, path = "decline") @CommandClass(modOnly = false, path = "decline")
public class DeclineMCCommand extends DiscordMCCommandBase { public class DeclineMCCommand extends DiscordMCCommandBase {
@ -13,7 +12,7 @@ public class DeclineMCCommand extends DiscordMCCommandBase {
return new String[] { // return new String[] { //
"§6---- Decline Discord connection ----", // "§6---- Decline Discord connection ----", //
"Decline a pending connection between your Discord and Minecraft account.", // "Decline a pending connection between your Discord and Minecraft account.", //
"To start the connection process, do §b@ChromaBot connect <MCname>§r in the #bot channel on Discord", // "To start the connection process, do §b/connect <MCname>§r in the #bot channel on Discord", //
"Usage: /" + alias + " decline" // "Usage: /" + alias + " decline" //
}; };
} }

View file

@ -1,7 +1,8 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.*; import buttondevteam.discordplugin.DiscordSenderBase;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.PistonMoveReaction; import org.bukkit.block.PistonMoveReaction;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -10,13 +11,11 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.metadata.MetadataValue; import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import buttondevteam.discordplugin.DiscordSenderBase;
import lombok.Getter;
import lombok.Setter;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.*;
@Getter @Getter
@Setter @Setter
@SuppressWarnings("deprecated") @SuppressWarnings("deprecated")

View file

@ -1,25 +1,27 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.net.InetSocketAddress; import buttondevteam.discordplugin.DiscordPlugin;
import java.util.*; import lombok.Getter;
import lombok.experimental.Delegate;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.advancement.Advancement; import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress; import org.bukkit.advancement.AdvancementProgress;
import org.bukkit.conversations.Conversation; import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent; import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.entity.*; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.map.MapView; import org.bukkit.map.MapView;
import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.PermissibleBase;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Scoreboard;
import buttondevteam.discordplugin.DiscordPlugin;
import lombok.experimental.Delegate;
import lombok.Getter;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.net.InetSocketAddress;
import java.util.*;
public class DiscordFakePlayer extends DiscordHumanEntity implements Player { public class DiscordFakePlayer extends DiscordHumanEntity implements Player {
protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid, String mcname) { protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid, String mcname) {
super(user, channel, entityId, uuid); super(user, channel, entityId, uuid);

View file

@ -1,7 +1,5 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.UUID;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -10,10 +8,11 @@ import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
import org.bukkit.inventory.*; import org.bukkit.inventory.*;
import org.bukkit.inventory.InventoryView.Property; import org.bukkit.inventory.InventoryView.Property;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.UUID;
public abstract class DiscordHumanEntity extends DiscordLivingEntity implements HumanEntity { public abstract class DiscordHumanEntity extends DiscordLivingEntity implements HumanEntity {
protected DiscordHumanEntity(IUser user, IChannel channel, int entityId, UUID uuid) { protected DiscordHumanEntity(IUser user, IChannel channel, int entityId, UUID uuid) {
super(user, channel, entityId, uuid); super(user, channel, entityId, uuid);

View file

@ -1,12 +1,5 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
@ -14,6 +7,13 @@ import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class DiscordInventory implements Inventory { public class DiscordInventory implements Inventory {
public DiscordInventory(DiscordHumanEntity holder) { public DiscordInventory(DiscordHumanEntity holder) {
this.holder = holder; this.holder = holder;

View file

@ -1,12 +1,7 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.Arrays; import lombok.Getter;
import java.util.Collection; import lombok.Setter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.attribute.Attribute; import org.bukkit.attribute.Attribute;
@ -21,12 +16,11 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import lombok.Getter;
import lombok.Setter;
import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
import java.util.*;
public abstract class DiscordLivingEntity extends DiscordEntity implements LivingEntity { public abstract class DiscordLivingEntity extends DiscordEntity implements LivingEntity {
protected DiscordLivingEntity(IUser user, IChannel channel, int entityId, UUID uuid) { protected DiscordLivingEntity(IUser user, IChannel channel, int entityId, UUID uuid) {

View file

@ -1,7 +1,10 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.Arrays; import buttondevteam.discordplugin.DiscordSenderBase;
import buttondevteam.discordplugin.IMCPlayer;
import lombok.Getter;
import lombok.val;
import net.minecraft.server.v1_12_R1.*;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
@ -9,17 +12,7 @@ import org.bukkit.craftbukkit.v1_12_R1.command.VanillaCommandWrapper;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import buttondevteam.discordplugin.DiscordSenderBase; import java.util.Arrays;
import buttondevteam.discordplugin.IMCPlayer;
import lombok.Getter;
import lombok.val;
import net.minecraft.server.v1_12_R1.ChatMessage;
import net.minecraft.server.v1_12_R1.CommandException;
import net.minecraft.server.v1_12_R1.EnumChatFormat;
import net.minecraft.server.v1_12_R1.IChatBaseComponent;
import net.minecraft.server.v1_12_R1.ICommandListener;
import net.minecraft.server.v1_12_R1.MinecraftServer;
import net.minecraft.server.v1_12_R1.World;
public class VanillaCommandListener<T extends DiscordSenderBase & IMCPlayer<T>> implements ICommandListener { public class VanillaCommandListener<T extends DiscordSenderBase & IMCPlayer<T>> implements ICommandListener {
private @Getter T player; private @Getter T player;

0
src/main/resources/plugin.yml Normal file → Executable file
View file

0
src/test/java/buttondevteam/DiscordPlugin/AppTest.java Normal file → Executable file
View file