Merge pull request #42 from TBMCPlugins/dev

Finished private Minecraft chat, lots of bug fixes
This commit is contained in:
Norbi Peti 2017-07-13 01:48:02 +02:00 committed by GitHub
commit c6fb0cd917
18 changed files with 1428 additions and 2022 deletions

View file

@ -1,4 +1,26 @@
cache:
directories:
- $HOME/.m2/repository/org/bukkit/craftbukkit
before_install: | # Wget BuildTools and run if cached folder not found
if [ ! -d "$HOME/.m2/repository/org/bukkit/craftbukkit/1.12-R0.1-SNAPSHOT" ]; then
wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
# grep so that download counts don't appear in log files
java -jar BuildTools.jar --rev 1.12 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$"
fi
language: java language: java
jdk: jdk:
- oraclejdk8 - oraclejdk8
sudo: true
deploy:
# deploy develop to the staging environment
- provider: script
script: chmod +x deploy.sh && sh deploy.sh staging
on:
branch: dev
skip_cleanup: true
# deploy master to production
- provider: script
script: chmod +x deploy.sh && sh deploy.sh production
on:
branch: master
skip_cleanup: true

10
deploy.sh Normal file
View file

@ -0,0 +1,10 @@
#!/bin/sh
FILENAME=$(find target/ -maxdepth 1 ! -name '*original*' -name '*.jar')
echo Found file: $FILENAME
if [ $1 = 'production' ]; then
echo Production mode
echo $UPLOAD_KEY > upload_key
chmod 400 upload_key
yes | scp -B -i upload_key -o StrictHostKeyChecking=no $FILENAME travis@server.figytuna.com:/minecraft/main/plugins
fi

24
pom.xml
View file

@ -13,7 +13,7 @@
<build> <build>
<!-- <sourceDirectory>target/generated-sources/delombok</sourceDirectory> <!-- <sourceDirectory>target/generated-sources/delombok</sourceDirectory>
<testSourceDirectory>target/generated-test-sources/delombok</testSourceDirectory> --> <testSourceDirectory>target/generated-test-sources/delombok</testSourceDirectory> -->
<sourceDirectory>src/main/java</sourceDirectory> <sourceDirectory>src/main/java</sourceDirectory>
<resources> <resources>
<resource> <resource>
<directory>src</directory> <directory>src</directory>
@ -131,6 +131,10 @@
<id>projectlombok.org</id> <id>projectlombok.org</id>
<url>http://projectlombok.org/mavenrepo</url> <url>http://projectlombok.org/mavenrepo</url>
</repository> </repository>
<repository>
<id>pex-repo</id>
<url>http://pex-repo.aoeu.xyz</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
@ -146,6 +150,12 @@
<version>1.12-R0.1-SNAPSHOT</version> <version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>com.github.austinv11</groupId> <groupId>com.github.austinv11</groupId>
<artifactId>Discord4j</artifactId> <artifactId>Discord4j</artifactId>
@ -188,5 +198,17 @@
<version>1.16.16</version> <version>1.16.16</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>ru.tehkode</groupId>
<artifactId>PermissionsEx</artifactId>
<version>1.23.1</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -1,12 +1,13 @@
package buttondevteam.discordplugin; package buttondevteam.discordplugin;
import buttondevteam.discordplugin.listeners.MCChatListener;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.PlayerData;
import buttondevteam.lib.player.UserClass; import buttondevteam.lib.player.UserClass;
@UserClass(foldername = "discord") @UserClass(foldername = "discord")
public class DiscordPlayer extends ChromaGamerBase { public class DiscordPlayer extends ChromaGamerBase {
private String did; private String did;
// private @Getter @Setter boolean minecraftChatEnabled;
public DiscordPlayer() { public DiscordPlayer() {
} }
@ -17,7 +18,11 @@ public class DiscordPlayer extends ChromaGamerBase {
return did; return did;
} }
public PlayerData<Boolean> minecraftChat() { /**
return data(false); * Returns true if player has the private Minecraft chat enabled. For setting the value, see
* {@link MCChatListener#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)}
*/
public boolean isMinecraftChatEnabled() {
return MCChatListener.isMinecraftChatEnabled(this);
} }
} }

View file

