Individual Signs
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, and the minecraft protocol isn't changing anything sign-related.
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 IndividualSigns 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 update the sign contents for a player.
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 modified by some plugin.
- setCancelled(boolean cancelled) - If the event is cancelled the sign contents won't get updated for the affected player, leaving it at their current content (blank if all SignSendEvents get cancelled).
- 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 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) { return player.getName(); } }; getLogger().info("Plugin 'InSigns' found. Using it now."); } else { getLogger().info("Plugin 'InSigns' not found. Additional sign features disabled."); } } |
Plugins using InSigns
- Paintball War Edition - Offering individual paintball statistics signs.
- ScoreboardStats - Offering some individual general statistics signs.
Let me know if your plugin uses InSigns and you want to be mentioned here.
Statistics
This plugin uses bStats to collect anonymous usage statistics to determine the how many servers are using the plugin and with which minecraft versions it is used with the most. All collected information can be publicly viewed here: https://bstats.org/plugin/bukkit/InSigns
You can disable bStats for all plugins on your server by editing the file plugins/bStats/config.yml, or alternatively disable it only for IndividualSigns by setting 'metrics-stats' to 'false' inside InSigns' config.
Donations
If you like this plugin, consider supporting its development by making a donation.
Thanks in advance!
@Duffa13
It's working fine for me on 1.8.3
Make sure your version of ProtocolLib is up to date.
Any update coming for Spigot 1.8.3?
@SM0K3YHD
Not by myself.
is it still possible to develop this idea?
@SM0K3YHD
I think there was a plugin doing this. Not sure if it still exists.
is this possible with heads?/other plugin or something??
IndividualSigns v2.3
IndividualSigns v2.2
@robodude99
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.
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.
@madtomic
You could use v2.0 if you want compatibility for 1.7.9.
Can you add support for 1.7.9
IndividualSigns v2.1
@blablubbabc
Oh well, okay. Thanks for your help! :)
@Smootey
Nope, probably not.
@blablubbabc
So I don't even need Individual Signs anymore for it then?
@Smootey
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).
@blablubbabc
Here my SignSendEvent:
Greets ~
@Smootey
You are not running Mc 1.8, right? InSigns isn't yet updated to 1.8, but I am currently on it.
Anyways, regarding storing found signs:
Your first way of looping through tile entities of a chunk was way better than now looping through all blocks of a chunk (because the list of tile entities is way smaller).
Also I would probably only store data about the locations (worldName, x, y, z) of the signs instead, not the actual Signs nor their Location (which hold a reference to the World object and should therefore not be stored directly, only store their world name).
Also I would store them in some kind of map which is indexed by some kind of chunk coordinates-object, so that I can easily find and remove the data for a certain chunk (for example on chunk unloads).
Regarding sending sign updates: I would probably limit the sign updates to certain signs only, for example the signs of the chunk the player is currently in. Or only for the chunks in a certain radius around a player.
A class which holds location information about a sign's location could look like this:
A class holding chunk coordinates could look similar, but only with x and z coordinate.
Also, how does your event handler for the SignSendEvent look like?
@blablubbabc
Okay, so, I've found my errors and now he's updating, but the sign is blank after one update :s
Here my classes:
ChunkLoadListener:
and here my Main:
Greets, Smootey
@Smootey
Does the 'if(sign.getLine(1).equals("\u00a7a\u00a7lBank"))' get triggered (you could add a debug broadcast there two)?
Also how does your listener looks like, the one listening for the SignSendEvent? Does the event trigger for you?
On another note it would probably be more performant to keep track of those bank signs instead of contantly re-iterating over all those loaded chunks: maybe only iterate through the chunks once on chunk load, keep track of the sign locations and also keep track of the locations when someone creates a new bank sign, until chunk unload.