advanced-achievements icon indicating copy to clipboard operation
advanced-achievements copied to clipboard

API: give custom achievement to player that does not exist in the config yet

Open Silthus opened this issue 4 years ago • 6 comments

:information_source: Basic information

I have a question about the API. I want to create an additional plugin that handles location achievements and allows creating them via commands and with a radius without relying on worldguard regions, signs or other unneeded stuff.

So I want to have a database with all locations and the achievement name. By default they don't look pretty but can be customized using the given key under the custom section in the config. Is that possible?

:question: Help request

  • Is it possible to add new custom achievement types on the fly via the API?
  • How can I give a player a single custom achievement that may not exist yet and has no counter?

Thank you for the help!

The plugin will of course be open source or if you like the idea, be integrated into the plugin itself.

Silthus avatar Mar 25 '21 14:03 Silthus

Hello @Silthus ! 👋🏻

Thanks for your interest in this project! The overall idea sounds like a good one.

* Is it possible to add new custom achievement types on the fly via the API?

Unfortunately, this is not currently possible. The main blocker to doing this is the fact that achievement categories are currently modelled as enums. For example: https://github.com/PyvesB/advanced-achievements/blob/master/advanced-achievements-api/src/main/java/com/hm/achievement/category/MultipleAchievements.java

This makes achievement types very static. I don't think it would too hard to change this though, it's mostly a matter of turning the enum into a class to which new categories can dynamically be added.

* How can I give a player a single custom achievement that may not exist yet and has no counter?

I'm going to disappoint you as well, achievements are currently only driven by config.yml. However, some of the refactoring that was conducted as part of the 7.0.0 release would allow to do this much more easily, as it would be a matter of adding achievements to AchievementMap.

I'm unsure how you would specify all the parameters (Type, Goal, etc.) and rewards for a dynamic achievement. You mentioned creating achievements via commands in your third-party plugin, I can't imagine it being practical to include all the information for an achievement.

In the meantime, an alternative would be to leverage the Commands or Custom categories, append new achievements to Advanced Achievements' config.yml for one of those categories, and call /aach reload. Admittedly clunky, but it should work fine.

I'm sorry I'm not able to provide a perfect solution, but let me know whether this information helps! 😉

PyvesB avatar Mar 25 '21 22:03 PyvesB

Hi @PyvesB

thank you for the detailed and quick reply. However I think the current API does make it possible what I thought of. Here is a code snipped on how I thought it might work:

AdvancedAchievementsAPI api = ...;

String category = "locations";
String identifier = "loc1";
String name = "Super dupa location";
String message = "You reached the super location";
Achievement achievement = api.getOrCreateAchievement(category, identifier, name, message);
// or use the achievement builder and then register the achievement
Achievement achievement = api.registerAchievement(new AchievementBuilder()....build());
// or get an existing achievement from the plugins category
Achievement achievement = api.getAchievement(category, identifier);

api.addAchievement(achievement, player);

And in the config.yml a new block is created for each achievement created via the API, maybe under a new plugins category?

...

Custom:
  votes:
    10:
      Message: Voted 10 times for the server!
      Name: customs_votes_10
      DisplayName: Server fan
      Type: normal
      Reward:
        Money: 5

Plugins:
  locations:
    loc1:
      Name: loc1
      DisplayName: Super dupa location
      Message: You reached the super location
      # the rest are defaults that are filled in
      Type: normal
      Reward: {}

What do you think? This would make it also possible to create more advanced custom achievements in plugins that do not rely on counters.

Silthus avatar Mar 26 '21 23:03 Silthus

// or use the achievement builder and then register the achievement Achievement achievement = api.registerAchievement(new AchievementBuilder()....build());

This feels like a good design.

As a first step, it would be useful to implement this for existing categories. The API method would insert the right blob of YAML in the existing configuration (i.e. in the right category section & sub-category if any).

Once that's done, you're unblocked and can leverage the existing Commands category. For example, calling:

Achievement loc1 = new AchievementBuilder().category(CommandAchievements.COMMANDS).subcategory("loc1").displayName("Super dupa location").message("You reached the super location").build();
api.registerAchievement(loc1);

Would produce:

Commands:
  loc1:
    Name: loc1
    DisplayName: Super dupa location
    Message: You reached the super location
...

And then your plugin could simply call:

Bukkit.getPluginManager().callEvent(new PlayerAdvancedAchievementEvent(player, loc1));

As a second step, longer term goal, an API method such as api.registerCategory could be implemented so that you can create a clean dedicated category for your plugin. This would require getting rid of the enums I mentioned in my previous comment. :)

PyvesB avatar Mar 27 '21 18:03 PyvesB

That sounds great!

Silthus avatar Mar 27 '21 20:03 Silthus

Would you like to help with some of this? The work can be broken down into small pieces that can easily be picked up without needing deep knowledge of the plugin.

In particular, a utility class that maps from an Achievement object to it corresponding YAML string representation will be needed. Basically something very similar to the AdvancementJsonHelper class (and its unit tests here).

PyvesB avatar Mar 28 '21 15:03 PyvesB

I will were I can, but unfortunately I don't have a lot of time at the moment. I will do my best and send a PR once I find the time.

Silthus avatar Mar 29 '21 18:03 Silthus