Long day today, so sorry for the delay. Sleepy, so no promises on quality of replies :p.
Yep, you can still call replicated functions on objects within the GameMode.
If you want that the player on a listen server is always on team1 and the client is always on team2, there are a couple things you could do. The way closest to what you already tried would be to actually check if they are locally controlled or not. The server representation of the listen server player will return as locally controlled, while the server’s representation of the client player will return as not locally controlled.
I don’t remember precisely how we normally do this off the top of my head (would have a better answer when I’m back in the office), but the basic gist is we usually actually create another actor that is set up very similar to how playerstates work that specifically holds info about an individual team instead of an individual player (so we call it something like ATeamInfo), which could potentially also store its list of members if it wanted. We normally have the GameMode spawn the actual team info actors and then I think we keep a list of them on the GameState for easy access by clients if they want to query things. The TeamInfo actor additionally normally would store team-level concepts that could be mode specific. Simple example, if you’re making a capture the flag mode, you could let the CTF team actors store how many flag captures each team has.
Then in my understanding of “OnClient” function replcation wouldn’t it be possible for me to set the team in the PC’s PlayerState and then call something like ClientInit() on the PC that calls the Init() function on the client ?
That was my first try of replcation. Client calls a OnServer function getTeam(). In getTeam I set my team and called a OnClient that tells the client to show some effects or what ever.
But maybe this function call only happens on the server representation of the client and never replicates to the remote client?
Sorry if I asking some silly questions here, but as you said in one of your videos, even if you prototype do it with multiplayer in mind.
As I am still learning the engine and c++ it is more like prototyping than actual game development what I am doing but I want to get
the multiplayer part working from the beginning as I will need it later.
Would you take AActor, AInfo or something else as base class?
Lets say I have a ATeamInfo a team consists of a teamleader (PC) and a couple of Pawns/Characters the teamleader commands.
On connecting to the server the GameMode would spawn a new PC, doing some Init stuff and creates a new TeamInfo. Would you store a reference to the PC on the team or would you store the reference to the team on the PC?
How would replicating such a construct work? Just putting the ATeamInfo in a replicated variable on the gamestate and everything works fine?
Yes that is the remote role -> getRemoteRole() (ENetRole)
at some point the role was equal on all PC instances. But now it is not anymore. To be honest, I really don’t know what I changed in order to get that right but a simple check in IsLocalPlayerController() is enough to assign my team right now.
@Billy: Are there any updates on the Couch Knights demo? From the description it sounds like it would cover some areas of replication I’m interested in via blueprints. I’m especially interested in replicating head turning/movement via Oculus or just looking around with the mouse. (As in seeing the character’s head rotating)
Same goes for future VR device support(hand controllers). There’s an unanswered(as far as I know) question from Twiddle that relates here: Replicating character rotation in ThirdPerson sample - UE4 AnswerHub
Edit: Looks like there was an update during Twitch (posted on youtube today) on Couch Knights, cool.
Client functions only execute for the client that owns the PC or character in question. So if you have a 4 player game and the server calls a client function on one of the players, only that particular player’s remote machine gets the function call, which is different from a multicast, which broadcasts out to all of them. If you wanted every client machine to do something when the team value is set, you might just want to make the team variable use replicatedUsing and respond inside that function.
No worries! Networking is a complicated topic and it took me a while to wrap my head around it when I was first learning too.
I think we use AInfo as our base class, but would have to double-check at the office. For replication of the teaminfo, we make the actor itself replicate (so it is available to all the clients) and then we store a reference to them in a replicated array on the GameState, so that each client has an easy way to query for team information. Re: where to store the references, probably depends on what you want to be able to do. If you want an easy collection of every member on the team, you probably want to store it on the team info. I want to say we store a team number/index on the player stuff to be able to ask for the team later if need be. Keep in mind if you need your team composition to be accessible to every client, that if you store exclusively player controller references, those are only available to the server and their corresponding owner player. So in a 4-player game, an individual client will only actually know about 1 player controller: his own.
Most of the time for networking checks, you tend to be checking Role directly instead of RemoteRole. Like if you want something to only execute on the network authority, you’d do:
if (Role == ROLE_Authority)
When you specify a RemoteRole for an actor, you’re saying what Role it will have on remote machines. So an actor with its RemoteRole set to ROLE_SimulatedProxy will have a Role of ROLE_Authority on the server and a role of ROLE_SimulatedProxy on the client.
It is not quite looking like that right now since I am rebuilding everything in C++.
The problem was that the team variable was only in the PlayerState of the controller and if the OnRep function was triggered there was no way back to the PlayerController so I put the team variable back into the controller.
Right now the the TeamInfo actor is saved in an array in the GameState AND the PlayerState.
The part in bold killed my editor many times until I noticed that :).
What I want to do with the team variable: the every PC should be able to query things like team members/leader with things like HP/Mana or whatever. Only the team leader should be able to add new members to the team via replicated functions.
Maybe storing the Team in the PlayerState is not the best idea in this case and I should it in the GameState and use an index like you and store it in the PC so it is able to find his/her own team :).
My bigger problem right now is that the way my game is build right now I use OnRep_PlayerState to trigger my Init function on the PC but even if the PlayerState is replicated the variables (the Team) in it might not and are NULL at the time of the first call.
Is there a way to make sure that if the PlayerState is replicated all its content is replicated before that? I Increased the priority on the TeamInfo actor and have thrown some forcenetupdate here and there to make it work but maybe there are better methods to achieve that.
Having these for C++ would be great, even if they weren’t videos! I had decided to do my best to learn C++ is part of picking up Unreal 4, so I’m trying to do as much as I can in there. Currently I’m trying to mimic and understand the ShooterGame logic, since that has network capabilities, and they’re entirely in C++. In ShooterGame, I believe they use a function to start and stop the shooting, and then variable mechanism to fire the ammunition (if the burstcounter changes on the server, fire another bullet). This is just my very amateur attempt to investigate this, having someone confirm that would be awesome!
However, I have a question on your statement regarding when to use a variable replication mechanism vs. a function. In my first project I’m creating a scenario where you charge projectiles and then, depending on the type of projectile, it releases automatically after its pre-defined charge time (Similar to casting a spell). If I’m understanding your statement correctly, both of these stages (beginning charge and releasing the projectile) should be: a) Functions / RPCs and B) Called on the server and C) Multicast so that all clients can see them.
Yep, that was probably the problem if they were AI controlled.
Looks neat, thanks for sharing!
On the server only, you can get back to the PlayerController through the Owner variable on the PlayerState. The controller will be the PlayerState’s owner. That doesn’t work for remote clients though, as they won’t know about that controller.
Yeah, the team stuff probably ends up being very game specific based on your needs. If you’re frequently asking for things like HP/Mana of teammates happens, you could possibly also look to store the Pawns/Characters that are on each team in their respective TeamInfos, but then you’d have to make sure that newly spawned pawns register into those arrays correctly (if you have respawning, etc.).
We tend to try to not rely on replication order in that way. I’m sorry I took so long to get around to replying to this thread again, so I’m not sure if you’ve already solved your issue yet or not. Are you trying to do a general initialization on the whole game (like game is ready to play, so I should play some effects!) or specifically when a team is set on one player?
I’m not actually well-versed on ShooterGame off the top of my head, so can’t confirm just yet w/o downloading it. My hunch is that it’s using a counter to replicate firing visuals, but would need to investigate to be sure. As it is, I’m actually probably about half-way done with porting the last 2 BP tutorial videos to a C++ blog, but I’m not sure when I’ll find time to finish it just yet. I started it during some spare time last weekend, but I’ll be in Portland for some developer events this weekend (hope to see a lot of people there!).
For variable vs. function, a rough rule-of-thumb is you want variable replication for persistent state and function replication for one-off events. In your case, how you handle it probably depends on exactly what you’re doing. When you’re charging the projectile, is it already spawned and sitting in place? Or is your character doing a cast animation and then it spawns the projectile after the charge? Do you need VFX (particles, sounds, etc.) specifically playing during charge, etc. If you’re doing a casting animation that need to play like a looping particle or something (and the cast time is long enough for it to matter), there’s an argument to be made that the casting step is a state that persists for a while (might want variable replication). Extreme example: Pretend the cast is 10 seconds long and it plays particles on your character during the cast. If you just use an event when it starts, players who are out of relevancy (part 4 of the videos) might miss the event. If they wander up to you afterwards, but before the cast, they won’t see the particles or know you’re preparing to cast.
SO I have to use my own movement implementation or can I set the owner to the PlayerController AND have the pawn possessed by the AIController?
Then everything the Clientside PlayerState might be needing later on must be queried from the server?
Right now I am saving a pointer to every teammember pawn in an array in my teaminfo. I am not able to test if that even works because my game is not in a state to spawn/handle team members right now.
I didn’t solved it completely, all I did was removing my reference to the team leader and use a team index instead.
I was trying to move the player camera after join depending on assigned team. The problem was even if the PlayerState was replicated to the client the containing team variable wasn’t and if I called my PC::init() in the On_RepPS function the team was still null and therefore my camera function couldn’t find the TeamStart camera. If possible I want to avoid a “click to play/ready” scenario. IF I add a pre game lobby system later the teams might be already replicated if the game starts but
I will probably have this kind of problems in many stages of my development. Do you have a tip how to handle such situations?
I’ve discovered an issue with how I’m handling the projectile, and I’m not sure what alternatives I have right now. The ProjectileMovement component is not replicating to my clients at all, that is, it’s still Null on my client side even though the server sees things happening and can modify it. This means when I add velocity to it upon it being launched, the client doesn’t seem to get that code running properly because it doesn’t have a ProjectileMovement component to set Velocity on (it crashes if i didn’t have an if (ProjectileMovement) prior).
Argh! Sorry again for being slow on the replies, was in Portland and then ill. Just now getting caught back up.
For movement stuff, you might want to check out what the top-town template game is doing. I’ve not played around with it much, but I just realized it might have player controlled movement in the style you’re looking for.
Yeah, so getting the player controller that way is not great unless you’re in a situation where the info you want only needs to be available to the owning client and the server. Was just pointing out that it’s technically possible to get back to the controller in that scenario on the server/owning client. It’s fine to have the team info on the game state and the individual player state to have a reference to its team info as well.
In this scenario, if you just want to do a local client initialization, set the camera, etc., you could probably actually do it on the OnRep of the TeamInfo on the PlayerState itself. You could cast the owner of the PlayerState to your PlayerController class (which should only be valid on the owner and the server) and then if it’s something you only want to happen for the local player (like camera changes), also make sure the controller IsLocallyControlled(), and if both of those things are true, then do w/e logic you want.
Re: general tips for this, we try to avoid complex chains of multiple references requiring each other to be initialized in order to handle replication. In the event we do have to do it, you can usually either have the reliant OnRep calls do similar things but only have whichever piece comes in last handle the actual code, or you could use timers to delay until pieces have replicated down. The timer solution can get out of hand/hacky if you use it everywhere, but it’s not too bad in minor cases. To do it, you’d put a non-looping timer (GetWorld()->GetTimerManager()->SetTimer(…)) in the OnRep that when called will verify if you have all of the things necessary. If not, the timer sets itself again. We tend to avoid the timer solution, but it is an option.
Re: the first question, nope, it’s not possible to have a static blueprint library function that will do explicitly that. The blueprint library functions won’t work with any of the replicated function call stuff directly. In general, you also won’t get a valid return value from any replicated function call you try to do across machines. The normal way to do something like that would be to have the client call a server function (so it will execute on the server), and then have the server call a client function in response to send something back to the client. The reason for that, if you think about it, is because if you wanted it to do one function call that executed on the server and returned a value back to you on the client all in one step, you’d have to wait for the server to answer and return something and you’d be stalling out the rest of your blueprint/code if it was explicitly waiting for it.
Thanks! Managed to avoid cold/flu type stuff, but I injured my feet somehow and then medicine I had to take made me feel ill.
Yep, BlueprintAuthorityOnly is a way to make sure that a function in a blueprint is only callable by the network authority. It doesn’t forcibly trigger the execution on the server if you try to call it from the client, it just ignores it.
So I have been trying to create a game timer that is displayed in the UI and tells the player how much time is left and Im building it all in blue prints.
I’m not entirely sure where to put the timer so that if some one joins the game they will get the server current time left for the game so there timer will sink with everyone else.
Right now I have the timer in the player controller. I recall hearing somewhere though the player controller is not replicated? If so where should I put this timer?
Also Im not even sure if Im doing the timer correctly, how might you go about setting up a timer so that when it ends the game restarts for everyone connected to the game?