Efficient way to design an inventory system?
#1

I am currently working on a gamemode to try new things, one of the things I want to learn is to design an inventory system.

Basically the design that I wrote down on a piece of paper is as follows: the gamemode contains several types items (+/- 100). A player can have a set amount of items in his inventory, depending on if he carries a backpack. This ranges between 5 items (no backpack) and 30 items (largest backpack).

Vehicles can also store items, depending on the size of the vehicle. Ranging between 0 items for bikes to 200 items for large trucks.

Items can also be dropped on the ground, then it'll stay there until someone picks it up, with a maximum of 30 minutes.

Items of one specific type can be in certain conditions. For example:
- A pack of bullets can contain 1 or 15 bullets
- A jerrycan can contain water, gas or nothing
- A key has a unique value to correspond to one specific lock

Every item and every condition has a unique number. For example: a pack of 9mm bullets has ID 35. The condition will be stored in a second integer, for example 15 (bullets).

I am using MySQL to store information.


What would be the most efficient way to save information about inventories and items, both in the SQL database and in-game?

Would it be the best to have +/- 30 columns for items, +/- 30 columns for item conditions in the 'players' table in SQL and then store it in the players enum array in the script?
Would it be better to have a seperate table to list every item owner by every player? And how would I then store this in the script? A seperate enum array?

I lack the technical knowledge to explain this as good as I wish, I hope someone out here has experience with this and can help me around because this is the part that I am stuck on now.
Reply
#2

Well i have tought about this system also.
And most efficent way is to make categorys for items in my opinion.
Like tools are in one category, weapons in other and so one.
And in gamemode you have array of 3000 items.
When player connects, his items are loaded from database and when disconnects his items are unloaded.
Reply
#3

Thats a bit too much to explain in a single post, i can only give some general tips.

Dont create separate tables for player inventories, vehicle inventories, etc, but instead do a single table with all inventories, and link vehicles and players to their inventory id in a different table. Makes save/load routines much easier in the script.
In the inventory table you might either serialize the data of all items to get a single binary object or string, or create a second table with columns like (inventory_id, item_slot, item_id, condition), that is then joined to get the full item list for each inventory.
First version is small and simple, second version is much more structured and easier to administrate.

Do not create a huge table with one column for each item. Thats bad database design, and requires big changes in the script and database whenever you decide to add a new item type.

For the ingame handling: Ive yet used vectors for that via the vector plugin. Two vectors for each inventory, one for the item ids, one for the conditions. Also store the database id of the inventory of course.
like
Код:
enum Inventory {
    inventory_id,
    item_id_vector,
    item_condition_vector
}
new playerInventories[MAX_PLAYERS][Inventory];
new vehicleInventories[MAX_VEHICLES][Inventory];
You might also use arrays instead of vectors, but obviously this would be a huge waste of memory. Vectors are the eco-way, its not that hard to learn how to use them properly.

