Bottom Line Up Front: Rep notify is working, but it is setting the client’s character mesh to be the same as the hosts rather than their own. What do I need to change to get it to use the client’s value instead?
I’ve likely overcomplicated this. But this is the process.
I made a blueprint component that includes a structure array. The structure array contains several different variables for each piece of a players equipment. I added the equipment struct to the player controller. This is the struct.
Using the RedPoint Games EOS online plugin the player pulls a save game from the cloud and sets it in their game instance. Within the save game is the same equipment array struct that is in the blueprint component. The rest of this process then runs and the player has their correct custom character.
The player joins a listen server and on begin play the controller gets the save game/equipment struct from the game instance and set’s the controller’s/blueprint component/equipment struct
An RPC on server then gets the game mode and calls a function within the game mode that spawns the player character. One input of that function is the BP player controller, and that controller is used to set the owner of the character within the game mode’s function.
In the game mode, immediately following the character spawn, an unreplicated event is called within the BP controller called “Set Equipment”, which has the new character BP as an input.
Within “Set Equipment” the character BP as set as a variable and then another event is called within the character BP also called “Set Equipment”, but the character BP even is replicated on the server. That event has the controller’s blueprint component as an input.
Within the character BP “Set Equipment” I get the equipment struct from the blueprint component and set w/ notify the same variable within the character BP.
Within the function called by the rep notify I get the various variables from the equipment struct and set child actor classes and skeletal mesh assets of the character.
At this point the client and host both have a custom character, but the client has the host’s custom character rather than their own (the one they had before joining the listen server). I thought that perhaps I needed to have the blueprint component in the player state rather than the controller, but when I tried that I couldn’t get the rep notify to run for the host and client.
What class is the Read User File being handled in and on what proxy (client or server).
Player class Begin Play doesn’t have any role/proxy conditional flow logic. Both the server and the client copies are executing that code.
Game Instance, just like the Game Mode, is only available to the server. Clients do not have a copy or access to it… excluding single player/coop where the client is the host aka server.
This happens before any playable map opens and before they join any listen servers. If they don’t have their copy of the game instance in the listen server, it would make sense that I’m having an issue. Where should I set the variables so they carry over into the server? Or do I need to load the user file again when joining the server?
Also, based on what you said, do I need to move my all this begin play logic in the controller to be after “Is Local Player Controller”?
The Character will be replicated for each player online. Each player replica will have its own Character blueprint instance.
The Player Controller will only be available on the individual client machine, and on the host.
If there’s something that is purely display related, then changing a property on a specific Character instance, and having that change replicate to the specific remote Character replicas will work just fine.
If you have persistent state in a multi-player game, it’s really important that you keep this state online on your server, not on your player. Also note that if you use player-hosted servers, the host’s EOS instance will not be the same as each individual clients’ EOS instance. Thus, “persistent” state should really be kept in a database you control on your server.
If you absolutely must use player-specific storage and no central server of your own, then each client needs to load the appropriate savegame, and send their individual state to the server/host, using some kind of RPC that’s specific to that individual player controller. It’s also important tha you only do this on the client that has the input (the actual player client) and not necessarily on the host instance of the player controller – the hosting player won’t have permission/access to your player-specific EOS profile.
This of course will open your game up for arbitrary cheating, but maybe you don’t care – co-op games are less sensitive to this than competitive shooters.
It sounds to me like you’re not quite separating this distinction correctly. Character versus PlayerController, and controlling client vs host, are both quite important distinctions. Also note that each individual client won’t have the GameMode, only the hosting player will have this. You’re probably better off pushing more state into your PlayerController, and, ultimately, into a database you control yourself.
Thank you both for being so helpful! I have definitely struggled with understanding ownership. I’m going to try and implement what you both have said sometime this week and see if that solves the problem.
Got it! Wish I could mark both answers as solutions. Just needed to go to the controller, check that it was the local controller, load the user file there, save a replicated equipment variable to the local controller, then RPC it to the server copy of the controller, and then the rep notifies in my character class started working for both the host and client! Thank you!