Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item Overhaul #1037

Closed
bundabrg opened this issue Jan 9, 2020 · 16 comments
Closed

Item Overhaul #1037

bundabrg opened this issue Jan 9, 2020 · 16 comments
Labels
Confirmed Something is confimed. Feature Request New feature or request.

Comments

@bundabrg
Copy link
Contributor

bundabrg commented Jan 9, 2020

Overview

This is a catch-all issue to address items in BQ 1.12+. I'll go through an link older issues to this one to help track. Please do comment if you have any thoughts/ideas or if this is a horrible idea as this is planning and feasibility stage.

Currently items are defined in items.yml and are fairly simple to setup either manually or by using the /bq item command.

The main issues are:

  • items.yml is used both for defining fully an item (for example the give event) as well as for matching an item (for example in the item condition) which may contain an incomplete definition or even wildcards
  • There are extra item configuration that is not easy to define using this interface. For example NMS data used by other plugins.

It would be handy to some format that provides the most generic way possible of handling Items whilst still allowing plugins to use more short-hand techniques to make it easier. This way you get the best of all worlds by being able to define items in a simpler fashion for plugins (IE, MMOItems could read a mmoitem.yml file that has fields specific to it in an easier format, or bossshop could provide items from its own plugin definitions) whilst still being able to save or generate items that are not internally supported.

This means that BQ should have an Item Provider plugin system that provides the ability to lookup an item in the same manner as currently, but behind the scenes those providers may use differing methods to define an item (it could be from a database, from a yml file, by querying another plugin etc). The Item Provider will allow both a 'match' as well as being able to provide a full definition for an item.

An ItemProvider can also be extended by 3rd parties in the same way ConversationIO, Events, Conditions etc can.

Example

For example, lets say we have the following event:

giveme: give mypackage.cash

When executed BQ will attempt to look up the item in the 'mypackage' package called 'cash'.

BQ could have 2 default ItemProviders called simple and serialized. It would ask each one in turn for the 'cash' item in the package and return a result from the first successful one.

Sample Item Providers

Simple

The simple provider will work the same was as current. It will lookup the item in an items.yml file in the package folder. This will also provide backwards compatibility.

Serialized

The serialized provider will make use of the Spigot item serializer which provides items in a much more verbose format as follows:

path-to-item:
  ==: org.bukkit.inventory.ItemStack
  v: <data version> # determines item data conversions; TODO: documentation of the available versions?
  type: <item type name>
  amount: <stack size>
  meta:
    ==: ItemMeta
    meta-type: <meta data type id>
    display-name: <display name>
    loc-name: <localized display name>
    lore:
    - <lore line>
    - < .. more lore lines .. >
    custom-model-data: <custom model data integer value>
    BlockStateTag: <serialized block state data> # concretize/example? same format as PublicBukkitValues
    enchants:
      <enchantment name>: <enchantment level>
      < .. more enchantment entries .. >
    attribute-modifiers:
      <attribute name>:
      - ==: org.bukkit.attribute.AttributeModifier
        amount: <amount>
        name: <modifier name>
        uuid: <modifier uuid>
        operation: <operation id>
      - < .. more attribute modifiers .. >
      < .. more attributes .. >
    repair-cost: <repair penalty>
    ItemFlags:
    - <item flag name>
    - < .. more item flag names .. >
    Unbreakable: <true|false>
    Damage: <damage value>
    internal: <unhandled data compressed as base64 text>
    PublicBukkitValues: <any custom plugin stored data> # TODO concretize/example?

This could be in a file items-serialized.yml in the package folder.

Changes

  • The command /bq item would need to be updated to define which provider you wish to save the item with, with the default being simple if not specified.

What an ItemProvider needs to provider

  • save - Given a real item, generate a definition (used by /bq item for example)
  • create - Create a real item
  • match - Given a real item, try to match a definition
@SaltyAimbOtter
Copy link
Member

Hello @bundabrg, @Wolf2323 and me looked over the suggestions and this is what we came up with:

  • Feature: Option to ignore any parameters such as durability when matching an item.
    Example format:
 ignore-while-matching:
  - meta.lore
  - amount
  - meta.attribute-modifiers.uuid
  • Scrap the simple item provider in favor of the serialized provider. This stops us from having to update the old simple provider each time something changes (there are already 12 special cases that would need to be updated if Mojang wants some change). The serialized provider will be updated by bukkit then. We would need to write an updater method that checks for the old items.yml file, if it finds one then the old item-creator will create a virtual itemstack that will just be fed into the default serialized item providers create method.
    The serialized item provider should then be renamed to default.

  • QOL: Create a new file for each item in the new /package/items folder instead of having a file per item provider (easier search).

