Targetting a specific player in Multiplayer

Thanks for the help so far, I know man this has been going on for a few days now lmao. I really hope I’ll be able to get it working in the end tho, since this entire system runs on blueprints without any Steam Subsystem bs or C++, and I’m still able to let all my friends connect to it. It’s just the freaking targetting/indexing of specific players lol.

Picture to describe what I’m going through:
dbd95c2014ebef28b1823ee4c9555a36a4e5ba81.jpeg

Anyway, goodnight, and ty again! :o

@TK-Master
Btw I was already able to store an username in MyGameInstance after selecting a character and calling it on the TopDownCharacter, so the GameInstance method works for sending data to other levels. (so you don’t waste your time tomorrow)

@Unreal Forums
The problem is applying the data to a specific character. In a singleplayer scenario you would use GetPlayerController or GetPlayerCharacter as target to apply the player’s preferences to.

temp7.png

But since this is/will be a (massively) multiplayer game, the index of 0 will only target the first player, which isn’t what we want:
*
“Johnny logs in, loads his data (hairstyle 1) from database. Then a hour later Sam logs in, loads his data (hairstyle 3) from database, but since Player Index is 0 data loads ** onto** Johnny’s character.
So now Johnny’s character has hairstyle 3.”*

So I need either a system that is able to index players and set an unique PlayerIndex variable for each player
(so I can use this variable to plug into GetPlayerController’s or GetPlayerCharacter’s input)
Or another way altogether that doesn’t use indexes but somehow gets specific PlayerControllers/PlayerCharacters I can then drag off of to do stuff with (set Material for example).

Hopefully a dev can shed some light on this plis?:rolleyes:

I’m unsure on where you are stuck now :stuck_out_tongue:

The Get Player Controller (Player Index) is for “local” multiplayer only (think mortal kombat when two players play on the same screen) or split screen, so forget that.

If you have managed to get the GameInstance working, then after you have opened the level, your newly spawned controller *should *be able to read the username that he logged in from the game instance, and your character can then load the data based on the username of its controller.

That’s what I already have working lol :stuck_out_tongue: my problem is how do I apply the loaded data onto the specific instance of the TopDownCharacter since I can’t use GetPlayerController/GetPlayerCharacter?

In my example I load appearance_color from the database, which I use to determine what material should be applied to that player’s version of TopDownCharacter.
(this could be anything from CharacterName, health values, what helmet he/she’s wearing, to morph target values, I chose material simply as example)

Then I want to Set Material which requires a target. What do I put in the target since I cant use GetPlayerCharacter->Mesh (because that requires an Index), how do I target the specific client I loaded the data for?

You should add the character’s mesh to the Set Material target of course :slight_smile:

Edit:
I mean, from the components list… you don’t need to use any node such as GetPlayerCharacter here.
Just drag the mesh component into the graph!

By the way…

The database communication should be done on the server only… the clients shouldn’t be allowed to directly get the data.

Same thing for the login… the client should send a “TryLogin” message to the server for example, then the server should communicate with the database and then send the character list (etc.) to the client.

It seems to apply the material to all the TopDownCharacter’s, which is weird. Also something seems to be going wrong with the materials.

temp3.png
temp2.png

I realize that, I just turned all replication off for now so I could test properly.
That being said, how would I set up replication in a correct way for this logic in your opinion? (for the GetCharacterColor event and SetPlayerMaterial event)

Um… I’m not entire sure why but looks like you might not be able to set a material at run time that way.

Can you try doing this with a material instance instead?

docs:

Will do, thanks for the help so far. I managed to find a weird bug that might have played a role in this problem.
The username that gets set after Event Begin Play, did not properly transfer over to the GetCharacterColor event for some reason… (perhaps casting to MyGameInstance to request the Username takes a while?)
This caused the JSON query parse through an empty string to my API so it would always return 0 instead of the actual appearance_color of the character.

What I did is the following:

Simply adding two delays of a second now causes the Username to get parsed into the JSON query properly, thus retrieving the correct data. :slight_smile:
Since this material bs doesnt seem to work for now, I set up the following to see if retreiving other data actually work for each individual character:

This renders the character’s name in a text render component above the character. (so I am able to tell if each player loads it’s own data from the database and apply it to their own instance of TopDownCharacter instead of to all)
The result is the following:

So this is finally working :o, the only problem now is network persistance. (When a client connects at a later time, how does he/she get the changes that were made when he/she wasn’t connected to the server yet)
In any case thanks alot TK-Master, couldn’t have done it without you.:o

Okay so the set material thingy is apparently a bug (sigh… this engine’s bugs man…) it doesn’t work with skeletal meshes.

https://answers.unrealengine.com/questions/219599/set-material-not-working-for-skeletal-mesh-compone.html

