-
-
Notifications
You must be signed in to change notification settings - Fork 355
Configuring Metadata in Towny objects.
The Towny API has a list of properties already hooked to towny objects that are editable by Towny plugin developers. While a lot of these are useful in the context of Towny, as an independent plugin developer, you may want to store other custom data within some towny objects. This is the purpose of metadata.
- Data not stored in the Towny plugin is decentralized which makes it hard for other devs to see and manipulate your stored data, this is especially problematic if another plugin depends on data from the plugin you are developing. Towny metadata is centralized thus allowing for easy access via documentation, and key-names.
- If your plugin requires external data on different towny objects developing a backend to deal with it, can be cumbersome and time intensive.
- Metadata allows for custom fields in towny objects like the ones already included, ie: pvp, explosions, residents.
- Plugins do not have to worry about towny objects like towns, nations, or residents changing names and losing data associated with them.
All TownyObjects can use hold MetaData and these include:
- Towns
- Nations
- Residents
- TownyWorlds
- TownBlocks
- PlotGroups
Check out Plugins using Metadata
The API uses a data field system for storing metadata, which essentially works a key-value storage. Plugins will create their own unique keys, and store a persistent value. Towny comes equipped with several primitive data fields already that work out of the box. However, Towny also provides an API to create and store custom data fields that allow storing more than just primitive values.
-
CustomDataField
(Base Class)IntegerDataField
StringDataField
BooleanDataField
DecimalDataField
LongDataField
ByteDataField
LocationDataField
ListDataField
Each of the data fields hold a specific type of data that is properly deserialized when Towny loads.
Towny provides a MetaDataUtil which can save you a bit of time with getting and setting metadata for these basic types.
In the case that none of the Towny-provided data fields satisfy your use case, you can create a custom data field class detailed on this page.
Each data field will essentially have three member variables: key, value, and label.
- Key: A unique non-empty string that identifies metadata property. Metadata is not shared between towny objects, so keys only need to be unique against other metadata keys for that specific towny object. However, a good general key should prefix the plugin name before the keyname e.g.
towny_explosion
. - Value: The value stored in the metadata. This depends on the specific data field chosen.
- Label: An optional string used to display the metadata on the towny object. For example, a metadata field with the label
Kills
associated with a specific town will show up when the town status of that town is shown (via/t
or/t [townname]
. Do not set labels if you want hidden metadata.
- Make sure that your plugin depends on Towny, you can do this by adding this to your plugin.yml:
depends: [Towny]
- Add Towny as a dependency to Maven as described here.
If a plugin registers global metadata, it provides a way for server administrators to add that metadata via in-game commands. This step is not necessary, if a plugin plans on having full control the metadata and does not want admin interaction with the metadata.
The metadata will be registered on load.
public class Plugin extends JavaPlugin {
// Parts of a datafield
private static String keyname = "plugin_intfield"; // This key must be unique to your plugin.
private static int defaultVal = 0; // This is the default value your data field will have whenever its added to an object.
private static String label = "Super Duper Int Field"; // Label that will be displayed when the towny object's status is shown.
// Use those parts to create a new data field to store an integer
private static IntegerDataField myCustomIntegerField = new IntegerDataField(keyname, defaultVal, label);
// Called when the plugin first loads.
@Override
public void onLoad() {
// (Optional) Try to globally register the data field.
// Globally registering data fields allow them to be modified in-game by administrators.
try {
TownyAPI.getInstance().registerCustomDataField(myCustomIntegerField);
} catch (KeyAlreadyRegisteredException e) {
getLogger().warning(e.getMessage()); // A flag with the same key name already exists try again
}
getLogger().info("Custom data field successfully registered!");
}
public static IntegerDataField getMyCustomIntegerField() {
return myCustomIntegerField;
}
}
// Create a new instance of the data-field passing in a unique key, and a default value.
IntegerDataField idf = new IntegerDataField("plugin_intfield", 10);
// For townblock objects
townblock.addMetaData(idf);
// For town objects
town.addMetaData(idf);
// For nation objects
nation.addMetaData(idf);
// Same for the rest of the Towny objects
Alternatively, if you want your metadata available to all towns by default you could loop through all of the objects on initialization and add the custom data.
private IntegerDataField idf = new IntegerDataField("plugin_idf", 10);
public void manipulateData(TownBlock townBlock) {
// Check if the townblock has metadata matching they key.
if (townBlock.hasMeta(idf.getKey())) {
// Get the generic data field from the townblock.
// In later versions, this process can be simplified via TownyObject#getMeta(key, IntegerDataField.class)
// which will fetch the data field matching the key as an IntegerDataField.
CustomDataField cdf = townBlock.getMeta(idf.getKey());
// Make sure that the datafield is an integer data field which is what 'idf' is.
if (cdf instanceof IntegerDataField) {
// Cast the data field to an integer data field.
IntegerDataField myfield = (IntegerDataField) cdf;
// Set the value
myfield.setValue(10);
}
}
}
With that you should be able to edit, add and change metadata.
This example file will demonstrate how to create, read, update, and delete metadata.
public class Plugin extends JavaPlugin {
private static String keyName = "plugin_key"; // A key name unique to your plugin.
private static int defaultVal = 0; // Default value of your data field.
private static String label = "Super Cool Int Field"; // Label for the metadata that will be displayed when status is called for that towny object.
private static IntegerDataField myCustomIntField = new IntegerDataField(keyName, defaultVal, label);
// Register the metadata globally for admins to add the metadata to objects via in-game commands.
@Override
public void onLoad() {
// Try to register the data field.
try {
TownyAPI.getInstance().registerCustomDataField(myCustomIntField);
} catch (KeyAlreadyRegisteredException e) {
getLogger().warning(e.getMessage()); // A flag with the same key name already exists try again
}
getLogger().info("Flag successfully registered!");
}
// Add metadata (Create)
public void addMetadataToTown(Town t) {
// Simply clone the metadata and add it to the town.
// If the object is not cloned, then every time you change the value for the field,
// it will change the value across all towny objects that have the metadata.
t.addMetaData(myCustomIntField.clone());
}
// Fetch metadata (Read)
public int getMetaDataFromTown(Town t) {
// Check that the town has the metadata key.
if (t.hasMeta(myCustomIntField.getKey())) {
// Get the metadata from the town using the key.
CustomDataField cdf = t.getMetaData(myCustomIntField.getKey());
// Check that it's an IntegerDataField
if (cdf instanceof IntegerDataField) {
// Cast to IntegerDataField
IntegerDataField idf = (IntegerDataField) cdf;
// Return the read value which is an integer.
return idf.getValue();
}
}
// Return a default value
return -1;
}
// Update metadata (Update)
public void updateMetaDataFromTown(Town t, int updatedVal) {
// Check that the town has the metadata key.
if (t.hasMeta(myCustomIntField.getKey())) {
// Get the metadata from the town using the key.
CustomDataField cdf = t.getMetaData(myCustomIntField.getKey());
// Check that it's an IntegerDataField
if (cdf instanceof IntegerDataField) {
// Cast to IntegerDataField
IntegerDataField idf = (IntegerDataField) cdf;
// Update the value
idf.setValue(updatedVal);
}
}
}
// Remove metadata (Delete)
public void removeMetaDataFromTown(Town t) {
t.removeMetaData(myCustomIntField);
}
}
- Home
- FAQ
- How Towny Works - Comprehensive guide for admins & players.
- Video Tutorials - Watch and learn with Major Graft.
- TownyAPI - Guide for plugin developers.
- Discord - Get involved with other Towny Admins, Plugin Developers, Testers. Support, General Discussion welcome.
- Troubleshooting
- Github Tickets
- Sponsor LlmDl - Support your developer.