PlaceholderAPI - A hub for your placeholders

Services are easy - you use a PlaceholderService interface describing the API entry point, and a PlaceholderServiceImpl class which implements the interface, providing the API. Then you set the class as the provider for the interface.

Thanks for the explanation! Working on that now.

Does anyone know have ideas on how other plugins can register their placeholders?

I would start by trying to make your system generalized. If you want to do this the way extended_clip did on Spigot, all you need to add to your Expansion class is a parsing method, which accepts a Player and a String; you should also decide whether you want this to return String or Text; String is simple to use and modify but Text supports click and hover actions, colors, etc. nicely which allows plugins to customize what they return. You already have the format in each of your expansions; just don’t make them static and add it to the original Expansion class.

The next step would be to create a registry, which holds all of your placeholder expansions. It should also have a method that accepts a string and returns the matching expansion; so if the string is “player_name”, it returns the Player expansion. When your plugin is setup (using GameInitializationEvent) you can register your own internal expansions to the registry. Your main class would then have reference to this registry and would have a getter method for it as well.

Your service would then be the next step to accomplish. You should have two primary functions: parse placeholders and register a placeholder. Parse should mimic what your current API does, except rather than using a switch on the token, pass it to your registry to determine the correct expansion to use. Register should allow plugins to add their own Expansion class to your plugin. Later on, you may decide to integrate certain functions into your plugin rather than having others handle it, such as expansion configuration, which gives other plugins nice customization options. I would also add a register function that accepts an Object and a BiFunction<Player, String, String>; the Object would be the plugin that owns the placeholder, from which you could get the unique id of the plugin, and the BiFunction would mimic the onPlaceholderRequest that you have in the Expansion class. This allows plugins to register simple placeholders more easily, which is similar to how Sponge handles simple commands.

This is how I would add the service to Sponge and allow plugins to register their own placeholders. I will look into creating a PR for your github repo that would accomplish this if you would like to see a code example, but these are the steps I would follow to accomplish these ideas.

Relational placeholders would change based on both who is sending the message and who is seeing the message. A good example of this would be Factions. For instance, if there are three players in different factions, one faction at war with another, one faction an ally with another, and one neutral, they will all have different relations to each other. If one player chats, their name may be a different color to different people depending on their factions’ relationship. For one player, the sender’s name would be red; another, green; another, neutral; etc.

3 Likes

Paired with AutoBroadcaster this plugin could be really good for providing values to messages.
I thought of this combination while developing my lottery plugin. I could provide the value of the current pot to this plugin which then gets broadcasted by AutoBroadcaster.

Your download link still links to TitleMOTD.

Moved To Ore

How about a placeholder for Bungeecord which says how many players are currently online in total? This might help.

Version 3.0 released!

Full release and info here.

View project on Ore.

1 Like

