Skip to content

Instantly share code, notes, and snippets.

@aadnk
Last active December 4, 2018 17:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aadnk/8792659 to your computer and use it in GitHub Desktop.
Save aadnk/8792659 to your computer and use it in GitHub Desktop.
An alternative to TagAPI.
package com.comphenix.example;
import java.util.Arrays;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.events.ListenerPriority;
import com.google.common.base.Joiner;
// Test plugin
public class ExampleMod extends JavaPlugin {
private LookupNameManager manager;
@Override
public void onEnable() {
manager = new LookupNameManager(this);
manager.start(ListenerPriority.NORMAL);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length < 2) {
sender.sendMessage(ChatColor.RED + "Must specify target player and new name.");
return true;
}
@SuppressWarnings("deprecation")
Player target = getServer().getPlayer(args[0]);
String name = Joiner.on(" ").join(Arrays.copyOfRange(args, 1, args.length));
if (target == null) {
sender.sendMessage(ChatColor.RED + "Cannot find player '" + args[0] + "'");
return true;
}
manager.setGlobalName(target, name);
sender.sendMessage(ChatColor.YELLOW + "Renamed " + target + " to " + name);
return true;
}
}
package com.comphenix.example;
import java.util.Map;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.events.ListenerPriority;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
public class LookupNameManager extends NameManager {
// Observing Client -> Entity -> Name
private Table<String, String, String> clientName = HashBasedTable.create();
// Fallback name in case the per-client name is missing
private Map<String, String> globalName = Maps.newHashMap();
// Remove outdated entries
protected boolean autoCleanup = true;
protected Listener bukkitListener;
/**
* Construct a new lookup handler.
* @param manager - the name manager.
*/
public LookupNameManager(Plugin plugin) {
super(plugin);
}
/**
* Start the handler and the associated name mananger.
* @param priority - the listener priority.
*/
public void start(ListenerPriority priority) {
super.start(priority);
registerBukkit();
}
private void registerBukkit() {
Plugin owner = getPlugin();
owner.getServer().getPluginManager().registerEvents(bukkitListener = new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
if (!autoCleanup)
return;
// Clean up table
String removed = e.getPlayer().getName();
clientName.rowKeySet().remove(removed);
clientName.columnKeySet().remove(removed);
globalName.remove(removed);
}
}, owner);
}
/**
* Invoked when we're intercepting the name of an observed entity.
* @param client - the client that is receiving the name.
* @param observedEntity - the entity whose name we are sending.
* @param observedName - the current name of the entity.
* @return The new name of the entity. Use NULL for no change.
*/
public final String handleName(Player client, Player observedEntity, String observedName) {
String changed = clientName.get(client.getName(), observedEntity.getName());
// Fall back to the global name change
if (changed == null) {
changed = globalName.get(observedEntity.getName());
}
return changed;
}
/**
* Set the global name of a given entity.
* <p>
* This will be overridden by {@link #setClientName(Player, Player, String)} for individual clients.
* @param observedEntity - the player entity to rename.
* @param observedName - the new name of this entity.
* @return The previous altered name, or NULL.
*/
public String setGlobalName(Player observedEntity, String observedName) {
checkGlobal(observedEntity);
String original = globalName.put(observedEntity.getName(), observedName);
// See if we need to update the entity
if (!Objects.equal(original, observedName))
updateEntity(null, observedEntity);
return original;
}
/**
* Set the visible name of a player entity for a given client.
* @param client - the client that will see the name change.
* @param observedEntity - the player entity to rename.
* @param observedName - the new name of this entity.
* @return The previous altered name, or NULL.
*/
public String setClientName(Player client, Player observedEntity, String observedName) {
checkClient(client, observedEntity);
String original = clientName.put(client.getName(),
observedEntity.getName(), observedName);
// See if we need to update the entity
if (!Objects.equal(original, observedName))
updateEntity(client, observedEntity);
return original;
}
/**
* Reset the visible name of an entity to the default globally.
* @param observedEntity - the entity whose name will be reset.
* @return The removed custom name, or NULL.
*/
public String resetGlobalName(Player observedEntity) {
checkGlobal(observedEntity);
String removed = globalName.remove(observedEntity.getName());
// Trigger a name update
if (removed != null)
updateEntity(null, observedEntity);
return removed;
}
/**
* Reset the visible name of an entity to the default for a client.
* @param client - the client we're resetting.
* @param observedEntity - the entity whose name will be reset.
* @return The removed custom name, or NULL.
*/
public String resetClientName(Player client, Player observedEntity) {
checkClient(client, observedEntity);
String removed = clientName.remove(client.getName(), observedEntity.getName());
// Trigger a name update
if (removed != null)
updateEntity(client, observedEntity);
return removed;
}
// Throw on NULL
private void checkGlobal(Player observedEntity) {
if (!isStarted())
throw new IllegalStateException("Name mananger hasn't started yet.");
Preconditions.checkNotNull(observedEntity, "observedEntity cannot be NULL");
}
// Here too
private void checkClient(Player client, Player observedEntity) {
Preconditions.checkNotNull(client, "client cannot be NULL");
checkGlobal(observedEntity);
}
/**
* Determine if this handler has started.
* @return TRUE if it has, FALSE otherwise.
*/
public boolean isStarted() {
return bukkitListener != null && super.isStarted();
}
/**
* Determine if we automatically remove logged out entires.
* @return TRUE if we do, FALSE otherwise.
*/
public boolean isAutoCleanup() {
return autoCleanup;
}
/**
* Set whether or not we automatically remove entries of logged out players.
* @param autoCleanup - TRUE to auto-clean, FALSE otherwise.
*/
public void setAutoCleanup(boolean autoCleanup) {
this.autoCleanup = autoCleanup;
}
/**
* Close the current lookup handler and the associated manager.
*/
public void close() {
if (isStarted()) {
HandlerList.unregisterAll(bukkitListener);
super.close();
bukkitListener = null;
}
}
}
package com.comphenix.example;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.google.common.base.Preconditions;
/**
* Represents a name manager.
* @author Kristian
*/
public abstract class NameManager {
protected ProtocolManager manager;
// Listeners
protected PacketAdapter packetListener;
// The parent plugin
protected final Plugin plugin;
/**
* Construct a new player renamer.
* @param plugin - the plugin.
*/
public NameManager(Plugin plugin) {
this.plugin = Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
}
/**
* Start the player renamer component.
* @param priority - the priority of our player modification.
*/
public void start(ListenerPriority priority) {
if (isStarted()) {
throw new IllegalStateException("Cannot start renamer twice.");
}
registerProtocolLib(priority);
}
private void registerProtocolLib(ListenerPriority priority) {
this.manager = ProtocolLibrary.getProtocolManager();
manager.addPacketListener(packetListener =
new PacketAdapter(plugin, priority, PacketType.Play.Server.NAMED_ENTITY_SPAWN) {
@Override
public void onPacketSending(PacketEvent event) {
Player observed = (Player) event.getPacket().getEntityModifier(event).read(0);
// Determine if we are
if (MinecraftReflection.isUsingNetty()) {
handleNetty(event, observed);
} else {
handleLegacy(event, observed);
}
}
});
}
/**
* Process a spawn player packet in version 1.7.2 and above.
* @param event - the packet event.
* @param observed - the observed player entity.
*/
private void handleNetty(PacketEvent event, Player observed) {
WrappedGameProfile profile = event.getPacket().getGameProfiles().read(0);
String name = handleName(event.getPlayer(), observed, profile.getName());
// Update the displayed name
if (name != null) {
event.getPacket().getGameProfiles().write(0, profile.withName(StringUtils.abbreviate(name, 16)));
}
}
// As above, only for 1.6.4 and below
private void handleLegacy(PacketEvent event, Player observed) {
String name = handleName(event.getPlayer(), observed, event.getPacket().getStrings().read(0));
// As above
if (name != null) {
event.getPacket().getStrings().write(0, StringUtils.abbreviate(name, 16));
}
}
/**
* Trigger an entity update.
* @param client - the client that will recieve the update.
* @param observerEntity - the observed entity to update.
*/
protected void updateEntity(Player client, Player observerEntity) {
// A list of the players we will update
List<Player> trackers = client != null ?
Arrays.asList(client) : manager.getEntityTrackers(observerEntity);
manager.updateEntity(observerEntity, trackers);
}
/**
* Invoked when we're intercepting the name of an observed entity.
* @param client - the client that is receiving the name.
* @param observedEntity - the entity whose name we are sending.
* @param observedName - the current name of the entity.
* @return The new name of the entity. Use NULL for no change.
*/
public abstract String handleName(Player client, Player observedEntity, String observedName);
/**
* Retrieve the owner plugin.
* @return The owner.
*/
public Plugin getPlugin() {
return plugin;
}
/**
* Determine if we're currently renaming players.
* @return TRUE if we are, FALSE otherwise.
*/
public boolean isStarted() {
return packetListener != null;
}
public void close() {
if (packetListener != null) {
manager.removePacketListener(packetListener);
packetListener = null;
packetListener = null;
}
}
}
@binka-dev
Copy link

Doesn't work on Minecraft 1.8.

Please update!

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