What's wrong with this RPC?
I'm trying to set up a door switch that locks and unlocks doors in my level and works in a multiplayer context (i.e. both server and clients can interact with said switch to lock/unlock doors.) but I'm running into a problem on the client side and I can't put my finger on the exact cause.
Here's the event graph from my Blueprint:
The DoorSwitch function is set to execute on server with SwitchHasAuthority and everything works great when the player on the server steps into the ConsoleTrigger volume and presses Interact (E)– doors lock/unlock properly and switch color changes on server and clients, but nothing happens when a client attempts to do the same.
Watching the Blueprint while playing in the editor, the OnComponentBeginOverlap and OnComponentEndOverlap events fire when either client or server enters/exits the trigger volume but only the server fires the rest when Interact (E) is pressed. Even the PrintString in RPCActivateConsole refuses to fire from the client.
Blueprint is set to Replicates=TRUE under defaults.
My current theories as to why this isn't working are:
1 - My Blueprint was placed in the level manually via the editor, which I believe causes it to be owned by the server, which might explain why the client RPC isn't firing.
2 - I'm not actually getting the right PlayerController for Enable/Disable input. I know that GetPlayerController only works in a local (split-screen) multiplayer context so I'm trying to use GetController but I'm not 100% sure that I'm doing that bit correctly for client/server multiplayer.
if It's #1, how can I either change the actor's owner or change the way the Blueprint spawns into the level to make it accessible by clients?
If it is #2, what should I be doing instead?
If the issue is somewhere else, please let me know. :)
asked Dec 17 '14 at 06:41 PM in Blueprint Scripting
So, after a lot of reading and trial-and-error, I managed to come up with a solution, which I'm posting here in case anyone else gets hung up trying to do something similar.
First and foremost, it appears that trying to do client input directly on a Blueprint class (especially once it's been placed in a level via the editor) just plain doesn't work. Not sure if this is intentional or not but it looks like my theory about the actor being owned by the server was accurate.
I managed to do a quick test using GetActorTransform/SpawnActor on a SpawnPoint as illustrated in Epic's Content Examples / Networking / 1.1 just to prove that something spawned into the level and thereby not owned by the server would take client input directly from the Blueprint class' Event Graph but this technique causes all sorts of other problems like the Actor only being visible on the client and not having collision by default and such that I didn't want to have to deal with, so...
I ended up abandoning the Blueprint class' Event Graph for the most part and instead did the input handling on the Player Controller (MyCharacter in my case), which I've come to learn is the generally-accepted best place to do such things.
Though I've come to understand the reasoning behind the idea of putting all input handling on the Player Controller (especially in a client/server multiplayer context), I do still kinda wish I could have made it work entirely on the Blueprint itself if only to make it more portable/modular but I digress.
Ultimately, all it took was a bit of a re-think as to how I'd refer to things within the Blueprint being removed from the context of the Blueprint class.
Here are the additions I had to make to my Player Controller (MyCharacter) Event Graph and the little bit of functionality I left on the Blueprint itself (where everything used to be).
The big changes here are having to identify and refer to the actors in the level themselves as opposed to he class as a whole– hence GetAllActorsOfClass. Also note that I'm now setting a non-Replicated variable in the Blueprint class (IsInRange) just to make sure that the Player Controller is in range of the console/button when they Interact (hit the E key).
I'm honestly not sure if there is another viable/better way to accomplish something like this. I experimented with EventDispatchers and a few other things but this was what ultimately worked for me.
If any of you UE4 gurus have any insights into any of this, I'd love to read them. I'm starting to feel like less of a newbie after having figured this out but I've still got a lot to learn and would appreciate any helpful feedback folks might have.
answered Dec 18 '14 at 06:26 AM
A good way to go about this would be to have any actor you want to interact with implement an "interact" interface.
Then in the PlayerController you bind a key to interact and make this call a Replicated, Run on Server event to which you pass a reference to the player controller and the actor that it is trying to interact with.
In the run on server event you check if the actor implements the "interact" interface, and if it does, you call the interact function on the actor.
With this method you can interact with anything that implements the interface and an interact function, and since it runs on the server it will be replicated to all clients as long as the actor is set to replicate.
Hope this can be helpful to someone :)
answered Jun 18 '16 at 12:19 PM
Follow this question
Once you sign in you will be able to subscribe for any updates here