Carpet

Carpet

2M Downloads

[Scarpet] Add advancements API

Firigion opened this issue ยท 0 comments

commented

Right now the only way to handle advancements from carpet is through run('advacement grant|revoke ...'), which is always undesirable. There's also no way to hook into the event of a player earning and advancement, which is usually the vanilla commands way to detect a bunch of things. To use that in scarpet, the current way is to hook into that event through a datapack that runs a scarpet command, which is less than optimal. Addig this API would grant a lot of flexibility, the same way adding the __on_statistic API did.

For instance, here's an example by the discord duser @chyx that uses advancements to detect inventory changes: they created the custom advancement (see here for orignial message).

{ "rewards":{"function":"chyx:invupd"},
  "criteria": {
    "example": {
      "trigger": "minecraft:inventory_changed",
      "conditions": {
      }
    }
  }
}

and packed a function that simply signlas an event and removes the advancement

script run signal_event('invupd', null, player())
advancement revoke @s only chyx:xd

I suggest an API that follows something like the following. Keep in mind this is a suggestion from someone that barely ever used vanilla advancements, so I might be missing something.

  • An event: __on_advancement(player, advancement), mimicking the __on_statistic event. Not sure if the callback is gonna need more arguments, it will depend on what the MC API exposes, I assume.
  • A way to get advancement trees: advancement_tree(advancement, direction). Here direction is one of 'up' or 'down', to return the parent and children advancements of the given one, respectively. If advancement is null, return a list of all root advancements. The return format for this is not gonna be user friendly, because scarpet doesn't have many data structure options, but I think a nested list should be okay.
  • A way to grant and revoke advancements: advancement_grant(player, advancement, direction?, end?) and the accompanying advancement_revoke(player, advancement, direction?, end?). If mode is null it only grants/revokes the given advancement, 'up' to affect all parent advancements, 'down' for all children. Optional end parameter indicates where to stop granting or revoking advancements. Has to be a parent if mode is 'up' or child if it's 'down'. end can also be an integer to indicate ammount of layers to remove. The two functions can be merged into advancement(player, mode, direction?, end?) but i think it makes the API a bit less readable. Maybe advancement_modify.
  • A way to query advancements, which could either be baked into the current querry functionality (query(player, 'advancement', advancement?) or into the proposed new API, like it's the case for scoreboards right now (advancement_query(player, adcanvement?). If queried with null, returns a list of all the advancements the player has. I don't think there's a need to query for multiple advancemets at once.
  • A way to define new advancements: signature for this one is difficult, but it's a key function for this API to be useful and I don't think adding it will be much of a stretch, seeing how there's already a create_datapack function in scarpet. Easiest way to implement it is to just have a map as input data and have scarpet format the map into json, like create_datapack currently works: advancement_new(resource_name, data).
  • A way to read an advancement's properties. Not sure if this one is needed, but it would be something like advancement_properties(advancement, props?). If queried with null it gives a list of all the non empty properties of the advancement, or a map of all of them. If queried with a property (string), returns the value. If queried with a lsit of properties, returns a map of property:value pairs. The Wiki lists all the properties an advancement can have.
  • An additional option is to have another event __on_advancement_trigger(player, trigger, data) that listens to the triggers that advancements use. Using this one could void the need for the advancement_new function and maybe even for the __on_advancement event, while also making the mechanics that makes advancements so useful easily available. In particular, it would be nice to not need to create a new advancement only to know when a player bred two animals (minecraft:bred_animals), which currently can only be detected through advancements. How to format data is gonna be a hard question to answer, tho, since triggers are usually defined with a bunch of contidions.

Of course like with everything in scarpet, all advancements have an implied minecraft: namespace, but should allow for arbitrary namespaces for customa dvancements both added through scarpet and manually through a datapck.