Thats basically the way I took to create an incredibly versatile inventory system, it has some more layers though to handle extra information for certain types of items (https://www.youtube.com/watch?v=Av61YO9Yb3o)
Reply
#4

I added "params" to the items in my inventory system.

An item could have up to three params, and I used a threading method for item related functions (OnPlayerUseItem, OnPlayerItemPickup, ... ) which put them into motion. i.e. the containments of the item "Bottle" were determined by the first param, being Whiskey, Vodka, etc. and the second param declared how full the bottle was (0=full, 1=half, 2=empty) and so on.

You should also create a seperate table for items. Keeps your 'players' table organised and contained. Item data is an entirely different thing so they shouldn't interwine with player stuff. Here's how I did it:



player_table_id is stored in the enumerator so I could easily remove entries from the items table. player_database_id is the player who owns the item. player_item_id is the item in question. amount, param1 and param2 should be self explanatory.
Reply
#5

If I were you I would also design my inventory system independent of the gamemode as it's own framework (include). This is definitely one thing I wish I had done better when making 420DayZ and could have saved myself a lot of time.
Reply
#6

At times like these, one wishes pawn supported classes, it would have made our lives much easier. But hey, a good developer is one who works around problems with what he/she has.
Dignity's method is the most approachable I'd say.
PHP код:
enum ENUM_ITEM
{
e_item_id,
e_item_condition
}
new 
item_info[MAX_ITEMS][ENUM_ITEM]; 
Let's assume an apple which is item ID 46, want to make it infected?
PHP код:
#define ITEM_STATE_INFECTED 1
#define ITEM_STATE_INFECTED 2
item_info[item_id][e_item_condition] = ITEM_STATE_INFECTED
want to store 12 bullets in a shotgun ammo box?
PHP код:
item_info[item_id][e_item_condition] = 12
I believe this method would work just fine, not too much heavy on memory, and to me looks efficient.
Would like to be corrected if I'm mistaken.
Reply
#7

Quote:
Originally Posted by Eoussama
Посмотреть сообщение
At times like these, one wishes pawn supported classes, it would have made our lives much easier. But hey, a good developer is one who works around problems with what he/she has.
Dignity's method is the most approachable I'd say.
PHP код:
enum ENUM_ITEM
{
e_item_id,
e_item_condition
}
new 
item_info[MAX_ITEMS][ENUM_ITEM]; 
Let's assume an apple which is item ID 46, want to make it infected?
PHP код:
#define ITEM_STATE_INFECTED 1
#define ITEM_STATE_INFECTED 2
item_info[item_id][e_item_condition] = ITEM_STATE_INFECTED
want to store 12 bullets in a shotgun ammo box?
PHP код:
item_info[item_id][e_item_condition] = 12
I believe this method would work just fine, not too much heavy on memory, and to me looks efficient.
Would like to be corrected if I'm mistaken.
Got it!

Still got more questions now; is there a limit to the amount of items used if I use that method? For example, if I use these stats;

- 60 playes playing at the same time, they can carry a maximum of 30 items each
- 20 vehicles in-game, with an average loading capacity of 20 items each
- Roughly 800 dropped items in-game

Would be a total of 3000 items and thus enums. Would this be doable or would it be a big stress on the server?

And how should I link the item to the player?
Reply
#8

I use almost the same method on my server, I get 30/40 at peak sometimes (each player having different amount of items with the biggest backpack supporting up to 50 item), with over +150 vehicles (15 items each), + tents/containers with +15 items each, airdrops 40 items, hospital crates (about 20 crates with 7 items each), +3900 items spawned across the map, + items dropped by other players..etc

There is no lag whatsoever.
Reply
#9

Quote:
Originally Posted by Eoussama
Посмотреть сообщение
I use almost the same method on my server, I get 30/40 at peak sometimes (each player having different amount of items with the biggest backpack supporting up to 50 item), with over +150 vehicles (15 items each), + tents/containers with +15 items each, airdrops 40 items, hospital crates (about 20 crates with 7 items each), +3900 items spawned across the map, + items dropped by other players..etc

There is no lag whatsoever.
How do you determine whether an object is owned by a player, dropped on the ground, in a car, etc?
Reply
#10

Quote:
Originally Posted by Mado
Посмотреть сообщение
Got it!

Still got more questions now; is there a limit to the amount of items used if I use that method? For example, if I use these stats;

- 60 playes playing at the same time, they can carry a maximum of 30 items each
- 20 vehicles in-game, with an average loading capacity of 20 items each
- Roughly 800 dropped items in-game

Would be a total of 3000 items and thus enums. Would this be doable or would it be a big stress on the server?

And how should I link the item to the player?
Theres no real point in using an array that stores all items. Rather use it for items that are on the ground and not in any inventory.

e.g. if youre using pickups for those dropped items
Код:
enum ENUM_ITEM
{
e_item_id,
e_item_condition,
e_item_pickup_id
}
For the inventory items its much easier to have them in inventories only, in the way i described above.
Using this plugin handling a players inventory would come down to just this

Код:
// On server start for each player slot, vehicle, etc
gPlayer[playerid][item_id_vector] = cvector();
gPlayer[playerid][item_condition_vector] = cvector();

// Getting an item
itemid = cvector_get(gPlayer[playerid][item_id_vector], item_slot);
itemCondition = cvector_get(gPlayer[playerid][item_condition_vector], item_slot);

// Adding an item
cvector_push_back(gPlayer[playerid][item_id_vector], item_id);
cvector_push_back(gPlayer[playerid][item_condition_vector], item_condition);

// Removing an item
cvector_remove(gPlayer[playerid][item_id_vector], item_slot);
cvector_remove(gPlayer[playerid][item_condition_vector], item_slot);

// On player leave
// Save items to database, then clear the vector so the next player wont "inherit" the items in that player slot
cvector_clear(gPlayer[playerid][item_id_vector]);
cvector_clear(gPlayer[playerid][item_condition_vector]);
No unused arrays wasting memory, good performance. You might also reduce it to a single vector by putting itemid and condition in one cell (e.g. first 10 bit for item id, last 22 bit for condition). Its even possible to create an iterator for vectors, so you can loop through inventories with foreach.
Fixed-size arrays just are a bad choice when the range of inventory sizes is rather big.

My complete multilayer inventory engine, including save/load, isnt even 400 lines.
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)