Skip to content

Instantly share code, notes, and snippets.

@aadnk
Created November 19, 2012 05:33
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save aadnk/4109103 to your computer and use it in GitHub Desktop.
Changing the color of armor with ProtocolLib
package com.comphenix.example;
import java.util.logging.Level;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.StructureModifier;
public class ColorChanger extends JavaPlugin implements Listener {
private ProtocolManager manager;
public void onLoad() {
manager = ProtocolLibrary.getProtocolManager();
}
@Override
public void onEnable() {
manager.addPacketListener(new PacketAdapter(this, ConnectionSide.SERVER_SIDE, Packets.Server.ENTITY_EQUIPMENT) {
@Override
public void onPacketSending(PacketEvent event) {
try {
PacketContainer packet = event.getPacket();
StructureModifier<ItemStack> items = packet.getItemModifier();
ItemStack stack = items.read(0);
// Only modify leather armor
if (stack != null && stack.getType().name().contains("LEATHER")) {
// The problem turned out to be that certain Minecraft functions update
// every player with the same packet for an equipment, whereas other
// methods update the equipment with a different packet per player.
// To fix this, we'll simply clone the packet before we modify it
packet = clonePacket(event.getPacket());
items = packet.getItemModifier();
event.setPacket(packet);
// Color that depends on the player's name
String recieverName = event.getPlayer().getName();
int color = recieverName.hashCode() & 0xFFFFFF;
// Write back the changed object
items.write(0, setColor(stack.clone(), color));
}
} catch (FieldAccessException e) {
getLogger().log(Level.WARNING, "Cannot read field.", e);
}
}
});
}
// Should probably be included with ProtocolLib
private PacketContainer clonePacket(PacketContainer packet) throws FieldAccessException {
PacketContainer copy = manager.createPacket(packet.getID());
StructureModifier<Object> source = packet.getModifier();
StructureModifier<Object> destination = copy.getModifier();
for (int i = 0; i < source.size(); i++) {
destination.write(i, source.read(i));
}
return copy;
}
private static ItemStack setColor(ItemStack item, int color) {
CraftItemStack craftStack = null;
net.minecraft.server.ItemStack itemStack = null;
if (item instanceof CraftItemStack) {
craftStack = (CraftItemStack) item;
itemStack = craftStack.getHandle();
} else if (item instanceof ItemStack) {
craftStack = new CraftItemStack(item);
itemStack = craftStack.getHandle();
}
NBTTagCompound tag = itemStack.tag;
if (tag == null) {
tag = new NBTTagCompound();
tag.setCompound("display", new NBTTagCompound());
itemStack.tag = tag;
}
tag = itemStack.tag.getCompound("display");
tag.setInt("color", color);
itemStack.tag.setCompound("display", tag);
return craftStack;
}
}
@aadnk
Copy link
Author

aadnk commented Jul 24, 2013

Keep in mind a lot of this could be simplified in the newest version of ProtocolLib and Bukkit:

ProtocolLibrary.getProtocolManager().addPacketListener(
    new PacketAdapter(this, ConnectionSide.SERVER_SIDE,
            Packets.Server.ENTITY_EQUIPMENT) {
        @Override
        public void onPacketSending(PacketEvent event) {
            PacketContainer packet = event.getPacket();
            ItemStack stack = packet.getItemModifier().read(0);

            // Only modify leather armor
            if (stack != null && stack.getType().name().contains("LEATHER")) {
                // The problem turned out to be that certain Minecraft functions update
                // every player with the same packet for an equipment, whereas other
                // methods update the equipment with a different packet per player.
                // To fix this, we'll simply clone the packet before we modify it
                event.setPacket(packet = packet.deepClone());
                stack = packet.getItemModifier().read(0);

                // Color that depends on the player's name
                String recieverName = event.getPlayer().getName();
                int color = recieverName.hashCode() & 0xFFFFFF;

                // Change the color
                LeatherArmorMeta meta = (LeatherArmorMeta) stack.getItemMeta();
                meta.setColor(Color.fromBGR(color));
                stack.setItemMeta(meta);
            }
        }
    });

@WASasquatch
Copy link

This method appears to be nullified in 1.9.2 ~ ProtoclLib 3.7.0-BETA. No errors, but leather armor is unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment