From cd2132ba45afe0ef77ed9be310423a6521ba898a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 11 Sep 2020 22:27:22 +0200 Subject: [PATCH] Fix ServerWatcher, mcchat works --- pom.xml | 13 ++++++- .../discordplugin/DiscordPlugin.java | 12 ++++++ .../playerfaker/ServerWatcher.java | 39 ++++++++++++++++--- .../playerfaker/VanillaCommandListener15.java | 2 +- .../org.mockito.plugins.MockMaker | 2 +- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 3c1de6e..4b4d005 100755 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,10 @@ Reactor-Tools https://repo.spring.io/milestone --> + + papermc + https://papermc.io/repo/repository/maven-public/ + @@ -141,6 +145,12 @@ 1.14.4-R0.1-SNAPSHOT provided + + com.destroystokyo.paper + paper + 1.16.3-R0.1-SNAPSHOT + provided + com.discord4j @@ -201,10 +211,11 @@ master-SNAPSHOT provided + org.mockito mockito-core - 3.0.0 + 3.5.10 org.mockito diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 0c983cc..f99bcbd 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -35,6 +35,7 @@ import lombok.val; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.mockito.internal.util.MockUtil; import reactor.core.publisher.Mono; import java.awt.*; @@ -101,6 +102,17 @@ public class DiscordPlugin extends ButtonPlugin { return getIConfig().getData("inviteLink", ""); } + @Override + public void onLoad() { //Needed by ServerWatcher + var thread = Thread.currentThread(); + getLogger().info("Setting context class loader for " + thread); + var cl = thread.getContextClassLoader(); + thread.setContextClassLoader(getClassLoader()); + MockUtil.isMock(null); //Load MockUtil to load Mockito plugins + getLogger().info("Restoring context class loader"); + thread.setContextClassLoader(cl); + } + @Override public void pluginEnable() { try { diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java b/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java index ed63c2e..bb039f7 100644 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java @@ -1,12 +1,14 @@ package buttondevteam.discordplugin.playerfaker; import buttondevteam.discordplugin.mcchat.MCChatUtils; +import com.destroystokyo.paper.profile.CraftPlayerProfile; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.entity.Player; import org.mockito.Mockito; +import java.lang.reflect.Modifier; import java.util.*; public class ServerWatcher { @@ -19,8 +21,17 @@ public class ServerWatcher { serverField.setAccessible(true); if (enable) { var serverClass = Bukkit.getServer().getClass(); - var mock = Mockito.mock(serverClass, Mockito.withSettings() - .stubOnly().defaultAnswer(invocation -> { + //var mockMaker = new InlineByteBuddyMockMaker(); + //System.setProperty("net.bytebuddy.experimental", "true"); + /*try { + var resources = cl.getResources("mockito-extensions/" + MockMaker.class.getName()); + System.out.println("Found resources: " + resources); + Iterables.toIterable(resources).forEach(resource -> System.out.println("Resource: " + resource)); + } catch (IOException e) { + throw new IllegalStateException("Failed to load " + MockMaker.class, e); + }*/ + var settings = Mockito.withSettings().stubOnly() + .defaultAnswer(invocation -> { var method = invocation.getMethod(); int pc = method.getParameterCount(); Player player = null; @@ -38,18 +49,34 @@ public class ServerWatcher { break; case "getOnlinePlayers": if (playerList == null) { - @SuppressWarnings("unchecked") var list = (List) invocation.callRealMethod(); + @SuppressWarnings("unchecked") var list = (List) method.invoke(origServer, invocation.getArguments()); playerList = new AppendListView<>(list, fakePlayers); } return playerList; + case "createProfile": //Paper's method, casts the player to a CraftPlayer + if (pc == 2) { + UUID uuid = invocation.getArgument(0); + String name = invocation.getArgument(1); + player = uuid != null ? MCChatUtils.LoggedInPlayers.get(uuid) : null; + if (player == null && name != null) + player = MCChatUtils.LoggedInPlayers.values().stream() + .filter(dcp -> dcp.getName().equalsIgnoreCase(name)).findAny().orElse(null); + if (player != null) + return new CraftPlayerProfile(player.getUniqueId(), player.getName()); + } + break; } if (player != null) return player; - return invocation.callRealMethod(); - })); + return method.invoke(origServer, invocation.getArguments()); + }); + //var mock = mockMaker.createMock(settings, MockHandlerFactory.createMockHandler(settings)); + //thread.setContextClassLoader(cl); + var mock = Mockito.mock(serverClass, settings); var originalServer = serverField.get(null); for (var field : serverClass.getFields()) //Copy public fields, private fields aren't accessible directly anyways - field.set(mock, field.get(originalServer)); + if (!Modifier.isFinal(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) + field.set(mock, field.get(originalServer)); serverField.set(null, mock); origServer = (Server) originalServer; } else if (origServer != null) diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener15.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener15.java index e0ea99b..66dc935 100644 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener15.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener15.java @@ -79,7 +79,7 @@ public class VanillaCommandListener15 var server = Bukkit.getServer(); var cmap = (SimpleCommandMap) server.getClass().getMethod("getCommandMap").invoke(server); val cmd = cmap.getCommand(cmdstr.split(" ")[0].toLowerCase()); - if (!(dsender instanceof Player) || !vcwcl.isAssignableFrom(cmd.getClass())) + if (!(dsender instanceof Player) || cmd == null || !vcwcl.isAssignableFrom(cmd.getClass())) return Bukkit.dispatchCommand(dsender, cmdstr); // Unconnected users are treated well in vanilla cmds if (!(dsender instanceof IMCPlayer)) diff --git a/src/main/resources/mockito-extensions/org.mockito.plugins.MockMaker b/src/main/resources/mockito-extensions/org.mockito.plugins.MockMaker index ca6ee9c..7da34da 100644 --- a/src/main/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ b/src/main/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -1 +1 @@ -mock-maker-inline \ No newline at end of file +org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker \ No newline at end of file