@J0B10
Copy link
Member

J0B10 commented Jan 16, 2020

Remember that the database also needs to be updated so that items inside the backpack are stored as deserialized Item Stacks.
Currently they are saved as QuestItems.

@bundabrg
Copy link
Contributor Author

Thanks for the comments and suggestions.

DB is something I forgot about but it makes sense it should support the most generic format as @joblo2213 has mentioned. That'll need to be performed in the ConfigUpdater.

For backwards compatibility I still think having a simple provider is easy enough for not much work, with the idea being that it is likely to be less used by default if its not as useful especially if no-one updates the provider. Perhaps a /q item migrate<itemname-with-wildcards> <provider> can be provided so someone can migrate an item from one provider to another easily when they are ready. I find the full serialized itemstack to be overly complex sometimes when you just want to quickly make an item directly in a config file. Serialized ItemStack also requires some tricks (like the ignore-while-matching suggestion) to support matching though it should be easy enough to extend it's format to something like:

(assuming separate file per itemstack so no need for itemname)

item_stack:
  ==: org.bukkit.inventory.ItemStack
  v: <data version> # determines item data conversions; TODO: documentation of the available versions?
  type: <item type name>
  ...
ignore-while-matching:
  - meta.lore
  - amount
  - meta.attribute-modifiers.uuid
otherlocalkey: blah

I do agree that having serialized itemstacks as default is a good idea as it doesn't really break backwards compatiblity and will encourage its use. Per-file items sounds like a good idea (MUCH easier to search) for serialized itemstacks as well.

The nice thing about being able to use multiple item providers is that any ideas can of course be written into a new provider or extend an existing one should it be useful as well and each provider can be concentrated on independently of the others to add features.

I also anticipate some additional compatibility item providers. For example there is a lot of data hidden in long hex strings in the serialized stacks that are used by some plugins. I believe Magic with wands uses NMS data which gets hidden here and having it in a simpler format for users to use would be useful (or even provided by the plugins itself entirely without reinventing the wheel)

API-wise I suspect this will be a breaking change since QuestItem is pretty integral to many API's and is inherited by lots of stuff. This will require poring over QuestItem to see how breaking it could be though its possible much of this can be hidden without needing to change the API itself.

@SaltyAimbOtter
Copy link
Member

Ok guys @Wolf2323 and me have reached a critical point while discussion where we have multiple options regarding security and identification methods. Are you up to a live discussion via discord?

@bundabrg
Copy link
Contributor Author

If you can please paste any discussions here once done (if its text based) just so it can be tracked in the issue as well that would be great.

@KingJulian13
Copy link

KingJulian13 commented Jan 23, 2020

How about a flag to block possible "interaction" with a questitem OR to force it into the Quest Inventory all the time.
Food can't be eaten.
Tools can't be used.
Spawneggs can't be placed.
Bonemeal can't be used.
....

I think you get what I mean.

@SaltyAimbOtter
Copy link
Member

SaltyAimbOtter commented Feb 24, 2020

Hello guys, @Wolf2323 and I had a long discussion again where we came up with a somewhat final / complete system. This system has almost no similarities with the old one. Please forget what the former "Quest Item" is:

We will refer to server owners as "creators". This explanation is a first version of a to-be-created wiki page "Items":


Quest items are predefined items that can be given to players with events. They can fulfill numerous use cases such as:

  • Quest rewards (money, trophies etc.)
  • Items that need to be used in a quest such as
    • special tools that the player needs to destroy a wall
    • specific goods that need to be transported from one NPC to another
  • Items from 3th party plugins

Safe an Item

/q item save <package>.<name> [provider] [vanilla] - Saves the held item
When we save or load an item with the default BetonQuest item provider we use the Bukkit serialize and deserialize functionality. The serialized Item is saved to the items folder in the selected package in a separate file. It is possible to specify another item provider such as the default one from BetonQuest.
Right now there are these providers:
default - The default BetonQuest item provider, that can save and load every Item, that we can imagine.
simple - This is an item provider to keep backwards compatibility and make it also easier to create an simple item in the file by hand. This is deprecated and should not be used anymore since this will not get updates for new, special item types and also
some information on the Item could be lost when creating it.

How to use 3th party item providers