Hopefully it’s fixed in 4.8.

Yeah I hope so too, luckily the Set Material was just an example, I don’t actually need it for my project so…:slight_smile:
Anyway thanks again!

The PlayerController does exist - but only for the one controlling it (the specific client) and the server. But the PlayerState was built especially for this, it’s replicated to everyone.
GameInstance is not a good place to replicate data, it’s the “personal datastore” for every client. To replicate Player-Specific data, use PlayerState

I’m a bit suprised your code in BeginPlay of the character works, because I think it’s executed on every client, not just the server. that would mean every player is sending it’s name whenever a new pawn is spawned.

Thanks for clearing that up. But could someone then edit data from client-side if that data is stored in GameInstance or does it still ‘run’ on the Server?
Also isn’t every player sending his/her name to every new pawn when spawned a good thing? Wouldn’t the CharacterNames otherwise be empty for the new player when a he/she connects to the game? :confused:

Think of GameInstance as the client’s private storage. Nobody but the owner has (or should have) access to it.
Plus side: The GameInstance even survives a ServerTravel from one map to the next!

In my project, I used to store the player name, because the client starts into a menu-level, where he is offline. When he connects, his chosen player name is sent to the server using an RPC and then the server set’s the name on a replicated-notify variable (for example in the playerstate).

It’s an easy error to do mentally, I fall into it all the time too. But imagine how a character is really instantiated. Let’s say we have a server and two clients: and .

  • something, eg. the player named “”, sends a request to spawn a character
  • the server instantiates the pawn and makes the player possess it.
  • for it to show up on every client’s display, the character is also instantiated on every client machine (!). So at least the constructor is called on every machine (and IMO, also “begin play”).
  • therefore, the constructor of 's character and it’s begin play are called on the server, on 's machine and also on 's machine.
  • I think the only reason that you see the correct name is, that the other clients are not the owner and their call to SET is ignored.

Why it’s not really good:
Imagine 1000 players login in after each other. On the first char, there is one call. When the 2nd logs in, 2 player send their name. 3 send it on 3rd… this results in 500500 calls! :slight_smile:
What you want is the new player () broadcasting it’s name when he joins the game. Of course also needs all the names of the other players. but the players already in the game do not need to have all names sent again.

IMO a better solution would be if the client sends the server whatever data is needed using RPC.
you could tell the client to send data in PostLogin (this is only executed on the server) using a RPC call, eg “ClientSidePostLogin”, and then the client sends the data to the server with an RPC eg “SetPlayerData”.
the server could then set some replicate-notify variable on the character which is automatically broadcasted, or you broadcast the name with an event to everyone, or you use the playerstate as your central data object.

PS: Setting the players color / material works, as long as you use dynamic material:

Good stuff, thanks! I will try implementing this when I get home. :slight_smile:

Hey , I adjusted my project to use a custom PlayerState I called ‘MyPlayerState’ but the data doesn’t persist when I load the main level…:confused:
I read something about hard (destroys all data) and seamless (preserves data) travel, from what I gathered you can’t do seamless travel in Blueprints? (atm I use execute console command ‘open ipaddress’ to travel to my main level) See this AnswerHub question.

In CharacterButton blueprint, OnClick executes JoinWorld event.

This event in the custom PlayerState saves the Character’s name.
58fbbd26b81931f9d4bd98cfe8acff93.png

Event begin play in my TopDownCharacter does this.

But it returns an empty string, I also tried adding a delay in but no matter what the string is always empty.

I also edited all default PlayerStates to use this new MyPlayerState class but to no avail.

I Believe you need to set the character name on the server its self, as all player states are held on the server and replicated down to their respective players, had quite a bit of trouble with this myself and documentation is practically zero on the specifics of this, it seems UE4 is primarily designed to make the generic shooter games etc, anything else and you start running into a endless series of brick walls, at least from my experience aha, especially with multiplayer.

Below is an example that should work… note run on server I set a variable “rk” on the servers version of the player state, regkey… this will then replicate down to the respective player who called the function, thus giving you some kind of player id for further requests, then you can run a search on server player state array for the player state that has the same “rk” value as requested allowing you to identify specific players…

119a079b753423b4a6e0e93431a22073b300a93d.jpeg

Hope this helps everyone!

*edit few more images

This is called in the local PlayerState blueprint:

and proof of working…

6c6c1fb340d32a5c1377f892a8b19dcf194ee6a1.jpeg

I don’t know if this is the correct way of doing it, but its the way I found that actually works as I intend it to, just play round with it, you will understand it eventually!

Just remember, unreal often likes things done in the way it intends them to be done, once you understand how it likes to do things, it becomes easier to work with and manipulate to how you want things to be done! aha :slight_smile:

But anyway hope this helps… let me know if there’s anything else!

o/