I’m trying to build my inventory system and until recently I was building it for singleplayer. It worked really great and supported everything I needed:
Each item can override virtual Use() function, so Character using it can do something with it (for example when you use food it would give you satiety and heal you a little, but when you ‘use’ armor character would equip it)
Some item properties can be changed at runtime: for example unloaded gun would weight less than loaded, and armor can lose it’s durability.
Items can extend base item and add some properties, override some functions.
So as I said earlier, it worked fine until I decided to add multiplayer support. I’m new to networking, so I’m facing some problems. I understand all basics, but struggling with understanding what I should replicate and how. In my game I should have a lot of items, so thinking about bandwitdth is important.
Should I replicate (with COND_InitialOnly) some properties like name, description (FText) or max items in one slot (int)? Or would I create some sort of DataTable and then load object info by some ID? But then what to do with virtual functions and properties, added by child classes? And if I solved previous questions, what functions should be Server, Client or NetMulticast?
Sorry if I’m asking too many questions in one post, I was trying to figure this out for a really long time, but with no luck.
It depends on what you want to do. If you have an Inventory class, you should replicate variables with COND_InitialOnly only if they don’t change during the gameplay. For the RPCs part it depends, again, on what you want to do. Keep in mind that Reliable RPCs (especially Reliable NetMulticast RPCs) consume a lot more than Unreliable, so if you have an RPC that is called every frame, make sure it’s set to Unreliable, otherwise it will easily saturate your bandwidth. And if you can, avoid Reliable NetMulticast RPCs at all, instead use variable replication with a ReplicatedUsing function (keeping in mind that it will be called only on clients, and not on the server, instead of the Multicast RPC).
To learn more about Network Optimization and Replication, you can watch the Unreal Inside live streams to have a general idea of how to keep your game network well optimized.
For Multiplayer you want the server to manage your inventory. Thus the logic for all inventory and item interactions must reside on the server.
e.g. You pickup an item. The client will initiate the action (animation), then RPC the server to do the logic for picking up. For example a line or sphere trace to detect items. On detection handle the logic for adding.
The same will apply for using an item such as meds/food, ammo usage and so forth.
Where the logic resides (class) depends on your game needs. Personally I prefer using an Actor Component in the Player State.
First of all, thank you for your reply and links, they’re really helpful. What I have now is InventoryComponent (Actor compoent), which I can ‘attach’ to everything (for example, to npc or chest). But wouldn’t replicating a huge FText even one time for object cause some sort of short lag to everyone on server in scenario where I spawn, let’s say, 30 same items (when unloading gun as an example)?
Thank you, this clears a lot of things. What I’m trying to achieve is to have an Actor Component which would represent inventory, because in my game player is not the only one who should have it. Npcs and storages would have their own inventory. So keeping it in PlayerState is not for my case
I shouldn’t have any dynamic text, but I’m worried that replicating a huge text even once, but for many objects spawned simultaneously could cause lags and other negative things.
A single FText should not be a problem, but if you’re worried about performance, you can always replicate an ID and then convert it to an FText on the client. With replication the problem is not only the bandwidth, but also the CPU load, because the server has to check every frame if a variable has changed and if it has to be sent again to the clients, and that’s why you have DOREPLIFETIME_CONDITION, Dormancy, NetUpdateFrequency, etc.
If you want to gain more performance, because maybe you have a huge amount of players, you should look into ReplicationGraph and you should see the tricks mentioned in those videos I linked before.
If you want more informations on the Replication Graph, you can watch this livestream from the Unreal Engine Team:
Anyway you can always test your network performance with the profiling tools (like NetworkProfiler):
For NPC’s you can still use Player state to hold it’s inventory.
For crates/storages etc you create a BP actor to represent the physical and interactive functionality (collision/bp interface), and add a AC_Inventory struct. The same struct setup your player will have, but without the add/drop/use functionality. The server will be moving from inventory to inventory.