Item providers allow BetonQuest to obtain items from a 3th party source. An example of that would be a RPG item plugin where player specific values might be included in the NBT data of the item. To prevent saving these together with all the other item information you can specify 3th party providers in the /q item save command. Example:
/q item save Quest2.Sword2 MMOItems

The vanilla argument:

When you add the argument "vanilla" to the /q item create command the item wont have a UUID or a timestamp (check the corresponding sections to understand these systems). This means that these items can be stacked with vanilla items again and have no flags and so on of BQ.

Variables in items

You can use variables in every part of the serialized item. This allows for translation
and for customizable items such as player heads that have the texture of the player that will obtain the item.
// We also plan to change the variable system to a) make them translatable and b) add a new local variable type for the item config.

Item Flags

/q item flag <add|remove> <package>.<name> [shown|hidden] <flag> [options] - Add or remove a flag from a item
Item Flags are specific options that can be toggled per item. Flags provide mechanics that are not possible in vanilla or that are not so easy to create, for example items that are not destroyed when dropped in lava or the ability to put items in the backpack. These raw flags can be put together to form groups flags. 3th party plugins can also add their own flags. However there are a bunch of raw pre defined BQ flags(The names are not final yet):

  • uneatable
  • unusable - cancel interact event (option for allowing the item to be put in armorstands & itemframes)
  • undropable
  • unplaceable
  • undespawnable
  • unbreakable
  • cant_break_blocks
  • indestructible - cancel entity death event, item is not destroyed from fire or lava
  • keep_on_death
  • cant_leave_inventory
  • allowed_inventory_types - e.g. MERCHANT, CHEST, BARREL
  • backpack_allow - could be moved to the backpack and back
  • backpack_only - is automatically in the backpack and could not moved out
  • backpack_auto - puts the item in the backpack when the player obtains it
  • owner_pick_up_only
  • name-on-drop
  • glowing-on-drop
  • message_on_pick_up
  • message_on_click
  • prevent-first-drop (Player has to press 'Q' twice)

More item flags could be possible, at the moment we think this these are enough. It is also possible to make a seperate plugin that adds much more flags to the items.

Configuring Flags

To manage these group flags there is a new global config called "flags.yml" that looks something like this:

raw-flags:
	uneatable:
		en: "Not edible"
		de: "Some translation"
		fr: "Some translation"
    unusable:
		en: "Not usable"
		de: "Some translation"
		fr: "Some translation"
            kept_on_death:
                        en: "&cKept upon dying"
                        de: "Some translation"
		fr: "Some translation"
	… and 3th party raw flags
rare-reward:
	default-shown: false
	flags:
         - uneatable
         - unusable
         - indestructable
         - cant-be-in-backpack
         - not-placeable
         - keep-on-death

quest-item:
	default-shown: true
	name:
		en: "&cQuest Item"
		de: "Some translation"
		fr: "Some translation"
	flags:
         - cant-leave-inventory{options="All options, the flag has"}
         - not-dropable
         - can-be-in-backpack
         - keep-on-death{shown=true;options="More Options"}

Notice that a group flag can also contain another group flag. That's why we call all the content in a group-flag child-flags.
All flags have a default text tag. It is only shown in the lore of an item when the shown parameter in the command is set. If you choose to put a group flag onto an item this group flag can have its own text that replaces all child-flags tags.

Applying Flags

If we now want to apply a flag or a group-flag onto an item we use this command:
/q item flag <add|remove> . [shown|hidden] [options]

If we wanted to add special behaviours onto an already existing quest item called "GoldenRing" we would run the command "/q item flag add LotR.GoldenRing quest-item".

This will add our special behaviour and some additional information in the items lore.
The lore will now have two new lines, one with "&cQuest Item" and the other one with "&cKept upon dying". The first line will be generated by the group flag, its default value for displaying that information is "true" as you can see in the config above (default-shown: true). Since we did not override that behaviour in the command the text is displayed. The other line is from the child flag that has the option "shown=true" defined in that group flag.
The flag part of the items config will now look like this:

item_flags:
quest-item{shown=true}

If you wanted to also display that this specific item cant be dropped but you dont want to change the group flag because you have applied it elsewhere you can override that shown=false setting (its actually not given in that config above which means it must be hidden) by adding show=true in the items flag option like this:

item_flags:
quest-item{shown=true;not-dropable{shown=true}}

You can also override all other flag options using this. //Concept

Updating Items

