Well, you probably want to have a TArray of these UItems or something like that. You can store it on your Pawn, for instance, and make this property replicated. Then, you can replicate it either on this character only (if you don’t want other players to be aware of your inventory) or to everybody.
And don’t forget to add this variable to the replicated variables list:
As far as I know, it is true only if it’s the ‘last-in-chain’ object. Meaning, it doesn’t have an Actor as its ‘outer’ object. But I would really just go with structs for your case.
Check out the ShooterGameExample.
Last time I checked, it used an array for its inventory.
Though based on actors, it’ll give you an idea on what to do.
USTRUCT()
struct FInventoryItem
{
// Some UPROPERTY()s like name, description and etc.
}
class AMyCharacter : public ACharacter
{
...
UPROPERTY(Replicated)
TArray<FInventoryItem> Inventory;
}
You don’t want to replicate whole objects (it’s expensive bandwidth wise). Instead you want to create a Datatable somewhere that has all your items(each containing a unique ID), then your inventory is just an array of those unique IDs:
UPROPERTY(Replicated)
TArray<uint32> Inventory;
Then just use that ID to look up the item stats/description/etc, so you’re only ever replicating n * 4 bytes rather than n * sizeof(FInventoryItem).
And if you don’t want to mess with data tables, you can also save asset references (FStringAssetReference) serialized to string. A little more bandwidth but more flexible and you don’t need to maintain this table.
It’s potentially a lot of bandwidth given you are transmitting the full string path (which could be using wchar). If you don’t want to maintain the table, you could hash the FStringAssetReference, and then at load time just iterate through your known directory and build up a hash to Asset map. The problem with just doing that is if you move an asset, you break the hash so items you previously had won’t stay with you. The Datatable lets you avoid that at the overhead of maintaining that (or you build a unique ID into each asset you want to carry,i.e. some GUID, and replicate that), etc.
Lots of ways to do it. Just depends on your bandwidth/persistence limitations.
Alright, so I tried just setting my TArray<UItemBase*> inventory; to replicated, but it doesn’t replicate. I made a call to the server to add an item from an ID, so it should replicate to the clients that it has an item in the inventory, but it’s just null on everyone but the server.
So uh, as I said before, UObjects won’t replicate.
Hey i do not think this approach will work.
As you say UObject do not replicate, so if the Object is not replicated the reference you potential store in your inventory array.
Will not be valid client side after you add it server side, and it will be null.
In order for the UObject to replicate it needs a Actor as the outer parent.
So you are better of defining a base item class derived from AActor::.
An item is surely something that is in the world at one point so making it a UObject makes little sense to me.
I tried it though, and when I wanted to make a new instance of an item(AItemBase* item = NewObject<AItemBase>()) I got an error, so I don’t think you can use NewObject with an actor.
Are there any alternatives, or should I go about it in a different way?
Well you should spawn the Item in world (create a instance of it) and then store it in the array.
Using a Server RPC to add the item server side, and have it replicated to client.
Now in my opinion having a inventory with references to actors for a networked game.
Is not something i see as a generally good idea, if you think about having a lot of players.
And all of them are carrying a bunch of items, that are referenced and must be located some where in the world but hidden or something as they are in a backpack or what have you.
A struct with a item id defining the type of item and filling in the data as needed.
e.g: Icons for UI using the ID.
Also have a look at conditonal replication, for my players inventory my condition is to Owner only like this.
// replicating this ONLY to owning player.
DOREPLIFETIME_CONDITION(AMyPlayerClass, InventoryContainer, COND_OwnerOnly);
This will save you a lot of badwidth.
Now am not saying its the only way to do it and depending on your game design so 4th but this is preferred approach by many.
I’d really like to avoid having all items spawned in the world, and a struct is not something I see as a viable option unless I can make my item subclasses inherit from the base item struct (which I don’t think is possible, or is it?).
And thanks for the tip, I’ll make sure to put it to good use.