@ -31,20 +31,33 @@ 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;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class DiscordPlayerSender extends DiscordSenderBase implements Player { public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer<DiscordPlayerSender> {
protected Player player; protected Player player;
// protected @Delegate(excludes = ProjectileSource.class) Player player; private @Getter VanillaCommandListener<DiscordPlayerSender> vanillaCmdListener;
// protected @Delegate(excludes = { ProjectileSource.class, Permissible.class }) Player player;
// protected @Delegate(excludes = { ProjectileSource.class, CommandSender.class }) Player player;
public DiscordPlayerSender(IUser user, IChannel channel, Player player) { public DiscordPlayerSender(IUser user, IChannel channel, Player player) {
super(user, channel); super(user, channel);
this.player = player; this.player = player;
vanillaCmdListener = new VanillaCommandListener<DiscordPlayerSender>(this);
}
@Override
public void sendMessage(String message) {
player.sendMessage(message);
super.sendMessage(message);
}
@Override
public void sendMessage(String[] messages) {
player.sendMessage(messages);
super.sendMessage(messages);
} }
@Override @Override

View file

@ -256,7 +256,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener<ReadyEvent> {
if (channel == chatchannel) if (channel == chatchannel)
MCChatListener.resetLastMessage(); // If this is a chat message, it'll be set again MCChatListener.resetLastMessage(); // If this is a chat message, it'll be set again
final String content = TBMCCoreAPI.IsTestServer() && channel != chatchannel || channel == botroomchannel // Both are the same for testing final String content = TBMCCoreAPI.IsTestServer() && channel != chatchannel || channel == botroomchannel // Both are the same for testing
? "*The following message is from a test server*\n" + message : message; || channel.isPrivate() //
? "*The following message is from a test server*\n" + message : message;
return perform( return perform(
() -> embed == null ? channel.sendMessage(content) : channel.sendMessage(content, embed, false)); () -> embed == null ? channel.sendMessage(content) : channel.sendMessage(content, embed, false));
} catch (Exception e) { } catch (Exception e) {

View file

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

View file

@ -1,9 +1,9 @@
package buttondevteam.discordplugin.commands; package buttondevteam.discordplugin.commands;
import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.discordplugin.listeners.MCChatListener;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.PlayerData;
import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IMessage;
public class MCChatCommand extends DiscordCommandBase { public class MCChatCommand extends DiscordCommandBase {
@ -16,17 +16,18 @@ public class MCChatCommand extends DiscordCommandBase {
@Override @Override
public void run(IMessage message, String args) { public void run(IMessage message, String args) {
if (!message.getChannel().isPrivate()) { if (!message.getChannel().isPrivate()) {
message.reply("This command can only be issued while DMing the bot."); DiscordPlugin.sendMessageToChannel(message.getChannel(),
"This command can only be issued in a direct message with the bot.");
return; return;
} }
try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) { try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) {
PlayerData<Boolean> mcchat = user.minecraftChat(); boolean mcchat = !user.isMinecraftChatEnabled();
mcchat.set(!mcchat.get()); MCChatListener.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user);
MCChatListener.privateMCChat(message.getChannel(), mcchat.get()); DiscordPlugin.sendMessageToChannel(message.getChannel(),
message.reply("Minecraft chat " + (mcchat.get() // "Minecraft chat " + (mcchat //
? "enabled. Use '" + message.getClient().getOurUser().mention() ? "enabled. Use '" + message.getClient().getOurUser().mention()
+ " mcchat' (with the mention) to disable." // + " 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);
} }

View file

@ -59,13 +59,10 @@ public class CommandListener {
if (event.getMessage().getAuthor().isBot()) if (event.getMessage().getAuthor().isBot())
return; return;
final IChannel channel = event.getMessage().getChannel(); final IChannel channel = event.getMessage().getChannel();
if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()) if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))
&& (!channel.isPrivate() || DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent()))
return; return;
if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID())) if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID()))
return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel
if (DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class).minecraftChat().get()) // Let the MCChatListener handle it
return;
event.getMessage().getChannel().setTypingStatus(true); // Fun event.getMessage().getChannel().setTypingStatus(true); // Fun
runCommand(event.getMessage(), true); runCommand(event.getMessage(), true);
} }
@ -84,8 +81,8 @@ public class CommandListener {
DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]); DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]);
} }
if (!event.getMessage().getChannel().isPrivate() // if (!event.getMessage().getChannel().isPrivate() //
|| DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class).minecraftChat() || DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class)
.get() .isMinecraftChatEnabled()
|| DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent()) || DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent())
return; return;
if (event.getMessage().getAuthor().isBot()) if (event.getMessage().getAuthor().isBot())

View file

