Individual Signs

Sign

Description

This plugin displays the text on signs for each player individual differently.

By default this plugin only replaces [PLAYER] on signs with the name and [DISPLAY] with the nick name of the player looking at it.
The permission nodes to create signs containing those tags are insigns.create.player and insigns.create.display.

However InSigns also includes an API for developers of other plugins to easily add own player-specific sign content.

This plugin could for example be used for individual greeting signs at your spawn. Your players will be amazed to see their own name on a sign!

IMPORTANT

This plugin needs ProtocolLib to work.
Make sure you have installed the right version of ProtocolLib.
This plugin should stay compatible with further versions of minecraft and bukkit as long as ProtocolLib doesn't have to change anything on it's API which InSigns is relying on.

Quick Presentation by VariationVault


For plugin developers: easy-to-use API

Here is a small example of how you can use this in your own plugin to display player-specific values on signs.
1.) First of all: add the Individual_Signs jar to your build path (just like you do it with the bukkit.jar)
2.) You can then create a listener which listens for the SignSendEvent (just like you create listeners for bukkit events): this event gets called every time the server is about to send a player the text of a sign.
3.) The event provides easy methods to get the current sign text and to change it:

  • getPlayer() - Gets the player which receives the sign packet.
  • getLocation() - Gets the location of the sign which text is being sent.
  • getLine(int index) - Gets the line of text at the specified index (0-3). The lines are in json format.
  • setLine(int index, String line) - Sets the line of text at the specified index. Has to be in proper json format.
  • isModified() - Whether or not this event was already modified by some plugin.
  • setCancelled(boolean cancelled) - If the event is cancelled the sign packet will not be sent to the player, leaving the sign blank.
  • isCancelled() - Checks whether or not some plugin cancelled this event already.

Example usage of the event to replace "[PLAYER]" with the player's name:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class SignSendListener implements Listener {

    public SignSendListener(Plugin plugin) {
        Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
    }

    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onSignSend(SignSendEvent event) {
        for (int i = 0; i < 4; i++) {
            String line = event.getLine(i);
            if (line.contains("[PLAYER]")) {
                event.setLine(i, line.replace("[PLAYER]", event.getPlayer().getName()));
            }
        }
    }
}

That's it. The InSigns-Plugin will handle all the needed packet manipulation for you.

Some other useful utilities provided by InSigns are:

  • The static method InSigns.sendSignChange(Player player, Sign sign) - Sends a SignUpdate-Packet to the specified player. Useful if you want to update certain signs periodically.
  • The SimpleChanger class which can be used to easily create a listener for simple key->value replacements and permission checks during sign creation. Example for the built-in [PLAYER] -> playerName replacement:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Override
public void onEnable() {
    Plugin insignsPlugin = getServer().getPluginManager().getPlugin("InSigns");
    if ((insignsPlugin != null) && insignsPlugin.isEnabled()) {
        // replaces "[PLAYER]" with the player's name on signs and checks for the 'insigns.create.player' permission
        // whenever a player tries to create a sign with "[PLAYER]" on it
        new SimpleChanger(this, "[PLAYER]", "insigns.create.player") {
            @Override
            public String getValue(Player player, Location location, String originalLine) {
                return player.getName();
            }
        };
        System.out.println("Plugin 'InSigns' found. Using it now.");
    } else {
        System.out.println("Plugin 'InSigns' not found. Additional sign features disabled.");
    }
}


Plugins using InSigns

Let me know if your plugin uses InSigns and you want to be mentioned here.

Notice

This plugin uses Hidendra's Metrics class to report usage stats to mcstats.org. This can be disable by setting 'metrics-stats' to false in the config.