Fantastic news! Few questions:

  • Would you consider the API itself to be stable, or do you think that you might tweak it soon? I don’t want to start looking at integrating with it if you think the API might still change.
  • What happens if there is a collision between two plugins trying to register the same token or set of tokens? So, if I want to register nucleus_*, but someone else has registered nucleus_*, or a subset of this, such as nucleus_blah, how will the system cope with that?
  • Is there a way for a plugin to use PlaceholderAPI but use different string delimiters instead (so not % % but {} syntax, for example? I guess you could use a TextTemplate, to be fair.
  • Do you have a dedicated Maven repo, or should I just use JitPack for now?

I’d like to create an optional companion (that is, separate plugin) to Nucleus that supports PlaceholderAPI tokens, so Nucleus will be able to dip into PlaceholderAPI (though probably not the % % syntax, more likely to try to support {% %} instead, but I digress), and PlaceholderAPI will be able to benefit from Nucleus tokens.

  • While I am fairly confident that the API will not change, I am not entirely sure as I haven’t quite figured out everything as far as extensibility is concerned. I doubt anything major will change though, unless I can do some simplification without loss of function.
  • If two plugins register with the same identifier, the system only accepts the first one. There are probably other ways of handling this because this seems exclusive in certain situations, however I am not sure there is a better way that is still simple.
  • While TextTemplate is completely supported, I do plan to allow custom delimiters for string parsing at some point; this might break the current API though.
  • I don’t have a dedicated repo, mostly because I don’t know how to set one up. If you could point me in the right direction that would be awesome.

Hopefully that answers your questions.

Out of curiosity, what tokens would you add with Nucleus?

EDIT: I committed to GitHub an update with delimiters that isn’t API breaking unless you want to provide your own implementation of the service, I will push a release soon.

Great, thanks. I imagine JitPack will suffice for you anyway, I had to do a lot of tweaking to set up my own!

With regards to Nucleus, I had my own system set up before this became a thing, you can see it here.

What I would want is a set of tokens that would expose all of the Nucleus tokens, including thirdparties that are registered with the service. So, I would want to register %nucleus_[tokenid]% as a catch all, and pass that through to my parser (except any that would try to reference the bridge, but that’s an implementation detail). Similarly, I plan to add {% %} (and, as an option, % %) support to Nucleus that will pass the token to PlaceholderAPI for parsing, if enabled - that’ll be easy for me to hook in.

I’ve got things such as unique visitor count, prefixes - you can see them all here. Many of them you will already have, but there is the chance I’ll add more, and Nucleus might try to do things differently for different tokens.

It’s what I do with my “primary tokens” and makes complete sense - do plugins know if they get rejected? My registration method just returns false if it can’t do so.

Anyway, all good to know. Thanks!

Because PlaceholderAPI doesn’t discriminate beyond the first '_', you can simply register “nucleus”, and the [tokenid] you would like to parse will be passed as Optional<String> (I will document this later today when I get more time, have some assignments to take care of).

Plugins will know if they get rejected as the register method returns true or false depending on success. Of course, the default expansions registered internally all get priority, however beyond that it’s up to load order. I might consider returning a Tristate instead, to distinguish between rejection and erroring, if necessary.

One thing to note is that, while I recommend it, you do not strictly need to have your plugin ID as an identifier, if for instance it isn’t attached to the plugin’s own functionality but the servers. If you register using the lambda, however, it does attach to plugin ID.

Advice: an error condition should throw an exception - that’s the whole point of them. So, I suggest you just make it throw a checked exception, or document what unchecked exceptions it might throw.

Other than that, great, I should be able to get my backend in order and create a bridge to this, expanding the reach of both plugins. Thanks, your explanation has been a great help.

/papi i player

forge-1.11.2-13.20.0.2227-universal.jar
spongeforge-1.11.2-2227-6.0.0-BETA-2148.jar
Placeholders-3.0.jar

I am aware of that issue and it will be fixed in version 3.1. I am going to update it soon.

Version 3.1 is out!

View the changelog here.

Check out the project on Ore

1 Like

Version 3.2 is out!

View the changelog here.

Check out the project on Ore and GitHub!

I have added a large amount of documentation to the GitHub Wiki. I hope it covers most of the information you are seeking. There is a slight amount of information I have yet to document (ConfigurableExpansions), primarily because I am unsure about a few things for it, however everything else should be complete.

If there is something you feel is missing, let me know and I will try to add it to the wiki.

A new version has been released for PlaceholderAPI, it is available for download here.


What’s new in version 3.3:

  • Added placeholders:
%player_option_[option]% - View a player's option (Like %rank_option_[option]%)
%player_permission_[permission]% - Check to see a player's permission status
   (Like %rank_permission_[permission]%)
%server_unique_players% - Get the number of unique players on the server
  • Some internal fixes and changes

Check out the plugin wiki!

View the plugin on GitHub!

A new version has been released for PlaceholderAPI, it is available for download here.


What’s new in version 3.4:

  • Bugfix for ConfigurableExpansion

Check out the plugin wiki!

View the plugin on GitHub!