So I made my own inventory system
by Todd Johnson · in Torque Game Engine · 07/08/2005 (5:54 am) · 9 replies
I was able to take Tim Newell's code and start off on my own inventory structure. I am running into one thing....
In my Inventory.h I have a bayManager array that holds 6 bay objects. These bay objects have a name and amount. When I do my %player.addToInventory("Gun", 1) it adds this information to my bayManager array correctly. However, when I say to display the contents of the array, everything is blank again?
I really think this is because I don't understand how information is persisted from client to server. Do I nead to read/write or pack/unpack this inventory data? Can someone please link me to some documentation. I've had this problem for quite some time. Thanks!
In my Inventory.h I have a bayManager array that holds 6 bay objects. These bay objects have a name and amount. When I do my %player.addToInventory("Gun", 1) it adds this information to my bayManager array correctly. However, when I say to display the contents of the array, everything is blank again?
I really think this is because I don't understand how information is persisted from client to server. Do I nead to read/write or pack/unpack this inventory data? Can someone please link me to some documentation. I've had this problem for quite some time. Thanks!
About the author
#2
I chose to do it in C++ because the inventory is core for my game. Plus I needed exposure into writing something in C++ again. I started to create to many scripting lines for my taste. Iu se to have a scripted inventory system.
So now when I log into the server and do %player.addToInventory("Item", 3) is adds that item to my inventory correctly. I have it adding and removing just like I want. However, if another player comes on, I can't get it to work. Here is what I'm talking about...
First player logs on, his player ID is 1242 (he started the server). Then he adds an item to his inventory. Then player ID 1250 joins via multiplayer. From the console, I then type 1250.addToInventory("AnotherItem",2). But, when I display the inventory from the second player's screen, it does not show anyhting in the inventory.
On the server, if I do 1242.displayInventory() it shows that that player has 3 "Item"'s in that inventory. Then I do 1252.displayInventory() on the server, it shows that player having 2 of "AnotherItem". But when I go to the second player's client to show their inv, nothing displays. Well it attempts to display but the inventroy is just empty. Any ideas?
07/10/2005 (6:15 am)
Well I noticed my problem was in my ConsoleMethods. I was not casting the integers (they were coming in as strings). I chose to do it in C++ because the inventory is core for my game. Plus I needed exposure into writing something in C++ again. I started to create to many scripting lines for my taste. Iu se to have a scripted inventory system.
So now when I log into the server and do %player.addToInventory("Item", 3) is adds that item to my inventory correctly. I have it adding and removing just like I want. However, if another player comes on, I can't get it to work. Here is what I'm talking about...
First player logs on, his player ID is 1242 (he started the server). Then he adds an item to his inventory. Then player ID 1250 joins via multiplayer. From the console, I then type 1250.addToInventory("AnotherItem",2). But, when I display the inventory from the second player's screen, it does not show anyhting in the inventory.
On the server, if I do 1242.displayInventory() it shows that that player has 3 "Item"'s in that inventory. Then I do 1252.displayInventory() on the server, it shows that player having 2 of "AnotherItem". But when I go to the second player's client to show their inv, nothing displays. Well it attempts to display but the inventroy is just empty. Any ideas?
#3
The class that stores the inventory info needs to do the above three functions and stream the fields so your client will have the same values as the server. It sounds like it's your PlayerData class that needs to do this. It should already have a bunch of addField, stream->write and stream->read calls in it. Just add more of these calls to persist your inventory information across client / server boundaries.
Something that I always do when I'm unit testing new code is to fire up a dedicated server and a separate client. This helps me verify that I wrote these three functions correctly.
Hope that helps.
07/10/2005 (11:14 am)
Just a wild guess, but it sounds like you're not doing the initPersistFields / packData / unpackData trio.The class that stores the inventory info needs to do the above three functions and stream the fields so your client will have the same values as the server. It sounds like it's your PlayerData class that needs to do this. It should already have a bunch of addField, stream->write and stream->read calls in it. Just add more of these calls to persist your inventory information across client / server boundaries.
Something that I always do when I'm unit testing new code is to fire up a dedicated server and a separate client. This helps me verify that I wrote these three functions correctly.
Hope that helps.
#4
My first understanding of initPersistFields() is that these are fields that are in the cs files. I don't see any need in having any of my inventory variables in a cs file so I don't think I need to add any addField()'s (I could be so very wrong).
Now for the packData() and unPackData() I notice the write streams accept U32. I'm not exactly sure why I need to persist this information since it should only be for each player (I don't really want it to be shared). This is where I don't understand what to do. I will post my code in the next post.
The inventory logic works it just doesn't work for me with a connected multiplayer. One additional thing I notice off hand is that the inventory object inv gets created 4 times by the time I join a game. I'm not sure why. This is using Tim Newell's inventory code but I don't think it was multiplayer friendly (works single player). Any analyzation is further appreciated!! Sorry for the huge post!
07/12/2005 (5:38 am)
I had a feeling it has something to do with client/server persisting. I have a feeling if I could get a point in the right direction I should be able to drive it home.My first understanding of initPersistFields() is that these are fields that are in the cs files. I don't see any need in having any of my inventory variables in a cs file so I don't think I need to add any addField()'s (I could be so very wrong).
Now for the packData() and unPackData() I notice the write streams accept U32. I'm not exactly sure why I need to persist this information since it should only be for each player (I don't really want it to be shared). This is where I don't understand what to do. I will post my code in the next post.
The inventory logic works it just doesn't work for me with a connected multiplayer. One additional thing I notice off hand is that the inventory object inv gets created 4 times by the time I join a game. I'm not sure why. This is using Tim Newell's inventory code but I don't think it was multiplayer friendly (works single player). Any analyzation is further appreciated!! Sorry for the huge post!
#5
Player.h has Inventory inv;
Player.cc
default.bind.cs
serverCommands.cs
07/12/2005 (5:42 am)
Inventory.cc#include "game/Inventory.h"
Inventory::Inventory() {
Con::printf("Starting Bay Manager");
MaximumAmountOfBays = 6;
ClearInventory();
}
Inventory::~Inventory() {
Con::printf("Removing Bay Manager");
}
void Inventory::ActivateBay(U32 position) {
if(ValidateSelectedBay(position) && !IsBayEmpty(position))
CurrentBay = position;
}
void Inventory::AddToInventory(char* name, U32 amount){
for( U32 i = 0; i < MaximumAmountOfBays; i++ ){
if( IsBayEmpty(i) ){
dStrcpy(bayManager[i].Name, name);
bayManager[i].Amount = amount;
CurrentBay = i;
break;
}
if( i == (MaximumAmountOfBays - 1) )
Con::printf("FULL INVENTORY YO");
}
}
void Inventory::RemoveFromInventory(U32 position){
if (ValidateSelectedBay(position))
{
dStrcpy(bayManager[position].Name, "");
bayManager[position].Amount = 0;
if( CurrentBay = position )
ActivateNextBay();
}
}
void Inventory::ActivateNextBay(){
U32 temporaryCounter = CurrentBay + 1;
for( U32 i = 1; i < MaximumAmountOfBays; i++ ){
if( temporaryCounter >= MaximumAmountOfBays )
temporaryCounter = 0;
if( !IsBayEmpty(temporaryCounter) ){
ActivateBay(temporaryCounter);
break;
}
temporaryCounter++;
}
}
void Inventory::DisplayInventory() {
for( U32 i = 0; i < MaximumAmountOfBays; i++ )
Con::printf("Bay %i contents: %s %i", i + 1, bayManager[i].Name, bayManager[i].Amount);
Con::printf("The current selected bay is %i", CurrentBay + 1);
}
void Inventory::ClearInventory(){
Con::printf("Clearing all bays");
for( U32 i = 0; i < MaximumAmountOfBays; i++ )
RemoveFromInventory(i);
}
bool Inventory::IsBayEmpty(U32 position) {
if( dStricmp(bayManager[position].Name, "") == 0 )
return true;
return false;
}
bool Inventory::ValidateSelectedBay(U32 position){
if(position > MaximumAmountOfBays - 1) {
Con::printf("Selected bay, %i, is over the maximum amount of bay slots 0-%i", position, MaximumAmountOfBays - 1);
return false;
}
if(position < 0) {
Con::printf("Selected bay, %i, is under the minimum amount of bay slots 0-%i", position, MaximumAmountOfBays - 1);
return false;
}
return true;
}Player.h has Inventory inv;
Player.cc
ConsoleMethod(Player, displayInventory, void, 2, 2, "(Display the current inventory)")
{object->inv.DisplayInventory();}
ConsoleMethod(Player, addToInventory, void, 4, 4, "(name, amount)")
{object->inv.AddToInventory((char*)argv[2], dAtoi(argv[3]));}
ConsoleMethod(Player, selectNextInventory, void, 2, 2, "(Select the next available bay)")
{object->inv.ActivateNextBay();}
ConsoleMethod(Player, selectInventory, void, 3, 3, "(position)")
{object->inv.ActivateBay(dAtoi(argv[2]));}
ConsoleMethod(Player, removeFromInventory, void, 3, 3, "(position)")
{object->inv.RemoveFromInventory(dAtoi(argv[2]));}
ConsoleMethod(Player, clearInventory, void, 2, 2, "(clear this players inventory)")
{object->inv.ClearInventory();}default.bind.cs
function activateBay(%bay)
{commandToServer('ActivateBay', %bay);}
moveMap.bindCmd( keyboard, "1", "", "activateBay(0);" );
moveMap.bindCmd( keyboard, "2", "", "activateBay(1);" );
moveMap.bindCmd( keyboard, "3", "", "activateBay(2);" );
moveMap.bindCmd( keyboard, "4", "", "activateBay(3);" );
moveMap.bindCmd( keyboard, "5", "", "activateBay(4);" );
moveMap.bindCmd( keyboard, "6", "", "activateBay(5);" );
moveMap.bindCmd( keyboard, "7", "", "commandToServer('ClearBays');" );
moveMap.bindCmd( keyboard, "8", "", "commandToServer('DisplayBays');" );serverCommands.cs
function serverCmdActivateBay(%client, %bay)
{%client.player.selectInventory(%bay);}
function serverCmdClearBays(%client)
{%client.player.clearInventory(); }
function serverCmdDisplayBays(%client)
{%client.player.displayInventory();}
#6
I've been working pretty intensely w/ inventory control for players and tieing it to a database etc. What I found out worked best was a model that worked like this
A list of the player_handles
each node in the list points to it's own inventory object.
Then you modify console methods so that you pass in the player handle w/ the inventory command.
This way all you have to do is modify the inventory.cs file and your done. Their are some catches like case sensitivity, just remember to down or upcase everything before you send it to the consolemethods or the dStrcomp function won't match 'Player1' with 'player1'.
Vince
07/12/2005 (6:02 am)
Todd,I've been working pretty intensely w/ inventory control for players and tieing it to a database etc. What I found out worked best was a model that worked like this
A list of the player_handles
each node in the list points to it's own inventory object.
Then you modify console methods so that you pass in the player handle w/ the inventory command.
This way all you have to do is modify the inventory.cs file and your done. Their are some catches like case sensitivity, just remember to down or upcase everything before you send it to the consolemethods or the dStrcomp function won't match 'Player1' with 'player1'.
Vince
#7
07/12/2005 (6:15 am)
Just curious, to know why you would go about it this way, rather than taking the stock inventory system and adjusting the script. Is this a just so I can say I did it kind of thing, or was there some kind of major design decision that required inventory to be handled in just exactly this way?
#8
07/12/2005 (3:46 pm)
That sounds like a rational idea Vince. I'll just keep an inventory id per player. That's not a problem. Unfortunately I'm not sure where to keep this "collection" of inventories. I don't see where the players are created in code. Where would I initiate this (in the engine).
#9
07/13/2005 (5:43 am)
I understand I would add a new inventory everytime a player connects but what engine class should I keep the collection of inventories in?
Torque Owner Dreamer
Default Studio Name
If it were me though I wouldn't place something like inventory directly into the engine, it's just too complex of a task. It would be much easier to script it, and place calls in the form of CommandToServer and CommandToClient, passing the needed info back and forth.
But that's just my opinion, good luck!