You must login to post a comment. Don't have an account? Register to get one!

  • Avatar of blablubbabc blablubbabc Jan 26, 2015 at 19:53 UTC - 1 like

    IndividualSigns v2.3

    • Fixed: NPE when sending signs with empty lines which were created prior to MC 1.8
    Last edited Jan 26, 2015 by blablubbabc
  • Avatar of blablubbabc blablubbabc Jan 24, 2015 at 16:15 UTC - 0 likes

    IndividualSigns v2.2

    • Removed debug print which was missed.

    @robodude99: Go

    Sorry, haven't seen your comment earlier.
    I don't get this error on my test server. I assume that you are using an incompatible version of ProtocolLib.
    Please make sure that you are using the latest ProtocolLib version from here: http:ci.shadowvolt.com/job/ProtocolLib/

    Edit: Actually, I was now able to reproduce this error (thanks to another ticket). This seems to only occur for signs with empty lines which were created prior to MC 1.8. Check out v2.3 of InSigns.

    Last edited Jan 26, 2015 by blablubbabc
  • Avatar of robodude99 robodude99 Jan 15, 2015 at 19:48 UTC - 0 likes

    I am getting a crazy error when using this. I think it has something to do with ProtocolLib because my plugin is not even implementing it yet, your plugin is just on my server. Here is a snippet.

    [14:37:31] [Server thread/ERROR]: [InSigns] Unhandled exception occured in onPacketSending(PacketEvent) for InSigns
    java.lang.NullPointerException
    	at de.blablubbabc.insigns.UpdateSignPacketUtility.getLinesAsStrings(UpdateSignPacketUtility.java:35) ~[IndividualSigns_v2.1.jar:?]
    	at de.blablubbabc.insigns.InSigns$3.onPacketSending(InSigns.java:76) ~[IndividualSigns_v2.1.jar:?]
    	at com.comphenix.protocol.injector.SortedPacketListenerList.invokeSendingListener(SortedPacketListenerList.java:195) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.SortedPacketListenerList.invokePacketSending(SortedPacketListenerList.java:149) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.PacketFilterManager.handlePacket(PacketFilterManager.java:637) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.PacketFilterManager.invokePacketSending(PacketFilterManager.java:613) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.NettyProtocolInjector.packetQueued(NettyProtocolInjector.java:286) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.NettyProtocolInjector.onPacketSending(NettyProtocolInjector.java:254) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.ChannelInjector.processSending(ChannelInjector.java:368) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.ChannelInjector.access$500(ChannelInjector.java:61) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.ChannelInjector$5.handleScheduled(ChannelInjector.java:334) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.ChannelInjector$5.onMessageScheduled(ChannelInjector.java:302) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.ChannelProxy$2.schedulingRunnable(ChannelProxy.java:110) [ProtocolLib%20(1).jar:?]
    	at com.comphenix.protocol.injector.netty.EventLoopProxy.execute(EventLoopProxy.java:79) [ProtocolLib%20(1).jar:?]
    	at net.minecraft.server.v1_8_R1.NetworkManager.a(NetworkManager.java:140) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.NetworkManager.handle(NetworkManager.java:101) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.PlayerConnection.sendPacket(PlayerConnection.java:858) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.EntityPlayer.a(EntityPlayer.java:544) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.EntityPlayer.s_(EntityPlayer.java:252) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.World.entityJoinedWorld(World.java:1588) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.World.g(World.java:1563) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.World.tickEntities(World.java:1410) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.WorldServer.tickEntities(WorldServer.java:577) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.MinecraftServer.z(MinecraftServer.java:757) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.DedicatedServer.z(DedicatedServer.java:316) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.MinecraftServer.y(MinecraftServer.java:623) [server.jar:git-Spigot-b8f6402-a646500]
    	at net.minecraft.server.v1_8_R1.MinecraftServer.run(MinecraftServer.java:526) [server.jar:git-Spigot-b8f6402-a646500]
    	at java.lang.Thread.run(Unknown Source) [?:1.8.0_05]
    [14:37:31] [Server thread/WARN]: [ProtocolLib] Cannot convert to a String with Apache: null
    [14:37:31] [Server thread/ERROR]: Parameters: 
      { a = { server = { k = "[]", l = NULL, m = NULL, propertyManager = "net.minecraft.server.v1_8_R1.PropertyManager@70144b0f", o = "net.minecraft.server.v1_8_R1.EULA@406f13e3", generateStructures = true, q = "SURVIVAL", r = false, convertable = "net.minecraft.server.v1_8_R1.WorldLoaderServer@6f0c53d8", m = "net.minecraft.server.v1_8_R1.MojangStatisticsGenerator@b598a51", universe = NULL, o = "[]", p = "net.minecraft.server.v1_8_R1.CommandDispatcher@7bcdf386", methodProfiler = "net.minecraft.server.v1_8_R1.MethodProfiler@4e19a37a", q = "net.minecraft.server.v1_8_R1.ServerConnection@2f4a4c6a", r = "net.minecraft.server.v1_8_R1.ServerPing@3b8fdbc6", s = "java.util.Random@1f267207", serverIp = "192.99.149.174", u = 26089, worldServer = "[Lnet.minecraft.server.v1_8_R1.WorldServer;@61f32608", v = "net.minecraft.server.v1_8_R1.DedicatedPlayerList@8fd78da", isRunning = true, isStopped = false, ticks = 1069, d = "DIRECT", e = NULL, f = 0, onlineMode = true, spawnAnimals = true, spawnNPCs = true, pvpMode = true, allowFlight = false, motd = "A Minecraft Server", F = 256, G = 0, g = "[J@5442398e", h = NULL, H = "java.security.KeyPair@2fe596b0", I = NULL, J = "world", demoMode = false, M = false, N = false, O = "", P = "", Q = true, R = 0, S = "menu.generatingTerrain", T = false, U = false, V = "[email protected]63", W = "[email protected]4372b", X =
    
  • Avatar of blablubbabc blablubbabc Jan 10, 2015 at 20:36 UTC - 0 likes

    @madtomic: Go

    You could use v2.0 if you want compatibility for 1.7.9.

  • Avatar of madtomic madtomic Jan 10, 2015 at 16:00 UTC - 0 likes

    Can you add support for 1.7.9

  • Avatar of blablubbabc blablubbabc Jan 02, 2015 at 01:15 UTC - 0 likes

    IndividualSigns v2.1

    • The SignSendEvent now ignores line changes if the line wasn't actually changed.
    • When a player places a sign we now stop scanning the lines of that sign after we find the first tag which the player has no permission for.
    • InSigns.sendSignChange(Player, Sign) now uses bukkit's api for sending the sign update packet.
    • Added new default replacement: [DISPLAY] gets replaced with a players display/nick name (permission: insigns.create.display)
    • Update for MC (spigot) 1.8 and the 1.8 version of ProtocolLib (found here):
      • Removed 15 character limit for Changer and SimpleChanger keys: in MC 1.8 the sign line length now depends on the character widths of the client. Also sign lines can be even longer when using json-formatted lines.
      • Also removed the line wrapping feature because of that.
      • The lines of the SignSendEvent are now in json format as well. Also when you set lines those have to be in proper json-format as well.
  • Avatar of Smootey Smootey Jan 01, 2015 at 21:55 UTC - 0 likes

    @blablubbabc: Go

    Oh well, okay. Thanks for your help! :)

  • Avatar of blablubbabc blablubbabc Jan 01, 2015 at 21:49 UTC - 0 likes

    @Smootey: Go

    Nope, probably not.

  • Avatar of Smootey Smootey Jan 01, 2015 at 21:47 UTC - 0 likes

    @blablubbabc: Go

    So I don't even need Individual Signs anymore for it then?

  • Avatar of blablubbabc blablubbabc Jan 01, 2015 at 21:43 UTC - 0 likes

    @Smootey: Go

    Your event handler looks fine. Have you validated that the event is properly called and that you are setting the lines to the correct values every time?

    Between as you are sending out sign updates frequently to all players anyways you could also send them the individual text directly via bukkit's player.sendSignChange(Location, String[] signLines) instead of modifying the outgoing sign packet via the SignSendEvent (which is great if you don't know the sign locations and only want to send players the individual text once they come near the sign / once minecraft normally sends the sign text).

    Last edited Jan 01, 2015 by blablubbabc

Facts

Date created
Sep 18, 2012
Category
Last update
Jan 26, 2015
Development stage
Release
Language
  • deDE
  • enUS
License
All Rights Reserved
Curse link
Individual Signs
Downloads
17,647
Recent files

Authors

Relationships

Required dependency
ProtocolLib