/q item update <package>.<name> - Update the given Item
Items are identified by a custom NBT-UUID which makes it very easy to compare them. Items have a unix timestamp saved in their NBT data upon creation. This timestamp is then compared with a unix timestamp in the configuration file of this item. If the timestamp in the NBT data is bigger then the one in the configuration file the plugin know that this item is valid and doesn’t need to be updated. If this is not the case the item will be replaced with a newly generated item.
This means that the unix timestamp in the config needs to be updated, therefore we need to add a new command that will do that for us: /q item update <package>.<name>

To properly update each item BQ has to check the players inventory for items that contain a UUID upon joining. This also happens when opening the backpack, taking an item out of a chest, trapped chest, enderchest, chest minecraft, furnace minecart, hopper minecraft, hopper dropper, dispenser, picking a book up from a lecture.

As long as the UNIX timestamp in the config is not updated the corresponding item will never be updated. Please don't change the timestamp yourself, use the command!

Removing items that are already in players hands

It is possible to remove an item that is already in the game by setting the item to air. When you run the update command afterwards all versions of that item that exist in your server will be replaced with air (which is an empty inventory slot).

Deleting an item

/q item delete <package>.<name> - Deletes the given Item
If you want to remove an items configuration from the items folder inside any package you can run this command. This will not remove the already existing ingame items. Information about how to remove these existing items in in the the paragraph above.


@Wolf2323 and @SaltyAimbOtter would like to implement this in the plugin because we spend tons of time writing this specification (it was rewritten multiple times). We also have wrapped our heads around a lot of very special cases and problems this system has. There are more aspects that we thought of that are not in this specification because it would be too huge. We might add them after this is done in a separate PR.

Refferences to other isues:

@KingJulian13
Copy link

Maybe add some "flag groups" that represent common flags like the current "quest item". In order to group common flags in one command. (specially for newbies)

Either as flag or just probably better: a "flag" that just exists as command, which adds the common flags.

@bundabrg
Copy link
Contributor Author

bundabrg commented Feb 26, 2020

A read through looks pretty good so far. Main question is how to implement the flags on the created items since I assume they will need to exist on the item itself either as part of its description using special flags or stored as NMS tags? Or would BQ be tracking the items itself?

Edit: Man I must be tired. I see you already cover that by tagging the description.

@Wolf2323
Copy link
Member

@KingJulian13
We already planned to add a bunch of default flag groups. A command that will add default flags will not be added, every flag has to be added with the e.g. '/q item flag add CustonItem QuestItem' command. By default, no other options are required by this command.

If you want a flag that add flaggs, then simply crate a new group flag in the config and add the group flag with the command above.

@bundabrg
The items have a NBT tag with the UUID, that is not visible normally(excepting you have a nbt viewer mod) and if we check for flags or other things like this, we only look at the UUID and get the needed information from the config. So it is not possible to see, which flags an item has, until the flag hat the 'shown' option set. Then the translated name is written down to the lore of the item.

@Wolf2323
Copy link
Member

I think the concept is ready for the implementation. But i also think it would be easier to wait, until the Config rework is done, because it contains new features, that would allow to easier load folders that contains the items.yml's.

So Depending on: #995

@SaltyAimbOtter
Copy link
Member

This rework should remove the quest_items_unbreakable config option.
remove_items_after_respawn might also be unnessesary as became visible in #1171.

@SaltyAimbOtter
Copy link
Member

It would be nice if items could be grouped together using config sections. This would then randomly pick one item from the list.
There could also be a random key in the section that sets chances.

@SaltyAimbOtter
Copy link
Member

Changing some item values with event (durabilty, lore, title) could be really usefull.

@SaltyAimbOtter
Copy link
Member

Some sort of wildcards:
grafik

@SaltyAimbOtter
Copy link
Member

Multiple Item Providers:

Vanilla Provider

E.g. vanilla:STONE
Works everywhere out of the box, no assignment in config needed. == BlockSelector??

Simple Provider

E.g. BQsimple:STONE
Assignment in config needed. Similar to old item system.
Allows for easy comparision using only attributes like name etc.

Serialized Provider

E.g. BQserialized:STONE
Assignment in config needed. Full serialization as defined in above concept.

@BetonQuest BetonQuest locked and limited conversation to collaborators Apr 29, 2022
@Wolf2323 Wolf2323 converted this issue into discussion #1858 Apr 29, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Confirmed Something is confimed. Feature Request New feature or request.
Projects
No open projects
BetonQuest 2.0.0
  
TODO Pre-Release 2
Development

No branches or pull requests

5 participants