@ -4,15 +4,21 @@ import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.*;
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
import buttondevteam.lib.*; import buttondevteam.lib.*;
import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.Channel;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
@ -31,50 +37,53 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
return; return;
if (e.getSender() instanceof DiscordSender || e.getSender() instanceof DiscordPlayerSender) if (e.getSender() instanceof DiscordSender || e.getSender() instanceof DiscordPlayerSender)
return; return;
synchronized (this) { Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
final String authorPlayer = DiscordPlugin.sanitizeString(e.getSender() instanceof Player // synchronized (this) {
? ((Player) e.getSender()).getDisplayName() // final String authorPlayer = DiscordPlugin.sanitizeString(e.getSender() instanceof Player //
: e.getSender().getName()); ? ((Player) e.getSender()).getDisplayName() //
final EmbedBuilder embed = new EmbedBuilder().withAuthorName(authorPlayer).withDescription(e.getMessage()) : e.getSender().getName());
.withColor(new Color(e.getChannel().color.getRed(), e.getChannel().color.getGreen(), final EmbedBuilder embed = new EmbedBuilder().withAuthorName(authorPlayer)
e.getChannel().color.getBlue())); .withDescription(e.getMessage()).withColor(new Color(e.getChannel().color.getRed(),
if (e.getSender() instanceof Player) e.getChannel().color.getGreen(), e.getChannel().color.getBlue()));
embed.withAuthorIcon("https://minotar.net/avatar/" + ((Player) e.getSender()).getName() + "/32.png"); if (e.getSender() instanceof Player)
final long nanoTime = System.nanoTime(); embed.withAuthorIcon(
Consumer<LastMsgData> doit = lastmsgdata -> { "https://minotar.net/avatar/" + ((Player) e.getSender()).getName() + "/32.png");
final EmbedObject embedObject = embed.build(); final long nanoTime = System.nanoTime();
String msg = lastmsgdata.channel.isPrivate() ? DiscordPlugin.sanitizeString(e.getChannel().DisplayName) Consumer<LastMsgData> doit = lastmsgdata -> {
: ""; final EmbedObject embedObject = embed.build();
if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() String msg = lastmsgdata.channel.isPrivate()
|| !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) ? DiscordPlugin.sanitizeString(e.getChannel().DisplayName) : "";
|| lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 if (lastmsgdata.message == null || lastmsgdata.message.isDeleted()
|| !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) { || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName())
lastmsgdata.message = DiscordPlugin.sendMessageToChannel(lastmsgdata.channel, msg, embedObject); || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120
lastmsgdata.time = nanoTime; || !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) {
lastmsgdata.mcchannel = e.getChannel(); lastmsgdata.message = DiscordPlugin.sendMessageToChannel(lastmsgdata.channel, msg, embedObject);
lastmsgdata.content = embedObject.description; lastmsgdata.time = nanoTime;
} else lastmsgdata.mcchannel = e.getChannel();
try { lastmsgdata.content = embedObject.description;
lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n" } else
+ embedObject.description;// The message object doesn't get updated try {
final LastMsgData _lastmsgdata = lastmsgdata; lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n"
DiscordPlugin.perform(() -> _lastmsgdata.message.edit(msg, embedObject)); + embedObject.description;// The message object doesn't get updated
} catch (MissingPermissionsException | DiscordException e1) { final LastMsgData _lastmsgdata = lastmsgdata;
TBMCCoreAPI.SendException("An error occured while editing chat message!", e1); DiscordPlugin.perform(() -> _lastmsgdata.message.edit(msg, embedObject));
} } catch (MissingPermissionsException | DiscordException e1) {
}; TBMCCoreAPI.SendException("An error occured while editing chat message!", e1);
if (e.getChannel().equals(Channel.GlobalChat)) }
doit.accept( };
lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel) : lastmsgdata); if (e.getChannel().equals(Channel.GlobalChat))
doit.accept(lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel)
: lastmsgdata);
for (LastMsgData data : lastmsgPerUser) { for (LastMsgData data : lastmsgPerUser) {
final IUser iUser = data.channel.getUsersHere().stream() final IUser iUser = data.channel.getUsersHere().stream()
.filter(u -> u.getLongID() != u.getClient().getOurUser().getLongID()).findFirst().get(); // Doesn't support group DMs .filter(u -> u.getLongID() != u.getClient().getOurUser().getLongID()).findFirst().get(); // Doesn't support group DMs
final DiscordPlayer user = DiscordPlayer.getUser(iUser.getStringID(), DiscordPlayer.class); final DiscordPlayer user = DiscordPlayer.getUser(iUser.getStringID(), DiscordPlayer.class);
if (user.minecraftChat().get() && e.shouldSendTo(getSender(data.channel, iUser, user))) if (user.isMinecraftChatEnabled() && e.shouldSendTo(getSender(data.channel, iUser, user)))
doit.accept(data); doit.accept(data);
}
} }
} // TODO: Author URL }); // TODO: Author URL
} }
private static class LastMsgData { private static class LastMsgData {
@ -121,25 +130,69 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
*/ */
private static ArrayList<LastMsgData> lastmsgPerUser = new ArrayList<LastMsgData>(); private static ArrayList<LastMsgData> lastmsgPerUser = new ArrayList<LastMsgData>();
public static boolean privateMCChat(IChannel channel, boolean start) { public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) {
return start ? lastmsgPerUser.add(new LastMsgData(channel)) TBMCPlayer mcp = dp.getAs(TBMCPlayer.class);
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
val p = Bukkit.getPlayer(mcp.getUUID());
if (start) {
val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID());
ConnectedSenders.put(user.getStringID(), sender);
if (p == null)// Player is offline - If the player is online, that takes precedence
Bukkit.getPluginManager().callEvent(new PlayerJoinEvent(sender, ""));
} else {
val sender = ConnectedSenders.remove(user.getStringID());
if (p == null)// Player is offline - If the player is online, that takes precedence
Bukkit.getPluginManager().callEvent(new PlayerQuitEvent(sender, ""));
}
}
return start //
? lastmsgPerUser.add(new LastMsgData(channel)) //
: lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID());
} }
// ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender
// Offline public chat......x............................................
// Online public chat.......x...........................................x
// Offline private chat.....x.......................x....................
// Online private chat......x.......................x...................x
// If online and enabling private chat, don't login
// If leaving the server and private chat is enabled (has ConnectedPlayer), call login in a task on lowest priority
// If private chat is enabled and joining the server, logout the fake player on highest priority
// If online and disabling private chat, don't logout
// The maps may not contain the senders for UnconnectedSenders
public static boolean isMinecraftChatEnabled(DiscordPlayer dp) {
return lastmsgPerUser.stream().anyMatch(
lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(dp.getDiscordID()));
}
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, DiscordSender> UnconnectedSenders = new HashMap<>(); public static final HashMap<String, DiscordSender> UnconnectedSenders = new HashMap<>();
public static final HashMap<String, DiscordPlayerSender> ConnectedSenders = new HashMap<>(); public static final HashMap<String, DiscordConnectedPlayer> ConnectedSenders = new HashMap<>();
/**
* May contain P&lt;DiscordID&gt; as key for public chat
*/
public static final HashMap<String, DiscordPlayerSender> OnlineSenders = new HashMap<>();
public static short ListC = 0; public static short ListC = 0;
public static void resetLastMessage() { public static void resetLastMessage() {
(lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel) : lastmsgdata).message = null; // Don't set the whole object to null, the player and channel information should (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel) : lastmsgdata).message = null; // Don't set the whole object to null, the player and channel information should
} // be preserved } // be preserved
public static void sendSystemMessageToChat(String msg) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, msg);
for (LastMsgData data : lastmsgPerUser)
DiscordPlugin.sendMessageToChannel(data.channel, msg);
}
@Override // Discord @Override // Discord
public void handle(MessageReceivedEvent event) { public void handle(MessageReceivedEvent event) {
val author = event.getMessage().getAuthor(); val author = event.getMessage().getAuthor();
val user = DiscordPlayer.getUser(author.getStringID(), DiscordPlayer.class); val user = DiscordPlayer.getUser(author.getStringID(), DiscordPlayer.class);
if (!event.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID()) if (!event.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID())
&& !(event.getMessage().getChannel().isPrivate() && user.minecraftChat().get() && !(event.getMessage().getChannel().isPrivate() && user.isMinecraftChatEnabled()
&& !DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent())) && !DiscordPlugin.checkIfSomeoneIsTestingWhileWeArent()))
return; return;
resetLastMessage(); resetLastMessage();
@ -168,12 +221,13 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
if (dsender instanceof DiscordSender && !Arrays.stream(UnconnectedCmds) if (dsender instanceof DiscordSender && !Arrays.stream(UnconnectedCmds)
.anyMatch(s -> cmd.equals(s) || cmd.startsWith(s + " "))) { .anyMatch(s -> cmd.equals(s) || cmd.startsWith(s + " "))) {
// Command not whitelisted // Command not whitelisted
dsender.sendMessage( // TODO dsender.sendMessage("Sorry, you can only access these commands:\n"
"Sorry, you need to be online on the server and have your accounts connected, you can only access these commands:\n" + Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc).collect(Collectors.joining(", "))
+ Arrays.stream(UnconnectedCmds).map(uc -> "/" + uc) + (user.getConnectedID(TBMCPlayer.class) == null
.collect(Collectors.joining(", ")) ? "\nTo access your commands, first please connect your accounts, using @ChromaBot connect in "
+ "\nTo connect your accounts, use @ChromaBot 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`!"
: "\nYou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"));
return; return;
} }
if (lastlist > 5) { if (lastlist > 5) {
@ -185,7 +239,7 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
dsender.sendMessage("Stop it. You know the answer."); dsender.sendMessage("Stop it. You know the answer.");
lastlist = 0; lastlist = 0;
} else } else
Bukkit.dispatchCommand(dsender, cmd); VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd);
lastlistp = (short) Bukkit.getOnlinePlayers().size(); lastlistp = (short) Bukkit.getOnlinePlayers().size();
} else { } else {
if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0) if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0)
@ -216,22 +270,18 @@ public class MCChatListener implements Listener, IListener<MessageReceivedEvent>
} }
} }
/**
* 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 DiscordSenderBase getSender(IChannel channel, final IUser author, DiscordPlayer dp) { private DiscordSenderBase getSender(IChannel channel, final IUser author, DiscordPlayer dp) {
final DiscordSenderBase dsender; val key = (channel.isPrivate() ? "" : "P") + author.getStringID();
Player mcp = null; // Offline players can't really run commands, or can they? No, they can't, really. return Stream.<Supplier<Optional<DiscordSenderBase>>>of( // https://stackoverflow.com/a/28833677/2703239
final String cid; () -> Optional.ofNullable(OnlineSenders.get(key)), // Find first non-null
if ((cid = dp.getConnectedID(TBMCPlayer.class)) != null // Connected? () -> Optional.ofNullable(ConnectedSenders.get(key)), // This doesn't support the public chat, but it'll always return null for it
&& (mcp = Bukkit.getPlayer(UUID.fromString(cid))) != null) { // Execute as ingame player () -> Optional.ofNullable(UnconnectedSenders.get(key)), () -> {
if (!ConnectedSenders.containsKey(author.getStringID())) val dsender = new DiscordSender(author, channel);
ConnectedSenders.put(author.getStringID(), new DiscordPlayerSender(author, channel, mcp)); UnconnectedSenders.put(key, dsender);
dsender = ConnectedSenders.get(author.getStringID()); return Optional.of(dsender);
} else { }).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get();
TBMCPlayer p = dp.getAs(TBMCPlayer.class);
if (!UnconnectedSenders.containsKey(author.getStringID()))
UnconnectedSenders.put(author.getStringID(),
new DiscordSender(author, channel, p == null ? null : p.PlayerName().get())); // Display the playername, if found
dsender = UnconnectedSenders.get(author.getStringID());
}
return dsender;
} }
} }

View file

@ -6,15 +6,20 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.ServerCommandEvent; import org.bukkit.event.server.ServerCommandEvent;
import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.CommandSource;
import buttondevteam.discordplugin.DiscordConnectedPlayer;
import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlayer;
import buttondevteam.discordplugin.DiscordPlayerSender;
import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.discordplugin.commands.ConnectCommand;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.*; import buttondevteam.lib.player.*;
import lombok.val;
import net.ess3.api.events.*; import net.ess3.api.events.*;
import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.IRole;
import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.handle.obj.IUser;
@ -22,9 +27,22 @@ import sx.blah.discord.util.DiscordException;
import sx.blah.discord.util.MissingPermissionsException; import sx.blah.discord.util.MissingPermissionsException;
public class MCListener implements Listener { public class MCListener implements Listener {
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(TBMCPlayerJoinEvent e) { public void onPlayerJoin(TBMCPlayerJoinEvent e) {
final Player p = Bukkit.getPlayer(e.GetPlayer().getUUID()); if (e.getPlayer() instanceof DiscordConnectedPlayer)
return; // Don't show the joined message for the fake player
final Player p = e.getPlayer();
DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class);
if (dp != null) {
val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
MCChatListener.OnlineSenders.put(dp.getDiscordID(),
new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p));
MCChatListener.OnlineSenders.put("P" + dp.getDiscordID(),
new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p));
MCChatListener.ConnectedSenders.values().stream()
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
.ifPresent(dcp -> Bukkit.getPluginManager().callEvent(new PlayerQuitEvent(dcp, "")));
}
if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) {
IUser user = DiscordPlugin.dc IUser user = DiscordPlugin.dc
.getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get())));
@ -32,15 +50,20 @@ public class MCListener implements Listener {
+ " do /discord accept"); + " do /discord accept");
p.sendMessage("§bIf it wasn't you, do /discord decline"); p.sendMessage("§bIf it wasn't you, do /discord decline");
} }
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " joined the game");
e.GetPlayer().PlayerName().get() + " joined the game");
MCChatListener.ListC = 0; MCChatListener.ListC = 0;
} }
@EventHandler @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerLeave(TBMCPlayerQuitEvent e) { public void onPlayerLeave(TBMCPlayerQuitEvent e) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, if (e.getPlayer() instanceof DiscordConnectedPlayer)
e.GetPlayer().PlayerName().get() + " left the game"); return; // Only care about real users
MCChatListener.OnlineSenders.entrySet()
.removeIf(entry -> entry.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()));
MCChatListener.ConnectedSenders.values().stream()
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
.ifPresent(dcp -> Bukkit.getPluginManager().callEvent(new PlayerJoinEvent(dcp, "")));
MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " left the game");
} }
@EventHandler @EventHandler
@ -61,16 +84,15 @@ public class MCListener implements Listener {
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onPlayerDeath(PlayerDeathEvent e) { public void onPlayerDeath(PlayerDeathEvent e) {
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, e.getDeathMessage()); MCChatListener.sendSystemMessageToChat(e.getDeathMessage());
} }
@EventHandler @EventHandler
public void onPlayerAFK(AfkStatusChangeEvent e) { public void onPlayerAFK(AfkStatusChangeEvent e) {
if (e.isCancelled()) if (e.isCancelled() || !e.getAffected().getBase().isOnline())
return; return;
DiscordPlugin.sendMessageToChannel(DiscordPlugin.chatchannel, MCChatListener.sendSystemMessageToChat(DiscordPlugin.sanitizeString(e.getAffected().getBase().getDisplayName())
DiscordPlugin.sanitizeString(e.getAffected().getBase().getDisplayName()) + " is " + " is " + (e.getValue() ? "now" : "no longer") + " AFK.");
+ (e.getValue() ? "now" : "no longer") + " AFK.");
} }
@EventHandler @EventHandler

View file

@ -1,31 +1,19 @@
package buttondevteam.discordplugin.playerfaker; package buttondevteam.discordplugin.playerfaker;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.*;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.PistonMoveReaction; import org.bukkit.block.PistonMoveReaction;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.metadata.MetadataValue; import org.bukkit.metadata.MetadataValue;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.ServerOperator;
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 buttondevteam.discordplugin.DiscordSenderBase;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.Delegate;
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;
@ -40,12 +28,7 @@ public abstract class DiscordEntity extends DiscordSenderBase implements Entity
private HashMap<String, MetadataValue> metadata = new HashMap<String, MetadataValue>(); private HashMap<String, MetadataValue> metadata = new HashMap<String, MetadataValue>();
@Delegate private Location location = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
private PermissibleBase perm = new PermissibleBase(new ServerOperator() {
private @Getter @Setter boolean op;
});
private Location location;
private Vector velocity; private Vector velocity;
private final int entityId; private final int entityId;
private EntityDamageEvent lastDamageCause; private EntityDamageEvent lastDamageCause;

View file

@ -0,0 +1,715 @@
package buttondevteam.discordplugin.playerfaker;
import java.net.InetSocketAddress;
import java.util.*;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.entity.*;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.map.MapView;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.plugin.Plugin;
import org.bukkit.scoreboard.Scoreboard;
import buttondevteam.discordplugin.DiscordPlugin;
import lombok.experimental.Delegate;
import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IUser;
public class DiscordFakePlayer extends DiscordHumanEntity implements Player {
protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid) {
super(user, channel, entityId, uuid);
perm = new PermissibleBase(Bukkit.getOfflinePlayer(uuid));
}
@Delegate
private PermissibleBase perm;
@Override
public String getName() {
return user.getName();
}
@Override
public EntityType getType() {
return EntityType.PLAYER;
}
@Override
public String getCustomName() {
return user.getName();
}
@Override
public void setCustomName(String name) {
}
@Override
public boolean isConversing() {
return false;
}
@Override
public void acceptConversationInput(String input) {
}
@Override
public boolean beginConversation(Conversation conversation) {
return false;
}
@Override
public void abandonConversation(Conversation conversation) {
}
@Override
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
}
@Override
public boolean isOnline() {
return true;// Let's pretend
}
@Override
public boolean isBanned() {
return false;
}
@Override
public boolean isWhitelisted() {
return true;
}
@Override
public void setWhitelisted(boolean value) {
}
@Override
public Player getPlayer() {
return this;
}
@Override
public long getFirstPlayed() {
return 0;
}
@Override
public long getLastPlayed() {
return 0;
}
@Override
public boolean hasPlayedBefore() {
return false;
}
@Override
public Map<String, Object> serialize() {
return new HashMap<>();
}
@Override
public void sendPluginMessage(Plugin source, String channel, byte[] message) {
}
@Override
public Set<String> getListeningPluginChannels() {
return Collections.emptySet();
}
@Override
public String getDisplayName() {
return user.getDisplayName(DiscordPlugin.mainServer);
}
@Override
public void setDisplayName(String name) {
}
@Override
public String getPlayerListName() {
return getName();
}
@Override
public void setPlayerListName(String name) {
}
@Override
public void setCompassTarget(Location loc) {
}
@Override
public Location getCompassTarget() {
return new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
}
@Override
public InetSocketAddress getAddress() {
return null;
}
@Override
public void sendRawMessage(String message) {
sendMessage(message);
}
@Override
public void kickPlayer(String message) {
}
@Override
public void chat(String msg) {
Bukkit.getPluginManager()
.callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers())));
}
@Override
public boolean performCommand(String command) {
return Bukkit.getServer().dispatchCommand(this, command);
}
@Override
public boolean isSneaking() {
return false;
}
@Override
public void setSneaking(boolean sneak) {
}
@Override
public boolean isSprinting() {
return false;
}
@Override
public void setSprinting(boolean sprinting) {
}
@Override
public void saveData() {
}
@Override
public void loadData() {
}
@Override
public void setSleepingIgnored(boolean isSleeping) {
}
@Override
public boolean isSleepingIgnored() {
return false;
}
@Override
public void playNote(Location loc, byte instrument, byte note) {
}
@Override
public void playNote(Location loc, Instrument instrument, Note note) {
}
@Override
public void playSound(Location location, Sound sound, float volume, float pitch) {
}
@Override
public void playSound(Location location, String sound, float volume, float pitch) {
}
@Override
public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) {
}
@Override
public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) {
}
@Override
public void stopSound(Sound sound) {
}
@Override
public void stopSound(String sound) {
}
@Override
public void stopSound(Sound sound, SoundCategory category) {
}
@Override
public void stopSound(String sound, SoundCategory category) {
}
@Override
public void playEffect(Location loc, Effect effect, int data) {
}
@Override
public <T> void playEffect(Location loc, Effect effect, T data) {
}
@Override
public void sendBlockChange(Location loc, Material material, byte data) {
}
@Override
public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
return false;
}
@Override
public void sendBlockChange(Location loc, int material, byte data) {
}
@Override
public void sendSignChange(Location loc, String[] lines) throws IllegalArgumentException {
}
@Override
public void sendMap(MapView map) {
}
@Override
public void updateInventory() {
}
@Override
public void awardAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
}
@Override
public void removeAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
}
@Override
public boolean hasAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
return false;
}
@Override
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic) throws IllegalArgumentException {
}
@Override
public void incrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
}
@Override
public void setStatistic(Statistic statistic, int newValue) throws IllegalArgumentException {
}
@Override
public int getStatistic(Statistic statistic) throws IllegalArgumentException {
return 0;
}
@Override
public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
}
@Override
public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
return 0;
}
@Override
public void incrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException {
}
@Override
public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException {
}
@Override
public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
}
@Override
public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
return 0;
}
@Override
public void incrementStatistic(Statistic statistic, EntityType entityType, int amount)
throws IllegalArgumentException {
}
@Override
public void decrementStatistic(Statistic statistic, EntityType entityType, int amount) {
}
@Override
public void setStatistic(Statistic statistic, EntityType entityType, int newValue) {
}
@Override
public void setPlayerTime(long time, boolean relative) {
}
@Override
public long getPlayerTime() {
return 0;
}
@Override
public long getPlayerTimeOffset() {
return 0;
}
@Override
public boolean isPlayerTimeRelative() {
return false;
}
@Override
public void resetPlayerTime() {
}
@Override
public void setPlayerWeather(WeatherType type) {
}
@Override
public WeatherType getPlayerWeather() {
return null;
}
@Override
public void resetPlayerWeather() {
}
@Override
public void giveExp(int amount) {
}
@Override
public void giveExpLevels(int amount) {
}
@Override
public float getExp() {
return 0;
}
@Override
public void setExp(float exp) {
}
@Override
public int getLevel() {
return 0;
}
@Override
public void setLevel(int level) {
}
@Override
public int getTotalExperience() {
return 0;
}
@Override
public void setTotalExperience(int exp) {
}
@Override
public float getExhaustion() {
return 0;
}
@Override
public void setExhaustion(float value) {
}
@Override
public float getSaturation() {
return 0;
}
@Override
public void setSaturation(float value) {
}
@Override
public int getFoodLevel() {
return 0;
}
@Override
public void setFoodLevel(int value) {
}
@Override
public Location getBedSpawnLocation() {
return null;
}
@Override
public void setBedSpawnLocation(Location location) {
}
@Override
public void setBedSpawnLocation(Location location, boolean force) {
}
@Override
public boolean getAllowFlight() {
return false;
}
@Override
public void setAllowFlight(boolean flight) {
}
@Override
public void hidePlayer(Player player) {
}
@Override
public void showPlayer(Player player) {
}
@Override
public boolean canSee(Player player) { // Nobody can see them
return false;
}
@Override
public boolean isFlying() {
return false;
}
@Override
public void setFlying(boolean value) {
}
@Override
public void setFlySpeed(float value) throws IllegalArgumentException {
}
@Override
public void setWalkSpeed(float value) throws IllegalArgumentException {
}
@Override
public float getFlySpeed() {
return 0;
}
@Override
public float getWalkSpeed() {
return 0;
}
@Override
public void setTexturePack(String url) {
}
@Override
public void setResourcePack(String url) {
}
@Override
public void setResourcePack(String url, byte[] hash) {
}
@Override
public Scoreboard getScoreboard() {
return null;
}
@Override
public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException {
}
@Override
public boolean isHealthScaled() {
return false;
}
@Override
public void setHealthScaled(boolean scale) {
}
@Override
public void setHealthScale(double scale) throws IllegalArgumentException {
}
@Override
public double getHealthScale() {
return 1;
}
@Override
public Entity getSpectatorTarget() {
return null;
}
@Override
public void setSpectatorTarget(Entity entity) {
}
@Override
public void sendTitle(String title, String subtitle) {
}
@Override
public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
}
@Override
public void resetTitle() {
}
@Override
public void spawnParticle(Particle particle, Location location, int count) {
}
@Override
public void spawnParticle(Particle particle, double x, double y, double z, int count) {
}
@Override
public <T> void spawnParticle(Particle particle, Location location, int count, T data) {
}
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, T data) {
}
@Override
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
double offsetZ) {
}
@Override
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
double offsetY, double offsetZ) {
}
@Override
public <T> void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
double offsetZ, T data) {
}
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
double offsetY, double offsetZ, T data) {
}
@Override
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
double offsetZ, double extra) {
}
@Override
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
double offsetY, double offsetZ, double extra) {
}
@Override
public <T> void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
double offsetZ, double extra, T data) {
}
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
double offsetY, double offsetZ, double extra, T data) {
}
@Override
public AdvancementProgress getAdvancementProgress(Advancement advancement) { // TODO: Test
return null;
}
@Override
public String getLocale() {
return null;
}
@Override
public Player.Spigot spigot() {
return new Player.Spigot();
}
}

View file

@ -6,16 +6,10 @@ import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.*;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.InventoryView.Property; import org.bukkit.inventory.InventoryView.Property;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.MainHand;
import org.bukkit.inventory.Merchant;
import org.bukkit.inventory.PlayerInventory;
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;
@ -25,15 +19,18 @@ public abstract class DiscordHumanEntity extends DiscordLivingEntity implements
super(user, channel, entityId, uuid); super(user, channel, entityId, uuid);
} }
private PlayerInventory inv = new DiscordPlayerInventory(this);
@Override @Override
public PlayerInventory getInventory() { // TODO public PlayerInventory getInventory() {
return null; return inv;
} }
private Inventory enderchest = new DiscordInventory(this);
@Override @Override
public Inventory getEnderChest() { public Inventory getEnderChest() {
// TODO Auto-generated method stub return enderchest;
return null;
} }
@Override @Override
@ -47,159 +44,125 @@ public abstract class DiscordHumanEntity extends DiscordLivingEntity implements
} }
@Override @Override
public InventoryView getOpenInventory() { public InventoryView getOpenInventory() { // TODO: Test
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public InventoryView openInventory(Inventory inventory) { public InventoryView openInventory(Inventory inventory) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public InventoryView openWorkbench(Location location, boolean force) { public InventoryView openWorkbench(Location location, boolean force) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public InventoryView openEnchanting(Location location, boolean force) { public InventoryView openEnchanting(Location location, boolean force) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void openInventory(InventoryView inventory) { public void openInventory(InventoryView inventory) {
// TODO Auto-generated method stub
} }
@Override @Override
public InventoryView openMerchant(Villager trader, boolean force) { public InventoryView openMerchant(Villager trader, boolean force) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public InventoryView openMerchant(Merchant merchant, boolean force) { public InventoryView openMerchant(Merchant merchant, boolean force) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void closeInventory() { public void closeInventory() {
// TODO Auto-generated method stub
} }
@Override @Override
public ItemStack getItemInHand() { public ItemStack getItemInHand() { // TODO: Test all ItemStack methods
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setItemInHand(ItemStack item) { public void setItemInHand(ItemStack item) {
// TODO Auto-generated method stub
} }
@Override @Override
public ItemStack getItemOnCursor() { public ItemStack getItemOnCursor() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setItemOnCursor(ItemStack item) { public void setItemOnCursor(ItemStack item) {
// TODO Auto-generated method stub
} }
@Override @Override
public boolean hasCooldown(Material material) { public boolean hasCooldown(Material material) {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public int getCooldown(Material material) { public int getCooldown(Material material) {
// TODO Auto-generated method stub
return 0; return 0;
} }
@Override @Override
public void setCooldown(Material material, int ticks) { public void setCooldown(Material material, int ticks) {
// TODO Auto-generated method stub
} }
@Override @Override
public boolean isSleeping() { public boolean isSleeping() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public int getSleepTicks() { public int getSleepTicks() {
// TODO Auto-generated method stub
return 0; return 0;
} }
@Override @Override
public GameMode getGameMode() { public GameMode getGameMode() {
// TODO Auto-generated method stub return GameMode.SPECTATOR;
return null;
} }
@Override @Override
public void setGameMode(GameMode mode) { public void setGameMode(GameMode mode) {
// TODO Auto-generated method stub
} }
@Override @Override
public boolean isBlocking() { public boolean isBlocking() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public boolean isHandRaised() { public boolean isHandRaised() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public int getExpToLevel() { public int getExpToLevel() {
// TODO Auto-generated method stub
return 0; return 0;
} }
@Override @Override
public Entity getShoulderEntityLeft() { public Entity getShoulderEntityLeft() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setShoulderEntityLeft(Entity entity) { public void setShoulderEntityLeft(Entity entity) {
// TODO Auto-generated method stub
} }
@Override @Override
public Entity getShoulderEntityRight() { public Entity getShoulderEntityRight() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setShoulderEntityRight(Entity entity) { public void setShoulderEntityRight(Entity entity) {
// TODO Auto-generated method stub
} }
} }

View file

@ -0,0 +1,212 @@
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.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class DiscordInventory implements Inventory {
public DiscordInventory(DiscordHumanEntity holder) {
this.holder = holder;
}
@Override
public int getSize() {
return 0;
}
@Override
public int getMaxStackSize() {
return 0;
}
@Override
public void setMaxStackSize(int size) {
}
@Override
public String getName() {
return "Player inventory";
}
@Override
public ItemStack getItem(int index) {
return null;
}
@Override
public HashMap<Integer, ItemStack> addItem(ItemStack... items) throws IllegalArgumentException { // Can't add anything
return new HashMap<>(
IntStream.range(0, items.length).mapToObj(i -> i).collect(Collectors.toMap(i -> i, i -> items[i])));
}
@Override
public HashMap<Integer, ItemStack> removeItem(ItemStack... items) throws IllegalArgumentException {
return new HashMap<>(
IntStream.range(0, items.length).mapToObj(i -> i).collect(Collectors.toMap(i -> i, i -> items[i])));
}
@Override
public ItemStack[] getContents() {
return new ItemStack[0];
}
@Override
public void setContents(ItemStack[] items) throws IllegalArgumentException {
if (items.length > 0)
throw new IllegalArgumentException("This inventory does not support items");
}
@Override
public ItemStack[] getStorageContents() {
return new ItemStack[0];
}
@Override
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
if (items.length > 0)
throw new IllegalArgumentException("This inventory does not support items");
}
@Override
public boolean contains(int materialId) {
return false;
}
@Override
public boolean contains(Material material) throws IllegalArgumentException {
return false;
}
@Override
public boolean contains(ItemStack item) {
return false;
}
@Override
public boolean contains(int materialId, int amount) {
return false;
}
@Override
public boolean contains(Material material, int amount) throws IllegalArgumentException {
return false;
}
@Override
public boolean contains(ItemStack item, int amount) {
return false;
}
@Override
public boolean containsAtLeast(ItemStack item, int amount) {
return false;
}
@Override
public HashMap<Integer, ? extends ItemStack> all(int materialId) {
return new HashMap<>();
}
@Override
public HashMap<Integer, ? extends ItemStack> all(Material material) throws IllegalArgumentException {
return new HashMap<>();
}
@Override
public HashMap<Integer, ? extends ItemStack> all(ItemStack item) {
return new HashMap<>();
}
@Override
public int first(int materialId) {
return -1;
}
@Override
public int first(Material material) throws IllegalArgumentException {
return -1;
}
@Override
public int first(ItemStack item) {
return -1;
}
@Override
public int firstEmpty() {
return -1;
}
@Override
public void remove(int materialId) {
}
@Override
public void remove(Material material) throws IllegalArgumentException {
}
@Override
public void remove(ItemStack item) {
}
@Override
public void clear(int index) {
}
@Override
public void clear() {
}
@Override
public List<HumanEntity> getViewers() {
return new ArrayList<>(0);
}
@Override
public String getTitle() {
return "Player inventory";
}
@Override
public InventoryType getType() {
return InventoryType.PLAYER;
}
private ListIterator<ItemStack> iterator = new ArrayList<ItemStack>(0).listIterator();
@Override
public ListIterator<ItemStack> iterator() {
return iterator;
}
@Override
public ListIterator<ItemStack> iterator(int index) {
return iterator;
}
@Override
public Location getLocation() {
return holder.getLocation();
}
@Override
public void setItem(int index, ItemStack item) {
}
private HumanEntity holder;
@Override
public HumanEntity getHolder() {
return holder;
}
}

View file

@ -0,0 +1,105 @@
package buttondevteam.discordplugin.playerfaker;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
public class DiscordPlayerInventory extends DiscordInventory implements PlayerInventory {
public DiscordPlayerInventory(DiscordHumanEntity holder) {
super(holder);
}
@Override
public ItemStack[] getArmorContents() {
return new ItemStack[0];
}
@Override
public ItemStack[] getExtraContents() {
return new ItemStack[0];
}
@Override
public ItemStack getHelmet() {
return null;
}
@Override
public ItemStack getChestplate() {
return null;
}
@Override
public ItemStack getLeggings() {
return null;
}
@Override
public ItemStack getBoots() {
return null;
}
@Override
public void setArmorContents(ItemStack[] items) {
}
@Override
public void setExtraContents(ItemStack[] items) {
}
@Override
public void setHelmet(ItemStack helmet) {
}
@Override
public void setChestplate(ItemStack chestplate) {
}
@Override
public void setLeggings(ItemStack leggings) {
}
@Override
public void setBoots(ItemStack boots) {
}
@Override
public ItemStack getItemInMainHand() {
return null;
}
@Override
public void setItemInMainHand(ItemStack item) {
}
@Override
public ItemStack getItemInOffHand() {
return null;
}
@Override
public void setItemInOffHand(ItemStack item) {
}
@Override
public ItemStack getItemInHand() {
return null;
}
@Override
public void setItemInHand(ItemStack stack) {
}
@Override
public int getHeldItemSlot() {
return 0;
}
@Override
public void setHeldItemSlot(int slot) {
}
@Override
public int clear(int id, int data) {
return 0;
}
}

View file

@ -0,0 +1,110 @@
package buttondevteam.discordplugin.playerfaker;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_12_R1.command.VanillaCommandWrapper;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import buttondevteam.discordplugin.DiscordSenderBase;
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 {
private @Getter T player;
private Player bukkitplayer;
/**
* This constructor will only send raw vanilla messages to the sender in plain text.
*
* @param player
* The Discord sender player (the wrapper)
*/
public VanillaCommandListener(T player) {
this.player = player;
this.bukkitplayer = null;
}
/**
* This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player.
*
* @param player
* The Discord sender player (the wrapper)
* @param bukkitplayer
* The Bukkit player to send the raw message to
*/
public VanillaCommandListener(T player, Player bukkitplayer) {
this.player = player;
this.bukkitplayer = bukkitplayer;
if (!(bukkitplayer instanceof CraftPlayer))
throw new ClassCastException("bukkitplayer must be a Bukkit player!");
}
@Override
public MinecraftServer C_() {
return ((CraftServer) Bukkit.getServer()).getServer();
}
@Override
public boolean a(int oplevel, String cmd) {
// return oplevel <= 2; // Value from CommandBlockListenerAbstract, found what it is in EntityPlayer - Wait, that'd always allow OP commands
return oplevel == 0 || player.isOp();
}
@Override
public String getName() {
return player.getName();
}
@Override
public World getWorld() {
return ((CraftWorld) player.getWorld()).getHandle();
}
@Override
public void sendMessage(IChatBaseComponent arg0) {
player.sendMessage(arg0.toPlainText());
if (bukkitplayer != null)
((CraftPlayer) bukkitplayer).getHandle().sendMessage(arg0);
}
public static boolean runBukkitOrVanillaCommand(DiscordSenderBase dsender, String cmdstr) {
val cmd = ((CraftServer) Bukkit.getServer()).getCommandMap().getCommand(cmdstr.split(" ")[0].toLowerCase());
if (!(dsender instanceof Player) || !(cmd instanceof VanillaCommandWrapper))
return Bukkit.dispatchCommand(dsender, cmdstr); // Unconnected users are treated well in vanilla cmds
if (!(dsender instanceof IMCPlayer))
throw new ClassCastException(
"dsender needs to implement IMCPlayer to use vanilla commands as it implements Player.");
IMCPlayer<?> sender = (IMCPlayer<?>) dsender; // Don't use val on recursive interfaces :P
val vcmd = (VanillaCommandWrapper) cmd;
if (!vcmd.testPermission(sender))
return true;
ICommandListener icommandlistener = sender.getVanillaCmdListener();
String[] args = cmdstr.split(" ");
args = Arrays.copyOfRange(args, 1, args.length);
try {
vcmd.dispatchVanillaCommand(sender, icommandlistener, args);
} catch (CommandException commandexception) {
// Taken from CommandHandler
ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.getArgs());
chatmessage.getChatModifier().setColor(EnumChatFormat.RED);
icommandlistener.sendMessage(chatmessage);
}
return true;
}
}