Created
December 28, 2013 14:15
-
-
Save aadnk/8159934 to your computer and use it in GitHub Desktop.
Allow players to edit signs through a command.
This file contains hidden or 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
package com.comphenix.example; | |
import java.lang.reflect.InvocationTargetException; | |
import java.util.concurrent.ConcurrentMap; | |
import org.bukkit.Location; | |
import org.bukkit.block.Block; | |
import org.bukkit.block.Sign; | |
import org.bukkit.command.Command; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.entity.Player; | |
import org.bukkit.event.Listener; | |
import org.bukkit.plugin.java.JavaPlugin; | |
import com.comphenix.protocol.PacketType; | |
import com.comphenix.protocol.ProtocolLibrary; | |
import com.comphenix.protocol.events.PacketAdapter; | |
import com.comphenix.protocol.events.PacketContainer; | |
import com.comphenix.protocol.events.PacketEvent; | |
import com.comphenix.protocol.injector.BukkitUnwrapper; | |
import com.comphenix.protocol.reflect.StructureModifier; | |
import com.comphenix.protocol.reflect.accessors.Accessors; | |
import com.comphenix.protocol.reflect.accessors.FieldAccessor; | |
import com.comphenix.protocol.utility.MinecraftReflection; | |
import com.google.common.base.Objects; | |
import com.google.common.collect.MapMaker; | |
public class SignEditorPlugin extends JavaPlugin implements Listener { | |
private ConcurrentMap<Player, Location> editing = new MapMaker().weakKeys().makeMap(); | |
// For accessing the underlying tile entity | |
private FieldAccessor tileEntityAccessor; | |
private FieldAccessor booleanAccessor; | |
private FieldAccessor humanAccessor; | |
@Override | |
public void onEnable() { | |
ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler( | |
new PacketAdapter(this, PacketType.Play.Client.UPDATE_SIGN) { | |
@Override | |
public void onPacketReceiving(PacketEvent event) { | |
Player player = event.getPlayer(); | |
StructureModifier<Integer> ints = event.getPacket().getIntegers(); | |
Location loc = new Location(player.getWorld(), ints.read(0), ints.read(1), ints.read(2)); | |
// Allow | |
if (Objects.equal(editing.get(player), loc)) { | |
setEditingPlayer((Sign) loc.getBlock().getState(), player); | |
} | |
} | |
}).syncStart(); | |
} | |
private void setEditingPlayer(Sign sign, Player player) { | |
// Extract a TileEntitySign from a CraftSign | |
if (tileEntityAccessor == null) { | |
Class<?> tileEntity = MinecraftReflection.getMinecraftClass("TileEntitySign"); | |
Class<?> humanClass = MinecraftReflection.getMinecraftClass("EntityHuman"); | |
tileEntityAccessor = Accessors.getFieldAccessor(sign.getClass(), tileEntity, true); | |
booleanAccessor = Accessors.getFieldAccessor(tileEntity, boolean.class, true); | |
humanAccessor = Accessors.getFieldAccessor(tileEntity, humanClass, true); | |
} | |
Object tileEntity = tileEntityAccessor.get(sign); | |
booleanAccessor.set(tileEntity, true); | |
humanAccessor.set(tileEntity, BukkitUnwrapper.getInstance().unwrapItem(player)); | |
} | |
@Override | |
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { | |
if (sender instanceof Player) { | |
Player player = (Player) sender; | |
@SuppressWarnings("deprecation") | |
Block block = player.getTargetBlock(null, 50); | |
if (block != null) { | |
displaySignEditor(player, block); | |
} | |
} | |
return true; | |
} | |
/** | |
* Display a sign editor for the given player. | |
* <p> | |
* The block could also be client-side. | |
* @ | |
* @param sign - the sign to edit. | |
*/ | |
private void displaySignEditor(Player player, Block sign) { | |
if (!player.getWorld().equals(sign.getWorld())) | |
throw new IllegalArgumentException("Player and sign must be in the same world."); | |
PacketContainer editSignPacket = new PacketContainer(PacketType.Play.Server.OPEN_SIGN_ENTITY); | |
// Permit this | |
editing.put(player, sign.getLocation()); | |
editSignPacket.getIntegers(). | |
write(0, sign.getX()). | |
write(1, sign.getY()). | |
write(2, sign.getZ()); | |
try { | |
ProtocolLibrary.getProtocolManager().sendServerPacket(player, editSignPacket); | |
} catch (InvocationTargetException e) { | |
throw new RuntimeException("Cannot send packet.", e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment