mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-09-11 22:28:03 +02:00
Merge pull request #1 from mmxw11/dev
Merge branches 'dev' and 'master' of https://github.com/mmxw11/ViaVersion into master
This commit is contained in:
commit
5a7626f280
@ -1,10 +1,12 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
@ -12,9 +14,11 @@ import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.bukkit.listeners.UpdateListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.*;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitInvContainerItemProvider;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaBulkChunkTranslator;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaMovementTransmitter;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InvContainerItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
@ -60,6 +64,7 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
/* Providers */
|
||||
Via.getManager().getProviders().use(BulkChunkTranslatorProvider.class, new BukkitViaBulkChunkTranslator());
|
||||
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BukkitViaMovementTransmitter());
|
||||
Via.getManager().getProviders().use(InvContainerItemProvider.class, new BukkitInvContainerItemProvider());
|
||||
Via.getManager().getProviders().use(HandItemProvider.class, new HandItemProvider() {
|
||||
@Override
|
||||
public Item getHandItem(final UserConnection info) {
|
||||
|
@ -0,0 +1,53 @@
|
||||
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 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() {
|
||||
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);
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
items.clear();
|
||||
}
|
||||
} finally {
|
||||
provider.onTaskExecuted(uuid);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
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;
|
||||
private Object clickTypeEnum;
|
||||
// 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);
|
||||
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
|
||||
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 {
|
||||
cinstance = wclickPacketClass.newInstance();
|
||||
Object nmsItem = nmsItemMethod.invoke(null, itemstack);
|
||||
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);
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
if (protocolId == 47) {
|
||||
ReflectionUtil.set(cinstance, "shift", 1);
|
||||
} else if (protocolId >= 107) { // 1.9+
|
||||
ReflectionUtil.set(cinstance, "shift", clickTypeEnum);
|
||||
}
|
||||
} 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, 2); // 2 ticks later (possible double click action).
|
||||
}
|
||||
|
||||
private void setupReflection() {
|
||||
if (!supported) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.wclickPacketClass = NMSUtil.nms("PacketPlayInWindowClick");
|
||||
Class<?> eclassz = NMSUtil.nms("InventoryClickType");
|
||||
Object[] constants = eclassz.getEnumConstants();
|
||||
this.clickTypeEnum = constants[1]; // QUICK_MOVE
|
||||
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 && protocolId <= 316) {
|
||||
return true; // 1.8
|
||||
}
|
||||
// this is not needed on 1.12+
|
||||
return false;
|
||||
}
|
||||
}
|
@ -149,10 +149,11 @@ public class PacketWrapper {
|
||||
}
|
||||
} else {
|
||||
Pair<Type, Object> read = readableObjects.poll();
|
||||
if (read.getKey().equals(type) || (type.getBaseClass().equals(read.getKey().getBaseClass()) && type.getOutputClass().equals(read.getKey().getOutputClass()))) {
|
||||
Type rtype = read.getKey();
|
||||
if (rtype.equals(type) || (type.getBaseClass().equals(rtype.getBaseClass()) && type.getOutputClass().equals(rtype.getOutputClass()))) {
|
||||
return (T) read.getValue();
|
||||
} else {
|
||||
if (type == Type.NOTHING) {
|
||||
if (rtype == Type.NOTHING) {
|
||||
return read(type); // retry
|
||||
} else {
|
||||
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
|
||||
|
@ -12,6 +12,7 @@ import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.entities.Entity1_12Types;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
|
||||
import us.myles.ViaVersion.api.platform.providers.ViaProviders;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.remapper.PacketHandler;
|
||||
import us.myles.ViaVersion.api.remapper.PacketRemapper;
|
||||
@ -19,6 +20,7 @@ import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.version.Types1_12;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.packets.InventoryPackets;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InvContainerItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.EntityTracker;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.types.Chunk1_9_3_4Type;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
|
||||
@ -384,6 +386,11 @@ public class Protocol1_12To1_11_1 extends Protocol {
|
||||
newId += 3;
|
||||
return newId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void register(ViaProviders providers) {
|
||||
providers.register(InvContainerItemProvider.class, new InvContainerItemProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(UserConnection userConnection) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_12to1_11_1.packets;
|
||||
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
import us.myles.ViaVersion.api.remapper.PacketHandler;
|
||||
import us.myles.ViaVersion.api.remapper.PacketRemapper;
|
||||
@ -8,6 +9,7 @@ import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.BedRewriter;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.Protocol1_12To1_11_1;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InvContainerItemProvider;
|
||||
|
||||
public class InventoryPackets {
|
||||
public static void register(Protocol1_12To1_11_1 protocol) {
|
||||
@ -118,8 +120,23 @@ public class InventoryPackets {
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
byte button = wrapper.get(Type.BYTE, 0);
|
||||
int mode = wrapper.get(Type.VAR_INT, 0);
|
||||
Item item = wrapper.get(Type.ITEM, 0);
|
||||
BedRewriter.toServerItem(item);
|
||||
// QUICK_MOVE PATCH (Shift + (click/double click))
|
||||
if (mode == 1 && button == 0 && item == null) {
|
||||
short windowId = wrapper.get(Type.UNSIGNED_BYTE, 0);
|
||||
short slotId = wrapper.get(Type.SHORT, 0);
|
||||
short anumber = wrapper.get(Type.SHORT, 1);
|
||||
InvContainerItemProvider provider = Via.getManager().getProviders().get(InvContainerItemProvider.class);
|
||||
boolean succeed = provider.registerInvClickPacket(windowId, slotId, anumber, wrapper.user());
|
||||
if (succeed) {
|
||||
wrapper.cancel();
|
||||
}
|
||||
// otherwise just pass through so the server sends the PacketPlayOutTransaction packet.
|
||||
} else {
|
||||
BedRewriter.toServerItem(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.platform.providers.Provider;
|
||||
|
||||
public class InvContainerItemProvider implements Provider {
|
||||
|
||||
public boolean registerInvClickPacket(short windowId, short slotId, short anumber, UserConnection uconnection) {
|
||||
return false; // not supported :/ plays very sad violin
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
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 {
|
||||
|
||||
private short windowId;
|
||||
private short slotId;
|
||||
private short actionNumber;
|
||||
}
|
Loading…
Reference in New Issue
Block a user