forked from ViaVersion/ViaVersion
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request ViaVersion#754 from mmxw11/master
Improve inventory handling for Bukkit servers
- Loading branch information
Showing
17 changed files
with
332 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
.../src/main/java/us/myles/ViaVersion/bukkit/providers/BukkitInventoryQuickMoveProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package us.myles.ViaVersion.bukkit.providers; | ||
|
||
import org.bukkit.entity.Player; | ||
import org.bukkit.inventory.InventoryView; | ||
import org.bukkit.inventory.ItemStack; | ||
import us.myles.ViaVersion.api.Via; | ||
import us.myles.ViaVersion.api.data.UserConnection; | ||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry; | ||
import us.myles.ViaVersion.api.protocol.ProtocolVersion; | ||
import us.myles.ViaVersion.bukkit.tasks.protocol1_12to1_11_1.BukkitInventoryUpdateTask; | ||
import us.myles.ViaVersion.bukkit.util.NMSUtil; | ||
import us.myles.ViaVersion.protocols.base.ProtocolInfo; | ||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider; | ||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.ItemTransaction; | ||
import us.myles.ViaVersion.util.ReflectionUtil; | ||
|
||
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; | ||
|
||
public class BukkitInventoryQuickMoveProvider extends InventoryQuickMoveProvider { | ||
|
||
private static Map<UUID, BukkitInventoryUpdateTask> updateTasks = new ConcurrentHashMap<UUID, BukkitInventoryUpdateTask>(); | ||
private boolean supported; | ||
// packet class | ||
private Class<?> windowClickPacketClass; | ||
private Object clickTypeEnum; | ||
// Use for nms | ||
private Method nmsItemMethod; | ||
private Method craftPlayerHandle; | ||
private Field connection; | ||
private Method packetMethod; | ||
|
||
public BukkitInventoryQuickMoveProvider() { | ||
this.supported = isSupported(); | ||
setupReflection(); | ||
} | ||
|
||
@Override | ||
public boolean registerQuickMove(short windowId, short slotId, short actionId, UserConnection userConnection) { | ||
if (!supported) { | ||
return false; | ||
} | ||
ProtocolInfo info = userConnection.get(ProtocolInfo.class); | ||
UUID uuid = info.getUuid(); | ||
BukkitInventoryUpdateTask updateTask = updateTasks.get(uuid); | ||
final boolean registered = updateTask != null; | ||
if (!registered) { | ||
updateTask = new BukkitInventoryUpdateTask(this, uuid); | ||
updateTasks.put(uuid, updateTask); | ||
} | ||
// http://wiki.vg/index.php?title=Protocol&oldid=13223#Click_Window | ||
updateTask.addItem(windowId, slotId, actionId); | ||
if (!registered) { | ||
Via.getPlatform().runSync(updateTask, 5L); | ||
} | ||
return true; | ||
} | ||
|
||
public Object buildWindowClickPacket(Player p, ItemTransaction storage) { | ||
if (!supported) { | ||
return null; | ||
} | ||
InventoryView inv = p.getOpenInventory(); | ||
short slotId = storage.getSlotId(); | ||
if (slotId < 0) { // clicked out of inv slot | ||
return null; | ||
} | ||
if (slotId > inv.countSlots()) { | ||
return null; // wrong container open? | ||
} | ||
ItemStack itemstack = inv.getItem(slotId); | ||
if (itemstack == null) { | ||
return null; | ||
} | ||
Object packet = null; | ||
try { | ||
packet = windowClickPacketClass.newInstance(); | ||
Object nmsItem = nmsItemMethod.invoke(null, itemstack); | ||
ReflectionUtil.set(packet, "a", (int) storage.getWindowId()); | ||
ReflectionUtil.set(packet, "slot", (int) slotId); | ||
ReflectionUtil.set(packet, "button", 0); // shift + left mouse click | ||
ReflectionUtil.set(packet, "d", storage.getActionId()); | ||
ReflectionUtil.set(packet, "item", nmsItem); | ||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL; | ||
if (protocolId == ProtocolVersion.v1_8.getId()) { | ||
ReflectionUtil.set(packet, "shift", 1); | ||
} else if (protocolId >= ProtocolVersion.v1_9.getId()) { // 1.9+ | ||
ReflectionUtil.set(packet, "shift", clickTypeEnum); | ||
} | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
return packet; | ||
} | ||
|
||
public boolean sendPlayer(Player p, Object packet) { | ||
if (packet == null) { | ||
return false; | ||
} | ||
try { | ||
Object entityPlayer = craftPlayerHandle.invoke(p); | ||
Object playerConnection = connection.get(entityPlayer); | ||
// send | ||
packetMethod.invoke(playerConnection, packet); | ||
} catch (IllegalAccessException | InvocationTargetException e) { | ||
e.printStackTrace(); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
public void onTaskExecuted(UUID uuid) { | ||
updateTasks.remove(uuid); | ||
} | ||
|
||
private void setupReflection() { | ||
if (!supported) { | ||
return; | ||
} | ||
try { | ||
this.windowClickPacketClass = NMSUtil.nms("PacketPlayInWindowClick"); | ||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL; | ||
if (protocolId >= ProtocolVersion.v1_9.getId()) { | ||
Class<?> eclassz = NMSUtil.nms("InventoryClickType"); | ||
Object[] constants = eclassz.getEnumConstants(); | ||
this.clickTypeEnum = constants[1]; // QUICK_MOVE | ||
} | ||
Class<?> craftItemStack = NMSUtil.obc("inventory.CraftItemStack"); | ||
this.nmsItemMethod = craftItemStack.getDeclaredMethod("asNMSCopy", ItemStack.class); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Couldn't find required inventory classes", e); | ||
} | ||
try { | ||
this.craftPlayerHandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle"); | ||
} catch (NoSuchMethodException | ClassNotFoundException e) { | ||
throw new RuntimeException("Couldn't find CraftPlayer", e); | ||
} | ||
try { | ||
this.connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection"); | ||
} catch (NoSuchFieldException | ClassNotFoundException e) { | ||
throw new RuntimeException("Couldn't find Player Connection", e); | ||
} | ||
try { | ||
this.packetMethod = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", windowClickPacketClass); | ||
} catch (NoSuchMethodException | ClassNotFoundException e) { | ||
throw new RuntimeException("Couldn't find CraftPlayer", e); | ||
} | ||
} | ||
|
||
private boolean isSupported() { | ||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL; | ||
if (protocolId >= ProtocolVersion.v1_8.getId() && protocolId <= ProtocolVersion.v1_11_1.getId()) { | ||
return true; // 1.8-1.11.2 | ||
} | ||
// this is not needed on 1.12+ servers | ||
return false; | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
...java/us/myles/ViaVersion/bukkit/tasks/protocol1_12to1_11_1/BukkitInventoryUpdateTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package us.myles.ViaVersion.bukkit.tasks.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.BukkitInventoryQuickMoveProvider; | ||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.ItemTransaction; | ||
|
||
public class BukkitInventoryUpdateTask implements Runnable { | ||
|
||
private BukkitInventoryQuickMoveProvider provider; | ||
private final UUID uuid; | ||
private final List<ItemTransaction> items; | ||
|
||
public BukkitInventoryUpdateTask(BukkitInventoryQuickMoveProvider provider, UUID uuid) { | ||
this.provider = provider; | ||
this.uuid = uuid; | ||
this.items = Collections.synchronizedList(new ArrayList<ItemTransaction>()); | ||
} | ||
|
||
public void addItem(short windowId, short slotId, short actionId) { | ||
ItemTransaction storage = new ItemTransaction(windowId, slotId, actionId); | ||
items.add(storage); | ||
} | ||
|
||
@Override | ||
public void run() { | ||
Player p = Bukkit.getServer().getPlayer(uuid); | ||
if (p == null) { | ||
provider.onTaskExecuted(uuid); | ||
return; | ||
} | ||
try { | ||
synchronized (items) { | ||
for (ItemTransaction storage : items) { | ||
Object packet = provider.buildWindowClickPacket(p, storage); | ||
boolean result = provider.sendPlayer(p, packet); | ||
if (!result) { | ||
break; | ||
} | ||
} | ||
items.clear(); | ||
} | ||
} finally { | ||
provider.onTaskExecuted(uuid); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.