Skip to content

Commit

Permalink
Fix signed/edited books retaining their old name in creative mode.
Browse files Browse the repository at this point in the history
A Book & Quil renamed with ItemRenamer will not be properly renamed to
the title when signed in creative mode, and retain its old name. We 
simply forgot to intercept certain packets (15 and 250), and undo the 
renaming before it gets accepted on the server side.

This bug was discovered by pilvimaa. :)
  • Loading branch information
aadnk committed Oct 21, 2013
1 parent 39b8991 commit a37ccfc
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 53 deletions.
Expand Up @@ -9,39 +9,28 @@
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.shininet.bukkit.itemrenamer.RenameProcessor;
import org.shininet.bukkit.itemrenamer.component.AbstractComponent;

import com.comphenix.protocol.Packets;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.events.PacketAdapter.AdapterParameteters;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.utility.StreamSerializer;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.base.Preconditions;

/**
* Represents an item stack unprocessor or cleaner that is required in Minecraft 1.6.1 and above.
* @author Kristian
*/
class AdvancedStackCleanerComponent extends AbstractComponent {
class AdvancedStackCleanerComponent extends BasicStackCleanerComponent {
/**
* Stores the version after which the NBT fix is mandatory.
*/
private static final MinecraftVersion REQUIRED_VERSION = new MinecraftVersion(1, 6, 1);

private final RenameProcessor processor;
private final ProtocolManager manager;

// The registered listener
private PacketListener listener;

public AdvancedStackCleanerComponent(@Nonnull RenameProcessor processor, @Nonnull ProtocolManager manager) {
this.processor = Preconditions.checkNotNull(processor, "processor cannot be NULL");
this.manager = Preconditions.checkNotNull(manager, "manager cannot be NULL.");
super(processor, manager);
}

/**
Expand All @@ -56,40 +45,34 @@ public static boolean isRequired() {
}

@Override
protected void onRegistered(@Nonnull Plugin plugin) {
manager.addPacketListener(listener = new PacketAdapter(
PacketAdapter.params(plugin, Packets.Client.SET_CREATIVE_SLOT).clientSide().optionIntercept()) {
@Override
public void onPacketReceiving(PacketEvent event) {
DataInputStream input = event.getNetworkMarker().getInputStream();
protected AdapterParameteters adapterBuilder(Plugin plugin) {
// Add the ability to intercept the raw packet data
return super.adapterBuilder(plugin).optionIntercept();
}

@Override
protected void unprocessFieldStack(PacketEvent event, ItemStack modified) {
DataInputStream input = event.getNetworkMarker().getInputStream();

// Skip simulated packets
if (input == null)
return;
// Skip simulated packets
if (input == null)
return;

try {
// Read slot
input.readShort();
ItemStack stack = readItemStack(input, new StreamSerializer());
try {
// Read slot
input.readShort();
ItemStack stack = readItemStack(input, new StreamSerializer());

// Now we can properly unprocess it
processor.unprocess(stack);
// And write it back
event.getPacket().getItemModifier().write(0, stack);
// Now we can properly unprocess it
processor.unprocess(stack);

// And write it back
event.getPacket().getItemModifier().write(0, stack);

} catch (IOException e) {
// Just let ProtocolLib handle it
throw new RuntimeException("Cannot undo NBT scrubber.", e);
}
}
});
}

@Override
protected void onUnregistered(@Nonnull Plugin plugin) {
manager.removePacketListener(listener);
listener = null;
} catch (IOException e) {
// Just let ProtocolLib handle it
throw new RuntimeException("Cannot undo NBT scrubber.", e);
}
}

/**
Expand Down
@@ -1,29 +1,39 @@
package org.shininet.bukkit.itemrenamer.listeners;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.annotation.Nonnull;

import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.shininet.bukkit.itemrenamer.RenameProcessor;
import org.shininet.bukkit.itemrenamer.component.AbstractComponent;

import com.comphenix.protocol.Packets;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketAdapter.AdapterParameteters;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.utility.StreamSerializer;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;

/**
* Represents an ItemStack unprocessor
* @author Kristian
*/
class BasicStackCleanerComponent extends AbstractComponent {
private final RenameProcessor processor;
private final ProtocolManager protocolManager;
protected final RenameProcessor processor;
protected final ProtocolManager protocolManager;

private PacketListener listener;
protected StreamSerializer serializer = new StreamSerializer();
protected PacketListener listener;

public BasicStackCleanerComponent(@Nonnull RenameProcessor processor, @Nonnull ProtocolManager protocolManager) {
this.processor = Preconditions.checkNotNull(processor, "processor cannot be NULL");
Expand All @@ -32,19 +42,78 @@ public BasicStackCleanerComponent(@Nonnull RenameProcessor processor, @Nonnull P

@Override
protected void onRegistered(@Nonnull Plugin plugin) {
protocolManager.addPacketListener(listener =
new PacketAdapter(plugin, ConnectionSide.CLIENT_SIDE, ListenerPriority.HIGH, Packets.Client.SET_CREATIVE_SLOT) {
protocolManager.addPacketListener(listener = new PacketAdapter(adapterBuilder(plugin)) {
@Override
public void onPacketReceiving(PacketEvent event) {
final PacketContainer packet = event.getPacket();

switch (event.getPacketID()) {
case Packets.Client.PLACE:
case Packets.Client.SET_CREATIVE_SLOT:
// Do the opposite
unprocessFieldStack(event, packet.getItemModifier().read(0));
break;

case Packets.Client.CUSTOM_PAYLOAD:
String channel = event.getPacket().getStrings().read(0);

if ("MC|BEdit".equals(channel) || "MC|BSign".equals(channel)) {
byte[] data = packet.getByteArrays().read(0);

// Attempt to unprocess this item stack
try {
packet.getByteArrays().write(0, unprocessByteStack(data));
} catch (Exception e) {
throw new RuntimeException("Unable to handle byte array: " + Bytes.asList(data));
}
}
break;
default :
throw new IllegalArgumentException("Unrecognized packet: " + event.getPacketID());
}
// Thread safe too!
if (event.getPacketID() == Packets.Client.SET_CREATIVE_SLOT) {
// Do the opposite
processor.unprocess(event.getPacket().getItemModifier().read(0));

}
}
});
}

/**
* Unprocess an item stack in a packet field.
* @param stack - the item stack to process.
*/
protected void unprocessFieldStack(PacketEvent event, ItemStack stack) {
processor.unprocess(stack);
}

/**
* Unprocess an item stack transmitted as a byte array in the custom data payload packet.
* @param data - the data.
* @return The unprocessed item stack.
* @throws IOException If anything went wrong.
*/
protected byte[] unprocessByteStack(byte[] data) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
ItemStack stack = serializer.deserializeItemStack(
new DataInputStream(new ByteArrayInputStream(data))
);

processor.unprocess(stack);
serializer.serializeItemStack(new DataOutputStream(output), stack);
return output.toByteArray();
}

/**
* Initialize the parameters used to construct the packet listener.
* @param plugin - the current plugin.
* @return The parameters for the packet listener.
*/
protected AdapterParameteters adapterBuilder(Plugin plugin) {
return PacketAdapter.params(plugin,
Packets.Client.PLACE, Packets.Client.SET_CREATIVE_SLOT, Packets.Client.CUSTOM_PAYLOAD).clientSide();
}

@Override
protected void onUnregistered(@Nonnull Plugin plugin) {
protocolManager.removePacketListener(listener);
Expand Down

0 comments on commit a37ccfc

Please sign in to comment.