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.
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.
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 registerednucleus_*
, or a subset of this, such asnucleus_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 aTextTemplate
, 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.
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 (ConfigurableExpansion
s), 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!