* Expired data bucket rows will not be queryable via the quest API, they may exist in a table until 5-10 minutes have past and the server will garbage collect and wipe the table clean of expired buckets
Keying is simply a way to uniquely identify a flag, if you want to make some data unique to a player, then you would need something to key uniquely to that player, such as their **character_id**.
If you wanted to set a flag uniquely for a NPC for example, you could use the **npc_type_id**, for a zone you could use the **zone_id**.
All of these circumstances are completely up to you and you have the entire Quest API to grab something that can make something unique!
* Below in this Lua example we will count the number of times a player has talked to an NPC, first by checking if we've got a bucket set at all, if not we will set an expiration time on it. Each time we call set_data, it will not over-ride the original expiration time unless we pass a new time parameter
* To set an expiration time in Perl, very similarly to the Lua example above, you would simply call your `set_data()` or `SetBucket()` function with an expiration flag as your 3rd parameter like so
Manual Keying
```pl
my $bucket_key = $client->CharacterID() . "-example-flag";
* Below are some simple benchmarks used to calculate performance. While even these numbers could be greatly optimized yet, these are plenty good for most use cases that server operators need. If you need even faster temporary data storage within the context of a zone, I would suggest using [[Entity Variables]] as they operate purely in memory
In South Qeynos, you will find an NPC named Vicus Nonad. Vicus is a tax collector, but because of his terrible cold, he needs a player to help make the rounds to collect taxes. The early implementation of this quest script utilized quest globals, and below is an example of replacing the quest global functionality with Data Buckets.
#:: Set a timer "cough" to repeat every 350 seconds (5 min 50 sec)
quest::settimer("cough", 350);
}
sub EVENT_TIMER {
#:: Match the "cough" timer
if ($timer eq "cough") {
quest::emote("coughs and wheezes.");
}
}
sub EVENT_SAY {
if ($text=~/hail/i) {
my $cough_link = quest::saylink("cough");
quest::say("Greetings, $name.My name is Vicus Nonad. <cough>I am the official tax collector for the fine city of Qeynos. <cough>I serve the will of Antonius Bayle, our glorious leader. <cough><cough>Please excuse my [$cough_link]. <cough>");
} elsif ($text=~/cough/i) {
my $help_link = quest::saylink("help with today's collections");
quest::say("Oh, <cough> I am sorry, but it seems I have fallen a bit ill. I was caught out in the rain the other day and my chills have gotten the best of me. <cough> If only someone would [$help_link].. <cough>");
} elsif ($text=~/help with today's collections/i) {
#:: Data bucket to verify quest has been started appropriately
my $bucket_key = $client->CharacterID() . "-tax-collection";
#:: Set a data bucket, quest started
quest::set_data($bucket_key, 1);
my $list_link = quest::saylink("link");
quest::say("Oh thank <cough> you so <cough><cough> much <cough>.. Here is the official collection box. Please collect from each merchant on the <cough> [$list_link]. Then bring me back the combined total of all your collections.");
#:: Give a 17012 - Tax Collection Box
quest::summonitem(17012);
} elsif ($text=~/list/i) {
quest::say("Oh. <cough>I am sorry.. I forgot to give it to you. Here you go. Be sure to give that back when your job is finished. <cough>");
#:: Give a 18009 - List of Debtors
quest::summonitem(18009);
}
}
sub EVENT_ITEM {
#:: Match a 18009 - List of Debtors and 13181 - Full Tax Collection Box
if (plugin::takeItems(13181 => 1, 18009 => 1)) {
quest::say("<cough> Great! Thank you so much. Here is a small gratuity for a job well done. Thank you again. <cough> Antonius Bayle and the People of Qeynos appreciate all yo have done.");
quest::say("Very good <cough> work. But I need both the full tax collection box and the list of debtors. You did get the [" . quest::saylink("list") . "] from me before you left, right? <cough>");
#:: Return a 13181 - Full Tax Collection Box
quest::summonitem(13181);
}
#:: Match a 18009 - List of Debtors
elsif (plugin::takeItems(18009 => 1)) {
quest::say("Very good <cough> work. But I need both the full tax collection box and the list of debtors. You did get the [" . quest::saylink("list") . "] from me before you left, right? <cough>");
}
#:: Return unused items
plugin::returnUnusedItems();
}
```
Above, we see the implementation of the Data Bucket Key. This replaces the use of `quest::setglobal`. In the Database, we see the corresponding key:
quest::say("Oh thank <cough> you so <cough><cough> much <cough>.. Here is the official collection box. Please collect from each merchant on the <cough> [list]. Then bring me back the combined total of all your collections.");
#:: Give a 17012 - Tax Collection Box
quest::summonitem(17012);
#:: Set the qglobal "tax_collection", to a value of "0", for all NPCs and Zones, and last forever
While this implementation may seem to be easier, it should be noted that on a server with many players, running a query through a hash of globals for each event that triggers a look up can cause serious performance issues. Imagine a hash being created for every global qglobal entry (the "5" in the script above), for EVERY event trigger!
Our intrepid adventurer is required to do this quest in order, by speaking with Vicus prior to the merchants in Qeynos who have to pay taxes. To enforce this, we verify that the user has the appropriate data bucket key set (line 9) before offering the dialogue that results in the tax payment:
quest::say("Here are the taxes, $name. Boy, you call the guards and they take their time to show up but be a few days late on your taxes and they send the goons after you. Sheesh!");
The rule ```Character, HeroicStatsUseDataBucketsToScale``` Allows scaling the benefits a Player or Bot receives from Heroic Stats using Data Buckets. This works with other multipliers, as long as a valid data bucket is applied to the character.
Below are valid keys that can be used, and the benefit given if keyed with a value of "1.00" or "1".
| Bucket Key "character-id-KEY" | Description assuming Bucket Value of "1.00" |