Trying to figure out a flexible solution to a "loot database"

Started by
13 comments, last by kburkhart84 6 years, 9 months ago

So I am building a mix of a 2d survival / action rpg (more towards the action rpg) and something that I am going to need to be able to keep track of is loot. I am going to have hundreds of base items I need to keep track of and then also each "entity" that can drop items will have a loot table of what items it can drop that I need to keep track of and I am trying to figure out an efficent way of doing this. I have an initial idea but what to get input on it.

NOTE: I am doing this in C# (Unity to be more specific).

I want to have 1 main class that would store an array of all possible items that can drop which would probably be read in from some sort of data file. Each of these items would have a unique string identifier so I would want to also store a dictionary<string, int> which would allow to easy access to the item by the identifier like this:


Item item = Items[itemDictionary[id]];

I assume this would be more efficent than using a List and doing something like filtering especically if the list of items gets really large.

Then each entity would have an array of all the possible items it can drop by storing the string identifiers. Then when the entity needs to drop a piece of loot, I can just pick a random index from that array which will lead me to the item from the main class storing all the items to know which item to drop.

Obviously this is a very high level overview of what I am think of implementing and I am sure as I expand thing, stuff might have to change but as a general concept, anyone have any feedback on this?

Advertisement

Don't use strings. Use ID numbers instead.

If you need to look up the string name of an item from its ID number, just index into a List<Item> using that ID, and pull the string off the Item itself - this is a constant time O(1) lookup instead of a hashmap lookup and string compare. If you want to go from string to ID, store a secondary dictionary, but be disciplined about moving to ID numbers as soon as practical in code, so you do fewer string operations.

This is pretty much how the Guild Wars 2 item data works, for example.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

1 hour ago, ApochPiQ said:

Don't use strings. Use ID numbers instead.

If you need to look up the string name of an item from its ID number, just index into a List<Item> using that ID, and pull the string off the Item itself - this is a constant time O(1) lookup instead of a hashmap lookup and string compare. If you want to go from string to ID, store a secondary dictionary, but be disciplined about moving to ID numbers as soon as practical in code, so you do fewer string operations.

This is pretty much how the Guild Wars 2 item data works, for example.

I second this! I've worked on a few RPGs, and this is pretty standard. This is why you will see LOOT ID TABLES when modding certain RPG games. It's way easier to track, and find when you do it this way. Stay away from searching by STRING.

Programmer and 3D Artist

I guess my though process behind using a string is that it is recognizable and rememberable, it is easy to know what "WOODEN_AXE" is but not 173. 

Well, you could use enum values, but only if you're okay with the tokens potentially becoming incorrect or else being vague like WEAPON_AXE_2.

Honestly there probably aren't many cases where you need to refer to a specific weapon type rather than just a variable with an ID in it. If you like you could just write something to look up the ID by name like Apoch said, but you're going to pay some perf cost for it, so you really don't want to make it common.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

So also, realize that what the game uses while running can be different than what the programmer/level designer/content creator/modder uses while creating.

It would be quite normal to have some form of (possibly partial) mapping of strings to IDs for items.

So let's start with the assumption that the game itself uses IDs for all of the game objects, including object templates (which is pretty much what an "item type" is.  We'll assume these are integers (16, 32,or 64 bit depending on scale and computer arch).

Now we can then assume that there can exist a map table of unique tokens or names, which references this ID, which can be used by modders, designers, with a simple call to a method like:  

int ItemTable.LookupIDByToken(string itemToken);

and you can optionally add overloads to 1 or more other methods that accept an item ID, to accept an itemToken and perform the lookup for you.  Even more than that, you can create a rule that the token/name of an item cannot start with a numeric character, and therefore any string which contains a number in the first character can be assumed to already be an item token ... so if a modder passes a string to a method expecting a token, that lookup method can simple do a super fact 1 character check, and then parse the string without any lookup at all.

And this is the trick that then allows you to use only a partial map table and not require all items have names.  Say you have a database with 4000 items, all of them can be easily referenced by ID (if it is known) .. but you could have a much shorter list of perhaps 300 common items, and maybe 50 "special" items that modders / designers could use for the 95% of them time they are just doing something simple putting a chest with a cache of money in a chest, with an options health potion or whatever.

Also, this technique of "first letter (or prefix) denotes how to interpret the token" can be built upon in the future.  So say you start with the ID that numbers are object, but maybe only tokens starting with "I..." are items, then later you can add simple routing to support passing through "S..." elements which may be skills, or "X.." loot which may be experience. etc.

2 hours ago, 3dmodelerguy said:

I guess my though process behind using a string is that it is recognizable and rememberable, it is easy to know what "WOODEN_AXE" is but not 173. 

To be honest, I just had an excel sheet on the other screen referencing all the IDs while coding. I wouldn't over think this, just use IDs for your items, and keep a reference guide some where. This is just how I personally did this prior.

Programmer and 3D Artist

What I use for an endless runner project is some kind of UUID struct that is wrapping arround a long value using an encoding function to Base34 (like Bitcoins Base58 encoding but with only capital letters and digits). So what I get is the 8 bytes unique ID in the background covered by a string like '6NYTP5QEJQDV9' for example. It may not be something very readable but it works as expected.

This string ID then is indicating the so named scene for streaming the level parts into the game while running. This fits the above suggestions so may be fine to use.

What you also could do is to write some kind of custom inspector or tool for unity to get editing of your items more user friendly storing anything into a ScriptableObject inheriting class as your master item database. This is how we do it in nearly any of our unity projects

https://en.wikipedia.org/wiki/Overengineering

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
On 7/6/2017 at 8:37 PM, Rutin said:

To be honest, I just had an excel sheet on the other screen referencing all the IDs while coding. I wouldn't over think this, just use IDs for your items, and keep a reference guide some where. This is just how I personally did this prior.

Rutin's answer is how Bethesda handles this with the fallout and skyrim engines ... just loot at:  http://www.ign.com/wikis/fallout-3/Item_Codes for an example. Everything's "item id" is just a 32 bit integer, which they write as 8 HEX digits (0-9 or A-F) so that you can recognize they are a game id at a glance.

This topic is closed to new replies.

Advertisement