Support item provider on a 1.8 server

... 1.9 is on the way
This commit is contained in:
mmxw11 2017-09-25 18:04:39 +03:00
parent 976c418c9e
commit b3d3921f6e
3 changed files with 180 additions and 6 deletions

View File

@ -1,22 +1,55 @@
package us.myles.ViaVersion.bukkit.protocol1_12to1_11_1;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.bukkit.providers.BukkitInvContainerItemProvider;
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.InvItemStorage;
public class BukkitInvContainerUpdateTask implements Runnable {
private BukkitInvContainerItemProvider provider;
private UUID uuid;
private final UUID uuid;
private final List<InvItemStorage> items;
public BukkitInvContainerUpdateTask(BukkitInvContainerItemProvider provider, UUID uuid) {
this.provider = provider;
this.uuid = uuid;
this.items = Collections.synchronizedList(new ArrayList<>());
}
public void addItem(short windowId, short slotId, short anumber) {
InvItemStorage storage = new InvItemStorage(windowId, slotId, anumber);
items.add(storage);
}
@Override
public void run() {
// TODO Auto-generated method stub
provider.onTaskExecuted(uuid);
Player p = Bukkit.getServer().getPlayer(uuid);
if (p == null) {
provider.onTaskExecuted(uuid);
return;
}
try {
synchronized (items) {
for (InvItemStorage storage : items) {
Object packet = provider.buildWindowClickPacket(p, storage);
boolean result = provider.sendPlayer(p, packet);
System.out.println("item result: " + result);
if (!result) {
break;
}
}
System.out.println("items: " + items);
items.clear();
}
} finally {
provider.onTaskExecuted(uuid);
}
}
}

View File

@ -1,28 +1,167 @@
package us.myles.ViaVersion.bukkit.providers;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.bukkit.protocol1_12to1_11_1.BukkitInvContainerUpdateTask;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InvContainerItemProvider;
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.InvItemStorage;
import us.myles.ViaVersion.util.ReflectionUtil;
public class BukkitInvContainerItemProvider extends InvContainerItemProvider {
private static Map<UUID, BukkitInvContainerUpdateTask> updateTasks = new ConcurrentHashMap<>();
private boolean supported;
// packet class
private Class<?> wclickPacketClass;
// Use for nms
private Method nmsItemMethod;
private Method ephandle;
private Field connection;
private Method packetMethod;
public BukkitInvContainerItemProvider() {
this.supported = isSupported();
setupReflection();
}
@Override
public boolean registerInvClickPacket(short windowId, short slotId, short anumber, UserConnection uconnection) {
if (!supported) {
return false;
}
ProtocolInfo info = uconnection.get(ProtocolInfo.class);
// TODO: lets add some stuff here :)
UUID uuid = info.getUuid();
BukkitInvContainerUpdateTask utask = updateTasks.get(uuid);
final boolean registered = utask != null;
if (!registered) {
utask = new BukkitInvContainerUpdateTask(this, uuid);
updateTasks.put(uuid, utask);
}
// http://wiki.vg/index.php?title=Protocol&oldid=13223#Click_Window
System.out.println("info: " + info + " QUICK ACTION windowId: " + windowId + " slotId: " + slotId + " button: " + 0 + " anumber: " + anumber + " mode: " + 1);
return false; // change to true once supported
utask.addItem(windowId, slotId, anumber);
if (!registered) {
scheduleTask(utask);
}
return true;
}
public Object buildWindowClickPacket(Player p, InvItemStorage storage) {
if (!supported) {
return null;
}
InventoryView inv = p.getOpenInventory();
short slotId = storage.getSlotId();
if (slotId > inv.countSlots()) {
return null; // wrong container open?
}
ItemStack itemstack = inv.getItem(slotId);
if (itemstack == null) {
return null;
}
Object cinstance = null;
try {
Object nmsItem = nmsItemMethod.invoke(null, itemstack);
// TODO: PASSTHROUGH PROTOCOLS? (Make InvItemStorage inheritance from Item?)
cinstance = wclickPacketClass.newInstance();
ReflectionUtil.set(cinstance, "a", (int) storage.getWindowId());
ReflectionUtil.set(cinstance, "slot", (int) slotId);
ReflectionUtil.set(cinstance, "button", 0); // shift + left mouse click
ReflectionUtil.set(cinstance, "d", storage.getActionNumber());
ReflectionUtil.set(cinstance, "item", nmsItem);
// TODO: THIS MUST BE AN ENUM on 1.9+ SERVERS!!
ReflectionUtil.set(cinstance, "shift", 1); // mode
} catch (Exception e) {
e.printStackTrace();
}
return cinstance;
}
public boolean sendPlayer(Player p, Object packet) {
if (packet == null) {
return false;
}
try {
Object entityPlayer = ephandle.invoke(p);
Object pconnection = connection.get(entityPlayer);
// send
packetMethod.invoke(pconnection, packet);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
return true;
}
public void onTaskExecuted(UUID uuid) {
updateTasks.remove(uuid);
}
private void scheduleTask(BukkitInvContainerUpdateTask utask) {
BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
Plugin instance = Bukkit.getServer().getPluginManager().getPlugin("ViaVersion");
scheduler.runTaskLater(instance, utask, 5); // 5 ticks later.
}
private void setupReflection() {
if (!supported) {
return;
}
try {
this.wclickPacketClass = NMSUtil.nms("PacketPlayInWindowClick");
Class<?> citemStack = NMSUtil.obc("inventory.CraftItemStack");
this.nmsItemMethod = citemStack.getDeclaredMethod("asNMSCopy", ItemStack.class);
} catch (Exception e) {
this.supported = false;
return;
}
try {
this.ephandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
} catch (NoSuchMethodException | ClassNotFoundException e) {
this.supported = false;
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
try {
this.connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
} catch (NoSuchFieldException | ClassNotFoundException e) {
this.supported = false;
throw new RuntimeException("Couldn't find Player Connection", e);
}
try {
this.packetMethod = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", wclickPacketClass);
} catch (NoSuchMethodException | ClassNotFoundException e) {
this.supported = false;
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
}
private boolean isSupported() {
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
if (protocolId == 47) {
return true; // 1.8
} /**else if (protocolId >= 107 && protocolId <= 110) {
return true; // 1.9
} else if (protocolId == 210) {
return true; // 1.10
} else if (protocolId == 315 || protocolId == 316) {
return true; // 1.11
}*/
// this is not needed on 1.12+
return false;
}
}

View File

@ -2,8 +2,10 @@ package us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@AllArgsConstructor
@ToString
@Getter
public class InvItemStorage {