Merge branch 'v1_7_R4-support'

This commit is contained in:
Jitse Boonstra
2019-02-15 21:08:14 +01:00
39 changed files with 888 additions and 288 deletions
+4
View File
@@ -4,6 +4,10 @@ cache:
- $HOME/.m2/ - $HOME/.m2/
install: install:
- wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar - wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
- wget http://central.maven.org/maven2/io/netty/netty-all/4.1.33.Final/netty-all-4.1.33.Final.jar
- mvn install:install-file -Dfile=netty-all-4.1.33.Final.jar -DgroupId=io.netty -DartifactId=netty-all -Dversion=4.1.33.Final -Dpackaging=jar
- wget https://github.com/Sarabveer/CraftBukkit-Spigot-Binary/blob/master/spigot-1.7.10-R0.1/spigot-1.7.10-R0.1-1649.jar
- mvn install:install-file -Dfile=spigot-1.7.10-R0.1-1649.jar -DgroupId=org.spigotmc -DartifactId=spigot -Dversion=1.7.10-R0.1-SNAPSHOT -Dpackaging=jar
- ls $HOME/.m2/repository/org/spigotmc/spigot/1.8-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.8-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8 >> /dev/null 2>&1
- ls $HOME/.m2/repository/org/spigotmc/spigot/1.8.3-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8.3 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.8.3-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8.3 >> /dev/null 2>&1
- ls $HOME/.m2/repository/org/spigotmc/spigot/1.8.8-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8.8 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.8.8-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.8.8 >> /dev/null 2>&1
+21 -7
View File
@@ -3,16 +3,14 @@ NPCLib Basic non-player character library.<br>
[![Release](https://jitpack.io/v/JitseB/NPCLib.svg)](https://github.com/JitseB/NPCLib/releases) [![Release](https://jitpack.io/v/JitseB/NPCLib.svg)](https://github.com/JitseB/NPCLib/releases)
[![Build Status](https://travis-ci.com/JitseB/NPCLib.svg?branch=master)](https://travis-ci.com/JitseB/NPCLib) [![Build Status](https://travis-ci.com/JitseB/NPCLib.svg?branch=master)](https://travis-ci.com/JitseB/NPCLib)
[![JDK](https://img.shields.io/badge/Using-Java%208-blue.svg)](http://jdk.java.net/8/) [![JDK](https://img.shields.io/badge/Using-Java%208-blue.svg)](http://jdk.java.net/8/)
[![Versions](https://img.shields.io/badge/MC-1.8%20--%201.13.2-blue.svg)](https://github.com/JitseB/NPCLib/releases) [![Versions](https://img.shields.io/badge/MC-1.7.10%20--%201.13.2-blue.svg)](https://github.com/JitseB/NPCLib/releases)
[![Thread](https://img.shields.io/badge/SpigotMC-Resource-orange.svg)](https://www.spigotmc.org/resources/npclib.55884/)
[![Thread](https://img.shields.io/badge/SpigotMC-Thread-orange.svg)](https://www.spigotmc.org/threads/npclib--basic-non-player-character-library.314460/)
= =
This is an API made specifically for spigot servers (Minecraft). Current supported versions: **1.8 - 1.13.2**. Lightweight replacement for Citizens. NPCLib only uses packets instead of registering the entity in the actual Minecraft server. This is an API made specifically for spigot servers (Minecraft). Current supported versions: **1.7.10 - 1.13.2**. Lightweight replacement for Citizens. NPCLib only uses packets instead of registering the entity in the actual Minecraft server.
**SpigotMC Resource** https://www.spigotmc.org/resources/npclib.55884/ <br>
**SpigotMC Thread** https://www.spigotmc.org/threads/npclib--basic-non-player-character-library.314460/
**Preview** (click to play video)
### Preview (click to play video)
[![YouTube Video](http://img.youtube.com/vi/LqwdqIxPIvE/0.jpg)](http://www.youtube.com/watch?v=LqwdqIxPIvE "NPCLib Basic non-player character library (Minecraft).") [![YouTube Video](http://img.youtube.com/vi/LqwdqIxPIvE/0.jpg)](http://www.youtube.com/watch?v=LqwdqIxPIvE "NPCLib Basic non-player character library (Minecraft).")
## Donate ## Donate
@@ -21,6 +19,21 @@ This is an API made specifically for spigot servers (Minecraft). Current support
Alternatively, you can help the project by starring the repository or telling others about NPCLib. :smile: Alternatively, you can help the project by starring the repository or telling others about NPCLib. :smile:
## Roadmap
- :heavy_check_mark: Spawn and destroy NPC (version 1.8 - latest).
- :heavy_check_mark: Autohide NPC when out of range.
- :heavy_check_mark: Add support for 1.7.10 (1.7 R4).
- :construction: Option to rotate head to player (when nearby).
- :construction: Add support for animated text (update-able holograms).
- :x: Give NPC armor and items in hand.
- :x: Multi-line text support for 1.7.10 (1.7 R4).
### Roadmad Legend
:heavy_check_mark: Feature is fully implemented and functional. <br>
:construction: Feature is still in development (or experimental). <br>
:x: Development of feature has yet to be started. <br>
## Developers ## Developers
### Usage ### Usage
@@ -40,6 +53,7 @@ Alternatively, you can put `npclib-plugin-v*.jar` under your `plugins` folder. B
```Java ```Java
// Creating a new NPC instance. // Creating a new NPC instance.
// MC 1.7.10 (1.7 R4) only supports single-line text.
NPC npc = lib.createNPC(skin, lines); NPC npc = lib.createNPC(skin, lines);
// Then let the library generate the necessary packets. // Then let the library generate the necessary packets.
+7 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib</artifactId> <artifactId>npclib</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-api</artifactId> <artifactId>npclib-api</artifactId>
@@ -19,6 +19,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>net.jitse</groupId>
<artifactId>npclib-nms-v1_7_R4</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms-v1_8_R1</artifactId> <artifactId>npclib-nms-v1_8_R1</artifactId>
+10 -2
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib</artifactId> <artifactId>npclib</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-commons</artifactId> <artifactId>npclib-commons</artifactId>
@@ -16,8 +16,16 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId> <artifactId>spigot</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version> <version>1.7.10-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Netty (implemented in version above 1.7.10) -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.33.Final</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>
@@ -0,0 +1,325 @@
package com.comphenix.tinyprotocol;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.channel.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Minimized version of TinyProtocol by Kristian suited for NPCLib.
*/
public abstract class LegacyTinyProtocol {
private static final AtomicInteger ID = new AtomicInteger(0);
// Used in order to lookup a channel
private static final Reflection.MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final Reflection.FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
private static final Reflection.FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
private static final Reflection.FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
private static final Reflection.FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final Reflection.FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
private static final Reflection.MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
// Packets we have to intercept
private static final Class<?> PACKET_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol");
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final Reflection.FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
private static final Reflection.FieldAccessor<Integer> protocolId = Reflection.getField(PACKET_SET_PROTOCOL, int.class, 0);
private static final Reflection.FieldAccessor<Enum> protocolType = Reflection.getField(PACKET_SET_PROTOCOL, Enum.class, 0);
// Speedup channel lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
private Map<Channel, Integer> protocolLookup = new MapMaker().weakKeys().makeMap();
private Listener listener;
// Channels that have already been removed
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
// List of network markers
private List<Object> networkManagers;
// Injected channel handlers
private List<Channel> serverChannels = Lists.newArrayList();
private ChannelInboundHandlerAdapter serverChannelHandler;
private ChannelInitializer<Channel> beginInitProtocol;
private ChannelInitializer<Channel> endInitProtocol;
// Current handler name
private String handlerName;
private volatile boolean closed;
protected Plugin plugin;
protected LegacyTinyProtocol(final Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
// Prepare existing players
registerBukkitEvents();
try {
System.out.println("[NPCLib] Attempting to inject into netty.");
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("[NPCLib] Attempting to delay injection.");
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("[NPCLib] Injection complete.");
}
}.runTask(plugin);
}
}
private void createServerChannelHandler() {
// Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() {
@SuppressWarnings("all")
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
// Stop injecting channels
if (!closed) {
channel.eventLoop().submit(() -> injectChannelInternal(channel));
}
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Cannot inject incomming channel " + channel, e);
}
}
};
// This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() {
@SuppressWarnings("all")
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol);
}
};
serverChannelHandler = new ChannelInboundHandlerAdapter() {
@SuppressWarnings("all")
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
private void registerBukkitEvents() {
listener = new Listener() {
@SuppressWarnings("unused")
@EventHandler(priority = EventPriority.LOWEST)
public final void onPlayerLogin(PlayerJoinEvent e) {
if (closed)
return;
Channel channel = getChannel(e.getPlayer());
// Don't inject players that have been explicitly uninjected
if (!uninjectedChannels.contains(channel)) {
injectPlayer(e.getPlayer());
}
}
@SuppressWarnings("unused")
@EventHandler
public final void onPluginDisable(PluginDisableEvent e) {
if (e.getPlugin().equals(plugin)) {
close();
}
}
};
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
}
@SuppressWarnings("unchecked")
private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
Object serverConnection = getServerConnection.get(mcServer);
boolean looking = true;
// We need to synchronize against this list
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
createServerChannelHandler();
// Find the correct list, or implicitly throw an exception
for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) {
//if (!ChannelFuture.class.isInstance(item))
// break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
serverChannels.add(serverChannel);
serverChannel.pipeline().addFirst(serverChannelHandler);
System.out.println("[NPCLib] Server channel handler injected (" + serverChannel + ")");
looking = false;
}
}
}
private void unregisterChannelHandler() {
if (serverChannelHandler == null)
return;
for (Channel serverChannel : serverChannels) {
final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler
serverChannel.eventLoop().execute(() -> {
try {
pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) {
// That's fine
}
});
}
}
private void registerPlayers(Plugin plugin) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
injectPlayer(player);
}
}
public Object onPacketInAsync(Player sender, Object packet) {
return packet;
}
private void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player;
}
private PacketInterceptor injectChannelInternal(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
uninjectedChannels.remove(channel);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
private Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName());
// Lookup channel again
if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player));
Object manager = getManager.get(connection);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
}
return channel;
}
private void uninjectChannel(final Channel channel) {
// No need to guard against this if we're closing
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
}
private void close() {
if (!closed) {
closed = true;
// Remove our handlers
for (Player player : plugin.getServer().getOnlinePlayers()) {
uninjectChannel(getChannel(player));
}
// Clean up Bukkit
HandlerList.unregisterAll(listener);
unregisterChannelHandler();
}
}
private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event
public volatile Player player;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Intercept channel
final Channel channel = ctx.channel();
if (PACKET_LOGIN_IN_START.isInstance(msg)) {
GameProfile profile = getGameProfile.get(msg);
channelLookup.put(profile.getName(), channel);
} else if (PACKET_SET_PROTOCOL.isInstance(msg)) {
String protocol = protocolType.get(msg).name();
if (protocol.equalsIgnoreCase("LOGIN")) {
protocolLookup.put(channel, protocolId.get(msg));
}
}
try {
msg = onPacketInAsync(player, msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Error in onPacketInAsync().", e);
}
if (msg != null) {
super.channelRead(ctx, msg);
}
}
}
}
@@ -4,7 +4,6 @@ import com.comphenix.tinyprotocol.Reflection.FieldAccessor;
import com.comphenix.tinyprotocol.Reflection.MethodInvoker; import com.comphenix.tinyprotocol.Reflection.MethodInvoker;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker; import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
import io.netty.channel.*; import io.netty.channel.*;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -22,11 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
* Represents a very tiny alternative to ProtocolLib. * Minimized version of TinyProtocol by Kristian suited for NPCLib.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/ */
public abstract class TinyProtocol { public abstract class TinyProtocol {
private static final AtomicInteger ID = new AtomicInteger(0); private static final AtomicInteger ID = new AtomicInteger(0);
@@ -46,7 +41,8 @@ public abstract class TinyProtocol {
// Packets we have to intercept // Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart"); private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0); private static final FieldAccessor getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START,
Reflection.getClass("com.mojang.authlib.GameProfile"), 0);
// Speedup channel lookup // Speedup channel lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap(); private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
@@ -67,38 +63,32 @@ public abstract class TinyProtocol {
// Current handler name // Current handler name
private String handlerName; private String handlerName;
protected volatile boolean closed; private volatile boolean closed;
protected Plugin plugin; protected Plugin plugin;
/** protected TinyProtocol(final Plugin plugin) {
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
* <p>
* You can construct multiple instances per plugin.
*
* @param plugin - the plugin.
*/
public TinyProtocol(final Plugin plugin) {
this.plugin = plugin; this.plugin = plugin;
// Compute handler name // Compute handler name
this.handlerName = getHandlerName(); this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
// Prepare existing players // Prepare existing players
registerBukkitEvents(); registerBukkitEvents();
try { try {
System.out.println("[NPCLib] Attempting to inject into netty.");
registerChannelHandler(); registerChannelHandler();
registerPlayers(plugin); registerPlayers(plugin);
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
// Damn you, late bind // Damn you, late bind
plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind."); plugin.getLogger().info("[NPCLib] Attempting to delay injection.");
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
registerChannelHandler(); registerChannelHandler();
registerPlayers(plugin); registerPlayers(plugin);
plugin.getLogger().info("[TinyProtocol] Late bind injection successful."); plugin.getLogger().info("[NPCLib] Injection complete.");
} }
}.runTask(plugin); }.runTask(plugin);
} }
@@ -108,6 +98,7 @@ public abstract class TinyProtocol {
// Handle connected channels // Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() { endInitProtocol = new ChannelInitializer<Channel>() {
@SuppressWarnings("all")
@Override @Override
protected void initChannel(Channel channel) throws Exception { protected void initChannel(Channel channel) throws Exception {
try { try {
@@ -119,7 +110,7 @@ public abstract class TinyProtocol {
} }
} }
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); plugin.getLogger().log(Level.SEVERE, "[NPCLib] Cannot inject incomming channel " + channel, e);
} }
} }
@@ -128,6 +119,7 @@ public abstract class TinyProtocol {
// This is executed before Minecraft's channel handler // This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() { beginInitProtocol = new ChannelInitializer<Channel>() {
@SuppressWarnings("all")
@Override @Override
protected void initChannel(Channel channel) throws Exception { protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol); channel.pipeline().addLast(endInitProtocol);
@@ -137,6 +129,7 @@ public abstract class TinyProtocol {
serverChannelHandler = new ChannelInboundHandlerAdapter() { serverChannelHandler = new ChannelInboundHandlerAdapter() {
@SuppressWarnings("all")
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg; Channel channel = (Channel) msg;
@@ -149,12 +142,10 @@ public abstract class TinyProtocol {
}; };
} }
/**
* Register bukkit events.
*/
private void registerBukkitEvents() { private void registerBukkitEvents() {
listener = new Listener() { listener = new Listener() {
@SuppressWarnings("unused")
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public final void onPlayerLogin(PlayerLoginEvent e) { public final void onPlayerLogin(PlayerLoginEvent e) {
if (closed) if (closed)
@@ -168,6 +159,7 @@ public abstract class TinyProtocol {
} }
} }
@SuppressWarnings("unused")
@EventHandler @EventHandler
public final void onPluginDisable(PluginDisableEvent e) { public final void onPluginDisable(PluginDisableEvent e) {
if (e.getPlugin().equals(plugin)) { if (e.getPlugin().equals(plugin)) {
@@ -195,7 +187,7 @@ public abstract class TinyProtocol {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) { for (Object item : list) {
if (!ChannelFuture.class.isInstance(item)) if (!(item instanceof ChannelFuture))
break; break;
// Channel future that contains the server connection // Channel future that contains the server connection
@@ -216,17 +208,12 @@ public abstract class TinyProtocol {
final ChannelPipeline pipeline = serverChannel.pipeline(); final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler // Remove channel handler
serverChannel.eventLoop().execute(new Runnable() { serverChannel.eventLoop().execute(() -> {
@Override
public void run() {
try { try {
pipeline.remove(serverChannelHandler); pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
// That's fine // That's fine
} }
}
}); });
} }
} }
@@ -237,119 +224,14 @@ public abstract class TinyProtocol {
} }
} }
/** public Object onPacketInAsync(Player sender, Object packet) {
* Invoked when the server is starting to send a packet to a player.
* <p>
* Note that this is not executed on the main thread.
*
* @param receiver - the receiving player, NULL for early login/status packets.
* @param channel - the channel that received the packet. Never NULL.
* @param packet - the packet being sent.
* @return The packet to send instead, or NULL to cancel the transmission.
*/
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
return packet; return packet;
} }
/** private void injectPlayer(Player player) {
* Invoked when the server has received a packet from a given player.
* <p>
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
*
* @param sender - the player that sent the packet, NULL for early login/status packets.
* @param channel - channel that received the packet. Never NULL.
* @param packet - the packet being received.
* @return The packet to recieve instead, or NULL to cancel.
*/
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
return packet;
}
/**
* Send a packet to a particular player.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the destination player.
* @param packet - the packet to send.
*/
public void sendPacket(Player player, Object packet) {
sendPacket(getChannel(player), packet);
}
/**
* Send a packet to a particular client.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet to send.
*/
public void sendPacket(Channel channel, Object packet) {
channel.pipeline().writeAndFlush(packet);
}
/**
* Pretend that a given packet has been received from a player.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the player that sent the packet.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Player player, Object packet) {
receivePacket(getChannel(player), packet);
}
/**
* Pretend that a given packet has been received from a given client.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Channel channel, Object packet) {
channel.pipeline().context("encoder").fireChannelRead(packet);
}
/**
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
* <p>
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
*
* @return A unique channel handler name.
*/
protected String getHandlerName() {
return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* <p>
* This will automatically be called when a player has logged in.
*
* @param player - the player to inject.
*/
public void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player; injectChannelInternal(getChannel(player)).player = player;
} }
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
* @return The packet interceptor.
*/
private PacketInterceptor injectChannelInternal(Channel channel) { private PacketInterceptor injectChannelInternal(Channel channel) {
try { try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
@@ -368,13 +250,7 @@ public abstract class TinyProtocol {
} }
} }
/** private Channel getChannel(Player player) {
* Retrieve the Netty channel associated with a player. This is cached.
*
* @param player - the player.
* @return The Netty channel.
*/
public Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName()); Channel channel = channelLookup.get(player.getName());
// Lookup channel again // Lookup channel again
@@ -388,24 +264,14 @@ public abstract class TinyProtocol {
return channel; return channel;
} }
/** private void close() {
* Uninject a specific player. if (!closed) {
* closed = true;
* @param player - the injected player.
*/
public void uninjectPlayer(Player player) {
uninjectChannel(getChannel(player));
}
/** // Remove our handlers
* Uninject a specific channel. for (Player player : plugin.getServer().getOnlinePlayers()) {
* <p>
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
*
* @param channel - the injected channel.
*/
public void uninjectChannel(final Channel channel) {
// No need to guard against this if we're closing // No need to guard against this if we're closing
Channel channel = getChannel(player);
if (!closed) { if (!closed) {
uninjectedChannels.add(channel); uninjectedChannels.add(channel);
} }
@@ -414,49 +280,12 @@ public abstract class TinyProtocol {
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName)); channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
} }
/**
* Determine if the given player has been injected by TinyProtocol.
*
* @param player - the player.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Player player) {
return hasInjected(getChannel(player));
}
/**
* Determine if the given channel has been injected by TinyProtocol.
*
* @param channel - the channel.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Channel channel) {
return channel.pipeline().get(handlerName) != null;
}
/**
* Cease listening for packets. This is called automatically when your plugin is disabled.
*/
public final void close() {
if (!closed) {
closed = true;
// Remove our handlers
for (Player player : plugin.getServer().getOnlinePlayers()) {
uninjectPlayer(player);
}
// Clean up Bukkit // Clean up Bukkit
HandlerList.unregisterAll(listener); HandlerList.unregisterAll(listener);
unregisterChannelHandler(); unregisterChannelHandler();
} }
} }
/**
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
*
* @author Kristian
*/
private final class PacketInterceptor extends ChannelDuplexHandler { private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event // Updated by the login event
public volatile Player player; public volatile Player player;
@@ -468,9 +297,9 @@ public abstract class TinyProtocol {
handleLoginStart(channel, msg); handleLoginStart(channel, msg);
try { try {
msg = onPacketInAsync(player, channel, msg); msg = onPacketInAsync(player, msg);
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); plugin.getLogger().log(Level.SEVERE, "[NPCLib] Error in onPacketInAsync().", e);
} }
if (msg != null) { if (msg != null) {
@@ -478,23 +307,10 @@ public abstract class TinyProtocol {
} }
} }
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
try {
msg = onPacketOutAsync(player, ctx.channel(), msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
}
if (msg != null) {
super.write(ctx, msg, promise);
}
}
private void handleLoginStart(Channel channel, Object packet) { private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) { if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet); Object profile = getGameProfile.get(packet);
channelLookup.put(profile.getName(), channel); channelLookup.put((String) Reflection.getMethod(profile.getClass(), "getName").invoke(profile), channel);
} }
} }
} }
@@ -9,6 +9,7 @@ import net.jitse.npclib.listeners.ChunkListener;
import net.jitse.npclib.listeners.PacketListener; import net.jitse.npclib.listeners.PacketListener;
import net.jitse.npclib.listeners.PlayerListener; import net.jitse.npclib.listeners.PlayerListener;
import net.jitse.npclib.skin.Skin; import net.jitse.npclib.skin.Skin;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
@@ -64,7 +65,8 @@ public class NPCLib {
pluginManager.registerEvents(new PlayerListener(), plugin); pluginManager.registerEvents(new PlayerListener(), plugin);
pluginManager.registerEvents(new ChunkListener(), plugin); pluginManager.registerEvents(new ChunkListener(), plugin);
new PacketListener().start(plugin); // Boot the according packet listener.
new PacketListener().start(plugin, Bukkit.getBukkitVersion().contains("1.7"));
} }
/** /**
@@ -4,9 +4,8 @@
package net.jitse.npclib.api; package net.jitse.npclib.api;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.jitse.npclib.NPCManager; import net.jitse.npclib.NPCManager;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.jitse.npclib.events.NPCDestroyEvent; import net.jitse.npclib.events.NPCDestroyEvent;
import net.jitse.npclib.events.NPCSpawnEvent; import net.jitse.npclib.events.NPCSpawnEvent;
import net.jitse.npclib.events.trigger.TriggerType; import net.jitse.npclib.events.trigger.TriggerType;
@@ -25,11 +24,11 @@ import java.util.*;
public abstract class NPC implements PacketHandler, ActionHandler { public abstract class NPC implements PacketHandler, ActionHandler {
protected final UUID uuid = UUID.randomUUID(); protected final UUID uuid = UUID.randomUUID();
protected final String name = uuid.toString().replace("-", "").substring(0, 10);
// Below was previously = (int) Math.ceil(Math.random() * 100000) + 100000 (new is experimental). // Below was previously = (int) Math.ceil(Math.random() * 100000) + 100000 (new is experimental).
protected final int entityId = Integer.MAX_VALUE - NPCManager.getAllNPCs().size(); protected final int entityId = Integer.MAX_VALUE - NPCManager.getAllNPCs().size();
protected double cosFOV = Math.cos(Math.toRadians(60)); protected double cosFOV = Math.cos(Math.toRadians(60));
protected String name = uuid.toString().replace("-", "").substring(0, 10);
private final Set<UUID> shown = new HashSet<>(); private final Set<UUID> shown = new HashSet<>();
private final Set<UUID> autoHidden = new HashSet<>(); private final Set<UUID> autoHidden = new HashSet<>();
@@ -39,7 +38,7 @@ public abstract class NPC implements PacketHandler, ActionHandler {
protected final List<String> lines; protected final List<String> lines;
protected JavaPlugin plugin; protected JavaPlugin plugin;
protected GameProfile gameProfile; protected GameProfileWrapper gameProfile;
protected Location location; protected Location location;
public NPC(JavaPlugin plugin, Skin skin, double autoHideDistance, List<String> lines) { public NPC(JavaPlugin plugin, Skin skin, double autoHideDistance, List<String> lines) {
@@ -51,11 +50,11 @@ public abstract class NPC implements PacketHandler, ActionHandler {
NPCManager.add(this); NPCManager.add(this);
} }
protected GameProfile generateGameProfile(UUID uuid, String name) { protected GameProfileWrapper generateGameProfile(UUID uuid, String name) {
GameProfile gameProfile = new GameProfile(uuid, name); GameProfileWrapper gameProfile = new GameProfileWrapper(uuid, name);
if (skin != null) { if (skin != null) {
gameProfile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); gameProfile.addSkin(skin);
} }
return gameProfile; return gameProfile;
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.api.wrapper;
import com.comphenix.tinyprotocol.Reflection;
import com.google.common.collect.ForwardingMultimap;
import net.jitse.npclib.skin.Skin;
import org.bukkit.Bukkit;
import java.util.UUID;
public class GameProfileWrapper {
// Written because of issue#10 (https://github.com/JitseB/NPCLib/issues/10).
// This class acts as an NMS reflection wrapper for the GameProfileWrapper class.
// TODO: Add this class to the v1_7_R4 module of NPCLib.
private final boolean is1_7 = Bukkit.getBukkitVersion().contains("1.7");
private final Class<?> gameProfileClazz = Reflection.getClass((is1_7 ? "net.minecraft.util." : "") + "com.mojang.authlib.GameProfile");
Object gameProfile;
public GameProfileWrapper(UUID uuid, String name) {
// Only need to check if the version is 1.7, as NPCLib doesn't support any version below this version.
this.gameProfile = Reflection.getConstructor(gameProfileClazz, UUID.class, String.class).invoke(uuid, name);
}
public void addSkin(Skin skin) {
// Create a new property with the skin data.
Class<?> propertyClazz = Reflection.getClass((is1_7 ? "net.minecraft.util." : "") + "com.mojang.authlib.properties.Property");
Object property = Reflection.getConstructor(propertyClazz,
String.class, String.class, String.class).invoke("textures", skin.getValue(), skin.getSignature());
// Get the property map from the GameProfileWrapper object.
Class<?> propertyMapClazz = Reflection.getClass((is1_7 ? "net.minecraft.util." : "") + "com.mojang.authlib.properties.PropertyMap");
Reflection.FieldAccessor propertyMapGetter = Reflection.getField(gameProfileClazz, "properties",
propertyMapClazz);
Object propertyMap = propertyMapGetter.get(gameProfile);
// Add our new property to the property map.
Reflection.getMethod(ForwardingMultimap.class, "put", Object.class, Object.class)
.invoke(propertyMap, "textures", property);
// Finally set the property map back in the GameProfileWrapper object.
propertyMapGetter.set(gameProfile, propertyMap);
}
public Object getGameProfile() {
return gameProfile;
}
}
@@ -4,9 +4,9 @@
package net.jitse.npclib.listeners; package net.jitse.npclib.listeners;
import com.comphenix.tinyprotocol.LegacyTinyProtocol;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import io.netty.channel.Channel;
import net.jitse.npclib.NPCManager; import net.jitse.npclib.NPCManager;
import net.jitse.npclib.api.NPC; import net.jitse.npclib.api.NPC;
import net.jitse.npclib.events.NPCInteractEvent; import net.jitse.npclib.events.NPCInteractEvent;
@@ -34,11 +34,13 @@ public class PacketListener {
// Prevent players from clicking at very high speeds. // Prevent players from clicking at very high speeds.
private final Set<UUID> delay = new HashSet<>(); private final Set<UUID> delay = new HashSet<>();
public void start(JavaPlugin plugin) { public void start(JavaPlugin plugin, boolean is1_7) {
new TinyProtocol(plugin) { if (is1_7) {
// 1.7 R4 packet interaction.
new LegacyTinyProtocol(plugin) {
@Override @Override
public Object onPacketInAsync(Player player, Channel channel, Object packet) { public Object onPacketInAsync(Player player, Object packet) {
if (packetPlayInUseEntityClazz.isInstance(packet)) { if (packetPlayInUseEntityClazz.isInstance(packet)) {
NPC npc = NPCManager.getAllNPCs().stream().filter( NPC npc = NPCManager.getAllNPCs().stream().filter(
@@ -47,7 +49,7 @@ public class PacketListener {
if (npc == null) { if (npc == null) {
// Default player, not doing magic with the packet. // Default player, not doing magic with the packet.
return super.onPacketInAsync(player, channel, packet); return super.onPacketInAsync(player, packet);
} }
if (delay.contains(player.getUniqueId())) { if (delay.contains(player.getUniqueId())) {
@@ -65,8 +67,44 @@ public class PacketListener {
return null; return null;
} }
return super.onPacketInAsync(player, channel, packet); return super.onPacketInAsync(player, packet);
}
};
} else {
// 1.8 (and above) packet interaction.
new TinyProtocol(plugin) {
@Override
public Object onPacketInAsync(Player player, Object packet) {
if (packetPlayInUseEntityClazz.isInstance(packet)) {
NPC npc = NPCManager.getAllNPCs().stream().filter(
check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
.findFirst().orElse(null);
if (npc == null) {
// Default player, not doing magic with the packet.
return super.onPacketInAsync(player, packet);
}
if (delay.contains(player.getUniqueId())) {
return null;
}
ClickType clickType = actionField.get(packet).toString()
.equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK;
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc));
UUID uuid = player.getUniqueId();
delay.add(uuid);
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
return null;
}
return super.onPacketInAsync(player, packet);
} }
}; };
} }
}
} }
+2 -1
View File
@@ -7,12 +7,13 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib</artifactId> <artifactId>npclib</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<modules> <modules>
<module>v1_7_R4</module>
<module>v1_8_R1</module> <module>v1_8_R1</module>
<module>v1_8_R2</module> <module>v1_8_R2</module>
<module>v1_8_R3</module> <module>v1_8_R3</module>
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_10_R1</artifactId> <artifactId>npclib-nms-v1_10_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_10_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_10_R1.EnumGamemode; import net.minecraft.server.v1_10_R1.EnumGamemode;
import net.minecraft.server.v1_10_R1.IChatBaseComponent; import net.minecraft.server.v1_10_R1.IChatBaseComponent;
import net.minecraft.server.v1_10_R1.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_10_R1.PacketPlayOutPlayerInfo;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_11_R1</artifactId> <artifactId>npclib-nms-v1_11_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_11_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_11_R1.EnumGamemode; import net.minecraft.server.v1_11_R1.EnumGamemode;
import net.minecraft.server.v1_11_R1.IChatBaseComponent; import net.minecraft.server.v1_11_R1.IChatBaseComponent;
import net.minecraft.server.v1_11_R1.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_11_R1.PacketPlayOutPlayerInfo;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_12_R1</artifactId> <artifactId>npclib-nms-v1_12_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_12_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_12_R1.EnumGamemode; import net.minecraft.server.v1_12_R1.EnumGamemode;
import net.minecraft.server.v1_12_R1.IChatBaseComponent; import net.minecraft.server.v1_12_R1.IChatBaseComponent;
import net.minecraft.server.v1_12_R1.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_12_R1.PacketPlayOutPlayerInfo;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_13_R1</artifactId> <artifactId>npclib-nms-v1_13_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_13_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_13_R1.EnumGamemode; import net.minecraft.server.v1_13_R1.EnumGamemode;
import net.minecraft.server.v1_13_R1.IChatBaseComponent; import net.minecraft.server.v1_13_R1.IChatBaseComponent;
import net.minecraft.server.v1_13_R1.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_13_R1.PacketPlayOutPlayerInfo;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_13_R2</artifactId> <artifactId>npclib-nms-v1_13_R2</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_13_R2.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_13_R2.EnumGamemode; import net.minecraft.server.v1_13_R2.EnumGamemode;
import net.minecraft.server.v1_13_R2.IChatBaseComponent; import net.minecraft.server.v1_13_R2.IChatBaseComponent;
import net.minecraft.server.v1_13_R2.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_13_R2.PacketPlayOutPlayerInfo;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId>
<version>1.4</version>
</parent>
<artifactId>npclib-nms-v1_7_R4</artifactId>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.nms.v1_7_R4;
import net.jitse.npclib.api.NPC;
import net.jitse.npclib.nms.v1_7_R4.packets.PacketPlayOutEntityHeadRotationWrapper;
import net.jitse.npclib.nms.v1_7_R4.packets.PacketPlayOutNamedEntitySpawnWrapper;
import net.jitse.npclib.nms.v1_7_R4.packets.PacketPlayOutPlayerInfoWrapper;
import net.jitse.npclib.nms.v1_7_R4.packets.PacketPlayOutScoreboardTeamWrapper;
import net.jitse.npclib.skin.Skin;
import net.minecraft.server.v1_7_R4.*;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.com.mojang.authlib.properties.Property;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.List;
import java.util.UUID;
/**
* @author Jitse Boonstra
*/
public class NPC_v1_7_R4 extends NPC {
private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn;
private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister;
private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove;
private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation;
private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy;
private GameProfile legacyGameProfile;
public NPC_v1_7_R4(JavaPlugin plugin, Skin skin, double autoHideDistance, List<String> lines) {
super(plugin, skin, autoHideDistance, lines);
// TODO: Add multi-line text support.
this.name = lines.get(0);
}
@Override
public void createPackets() {
this.legacyGameProfile = generateLegacyGameProfile(uuid, name.length() < 16 ? name : name.substring(0, 15));
PacketPlayOutPlayerInfoWrapper packetPlayOutPlayerInfoWrapper = new PacketPlayOutPlayerInfoWrapper();
// Packets for spawning the NPC:
this.packetPlayOutScoreboardTeamRegister = new PacketPlayOutScoreboardTeamWrapper()
.createRegisterTeam(legacyGameProfile.getId().toString().replace("-", "").substring(0, 10), name); // First packet to send.
this.packetPlayOutPlayerInfoAdd = packetPlayOutPlayerInfoWrapper
.create(0, legacyGameProfile, name.length() < 16 ? name : name.length() < 16 ? name : name.substring(0, 15)); // Second packet to send.
this.packetPlayOutNamedEntitySpawn = new PacketPlayOutNamedEntitySpawnWrapper()
.create(legacyGameProfile, location, entityId); // Third packet to send.
this.packetPlayOutEntityHeadRotation = new PacketPlayOutEntityHeadRotationWrapper()
.create(location, entityId); // Fourth packet to send.
this.packetPlayOutPlayerInfoRemove = packetPlayOutPlayerInfoWrapper
.create(4, legacyGameProfile, name.length() < 16 ? name : name.substring(0, 15)); // Fifth packet to send (delayed).
// Packet for destroying the NPC:
this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send.
// Second packet to send is "packetPlayOutPlayerInfoRemove".
this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper()
.createUnregisterTeam(legacyGameProfile.getId().toString().replace("-", "").substring(0, 10)); // Third packet to send.
}
@Override
public void sendShowPackets(Player player) {
PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection;
playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister);
playerConnection.sendPacket(packetPlayOutPlayerInfoAdd);
playerConnection.sendPacket(packetPlayOutNamedEntitySpawn);
playerConnection.sendPacket(packetPlayOutEntityHeadRotation);
Bukkit.getScheduler().runTaskLater(plugin, () ->
playerConnection.sendPacket(packetPlayOutPlayerInfoRemove), 50);
}
@Override
public void sendHidePackets(Player player, boolean scheduler) {
PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection;
playerConnection.sendPacket(packetPlayOutEntityDestroy);
playerConnection.sendPacket(packetPlayOutPlayerInfoRemove);
if (scheduler) {
// Sending this a bit later so the player doesn't see the name (for that split second).
Bukkit.getScheduler().runTaskLater(plugin, () ->
playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5);
} else {
playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister);
}
}
private GameProfile generateLegacyGameProfile(UUID uuid, String name) {
GameProfile gameProfile = new GameProfile(uuid, name);
if (skin != null) {
gameProfile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
}
return gameProfile;
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.nms.v1_7_R4.packets;
import com.comphenix.tinyprotocol.Reflection;
import net.minecraft.server.v1_7_R4.PacketPlayOutEntityHeadRotation;
import org.bukkit.Location;
/**
* @author Jitse Boonstra
*/
public class PacketPlayOutEntityHeadRotationWrapper {
public PacketPlayOutEntityHeadRotation create(Location location, int entityId) {
PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation = new PacketPlayOutEntityHeadRotation();
Reflection.getField(packetPlayOutEntityHeadRotation.getClass(), "a", int.class).
set(packetPlayOutEntityHeadRotation, entityId);
Reflection.getField(packetPlayOutEntityHeadRotation.getClass(), "b", byte.class)
.set(packetPlayOutEntityHeadRotation, (byte) ((int) location.getYaw() * 256.0F / 360.0F));
return packetPlayOutEntityHeadRotation;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.nms.v1_7_R4.packets;
import com.comphenix.tinyprotocol.Reflection;
import net.minecraft.server.v1_7_R4.DataWatcher;
import net.minecraft.server.v1_7_R4.PacketPlayOutNamedEntitySpawn;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import org.bukkit.Location;
/**
* @author Jitse Boonstra
*/
public class PacketPlayOutNamedEntitySpawnWrapper {
public PacketPlayOutNamedEntitySpawn create(GameProfile gameProfile, Location location, int entityId) {
PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn = new PacketPlayOutNamedEntitySpawn();
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "a", int.class)
.set(packetPlayOutNamedEntitySpawn, entityId);
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "b", GameProfile.class)
.set(packetPlayOutNamedEntitySpawn, gameProfile);
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "c", int.class)
.set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D));
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class)
.set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D));
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class)
.set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D));
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "f", byte.class)
.set(packetPlayOutNamedEntitySpawn, (byte) ((int) (location.getYaw() * 256.0F / 360.0F)));
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "g", byte.class)
.set(packetPlayOutNamedEntitySpawn, (byte) ((int) (location.getPitch() * 256.0F / 360.0F)));
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.a(10, (byte) 127);
Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class)
.set(packetPlayOutNamedEntitySpawn, dataWatcher);
return packetPlayOutNamedEntitySpawn;
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.nms.v1_7_R4.packets;
import com.comphenix.tinyprotocol.Reflection;
import net.minecraft.server.v1_7_R4.PacketPlayOutPlayerInfo;
import net.minecraft.util.com.mojang.authlib.GameProfile;
/**
* @author Jitse Boonstra
*/
public class PacketPlayOutPlayerInfoWrapper {
public PacketPlayOutPlayerInfo create(int action, GameProfile gameProfile, String name) {
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
// Action values:
// 0 = Add player
// 1 = Update gamemode
// 2 = Update latency
// 3 = Update display name
// 4 = Remove player
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "action", int.class)
.set(packetPlayOutPlayerInfo, action);
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "player", GameProfile.class)
.set(packetPlayOutPlayerInfo, gameProfile);
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "username", String.class)
.set(packetPlayOutPlayerInfo, name);
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "ping", int.class)
.set(packetPlayOutPlayerInfo, 0);
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "gamemode", int.class)
.set(packetPlayOutPlayerInfo, 1);
return packetPlayOutPlayerInfo;
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018 Jitse Boonstra
*/
package net.jitse.npclib.nms.v1_7_R4.packets;
import com.comphenix.tinyprotocol.Reflection;
import net.minecraft.server.v1_7_R4.PacketPlayOutScoreboardTeam;
import java.util.Collection;
/**
* @author Jitse Boonstra
*/
public class PacketPlayOutScoreboardTeamWrapper {
public PacketPlayOutScoreboardTeam createRegisterTeam(String uuidName, String name) {
PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam();
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "f", int.class)
.set(packetPlayOutScoreboardTeam, 0);
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class)
.set(packetPlayOutScoreboardTeam, name.length() < 16 ? name : name.substring(0, 15));
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class)
.set(packetPlayOutScoreboardTeam, uuidName);
if (name.length() > 16) {
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "d", String.class)
.set(packetPlayOutScoreboardTeam, name.substring(15));
}
if (name.length() > 32) {
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class)
.set(packetPlayOutScoreboardTeam, name.substring(31));
}
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "g", int.class)
.set(packetPlayOutScoreboardTeam, 1);
Reflection.FieldAccessor<Collection> collectionFieldAccessor = Reflection.getField(
packetPlayOutScoreboardTeam.getClass(), "e", Collection.class);
Collection collection = collectionFieldAccessor.get(packetPlayOutScoreboardTeam);
collection.add(name.length() < 16 ? name : name.substring(0, 15));
collectionFieldAccessor.set(packetPlayOutScoreboardTeam, collection);
return packetPlayOutScoreboardTeam;
}
public PacketPlayOutScoreboardTeam createUnregisterTeam(String uuidName) {
PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam();
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "f", int.class)
.set(packetPlayOutScoreboardTeam, 1);
Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class)
.set(packetPlayOutScoreboardTeam, uuidName);
return packetPlayOutScoreboardTeam;
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_8_R1</artifactId> <artifactId>npclib-nms-v1_8_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_8_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_8_R1.*; import net.minecraft.server.v1_8_R1.*;
import java.util.List; import java.util.List;
@@ -15,7 +16,9 @@ import java.util.List;
*/ */
public class PacketPlayOutPlayerInfoWrapper { public class PacketPlayOutPlayerInfoWrapper {
public PacketPlayOutPlayerInfo create(EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_8_R2</artifactId> <artifactId>npclib-nms-v1_8_R2</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_8_R2.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_8_R2.IChatBaseComponent; import net.minecraft.server.v1_8_R2.IChatBaseComponent;
import net.minecraft.server.v1_8_R2.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_8_R2.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_8_R2.WorldSettings; import net.minecraft.server.v1_8_R2.WorldSettings;
@@ -17,7 +18,9 @@ import java.util.List;
*/ */
public class PacketPlayOutPlayerInfoWrapper { public class PacketPlayOutPlayerInfoWrapper {
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_8_R3</artifactId> <artifactId>npclib-nms-v1_8_R3</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_8_R3.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_8_R3.IChatBaseComponent; import net.minecraft.server.v1_8_R3.IChatBaseComponent;
import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_8_R3.WorldSettings; import net.minecraft.server.v1_8_R3.WorldSettings;
@@ -17,7 +18,9 @@ import java.util.List;
*/ */
public class PacketPlayOutPlayerInfoWrapper { public class PacketPlayOutPlayerInfoWrapper {
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_9_R1</artifactId> <artifactId>npclib-nms-v1_9_R1</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_9_R1.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_9_R1.IChatBaseComponent; import net.minecraft.server.v1_9_R1.IChatBaseComponent;
import net.minecraft.server.v1_9_R1.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_9_R1.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_9_R1.WorldSettings; import net.minecraft.server.v1_9_R1.WorldSettings;
@@ -18,7 +19,9 @@ import java.util.List;
*/ */
public class PacketPlayOutPlayerInfoWrapper { public class PacketPlayOutPlayerInfoWrapper {
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib-nms</artifactId> <artifactId>npclib-nms</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-nms-v1_9_R2</artifactId> <artifactId>npclib-nms-v1_9_R2</artifactId>
@@ -6,6 +6,7 @@ package net.jitse.npclib.nms.v1_9_R2.packets;
import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.jitse.npclib.api.wrapper.GameProfileWrapper;
import net.minecraft.server.v1_9_R2.IChatBaseComponent; import net.minecraft.server.v1_9_R2.IChatBaseComponent;
import net.minecraft.server.v1_9_R2.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_9_R2.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_9_R2.WorldSettings; import net.minecraft.server.v1_9_R2.WorldSettings;
@@ -23,7 +24,9 @@ public class PacketPlayOutPlayerInfoWrapper {
private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz,
packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, WorldSettings.EnumGamemode.class, IChatBaseComponent.class); packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, WorldSettings.EnumGamemode.class, IChatBaseComponent.class);
public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfileWrapper gameProfileWrapper, String name) {
GameProfile gameProfile = (GameProfile) gameProfileWrapper.getGameProfile();
PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo();
Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class)
.set(packetPlayOutPlayerInfo, action); .set(packetPlayOutPlayerInfo, action);
+1 -1
View File
@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib</artifactId> <artifactId>npclib</artifactId>
<version>1.3</version> <version>1.4</version>
</parent> </parent>
<artifactId>npclib-plugin</artifactId> <artifactId>npclib-plugin</artifactId>
+1 -1
View File
@@ -8,7 +8,7 @@
<groupId>net.jitse</groupId> <groupId>net.jitse</groupId>
<artifactId>npclib</artifactId> <artifactId>npclib</artifactId>
<version>1.3</version> <version>1.4</version>
<name>NPCLib</name> <name>NPCLib</name>
<url>https://github.com/JitseB/NPCLib</url> <url>https://github.com/JitseB/NPCLib</url>