4.7.4 server only function replication does not fire. (Example project included)

I’m creating a simple clickable object that can be picked up in game. idea is that you can click it to collect it. When clicked this will call server only function that sets collected and “collectedRotation” variables. Both of these are replicated. This should cause them to replicate down to clients. When performed by server this behaves as expected but when client clicks item, event is never called on server version of object.

I’ve included a example project that includes object in question. general order of operations should be:
[Project Example][1]

  1. Client clicks object
  2. Client object registers click and performs action
  3. Calls server function to modify collected items variables
  4. Call interface function on player controller that clicked.
  5. Player Controller implements interface call (in this case it calls collect item on player state)
  6. Player state spawns item for player (and would store in an array in a proper implementation)

So looking into this more, only conclusion I can draw is that collectible item does not have a NetOwner on client and thus can not make server only call. How should requests to server be handled in this situation?

Hi ,

I believe problem you’re running into is that replicated variables do not communicate from Client to Server, only from Server to Client, as described here:

For something like this, it might be better to use RepNotify functions. Let me know if you need any help setting that up.

Hope that helps!

Well I can understand that but I could have sworn that I was going server to client. only time replicated variables are changed are within a server only function. Does this not effectively cause client to request change from server and then have server replicate changes down to all clients?

I’ve updated main post with screenshots of post to make it easier to have a quick look.

So I have looked into this further Specifically events section in link you provided. It looks like client can never call collect because object is not owned by invoking client. (it starts in level so it is never called due to it being owned by server)

I then tried to have client spawn an actor that replicates. Due to it not being server it only appeared on client and not server but client was able to interact with object just fine.

last thing I tried was to spawn an object using a check for authority. If you had authority spawn object if not call a server only function that spawned it. Doing this cause object to spawn on server and replicate down. however server owned object again so client could not interact with it because run on server call was dropped.

Given that player controllers do not inherently replicate (nor does it really make sense for them to) how should a non replicating actor make a request to server?

That’s correct. Sorry I answered before looking at project first, but since Actor is owned by Server, Run on Server won’t communicate with Server from Client, and that RPC will be dropped.

To get around this, easiest thing is to send information to Client’s PlayerController, which can communicate with Server. Something like this:

That calls this on local PlayerController:

37653-collectibleplayercontrollerrpc.png

Which calls Server_CollectItem Custom Event on Collectible.

Hope that helps!

while I understand workaround, that ruins encapsulation of system since I can’t make a interface event server only. Having to make a new version of a collectible based on every version of player controller isn’t practice. Is there a way for server to assign ownership to a client?

There isn’t a way to assign ownership to a Client, but that wouldn’t make a lot of sense outside of components; most everything in a level belongs to Server. Clients can only own a few things: Client’s player controller, pawn, and player state, and any components belonging to those. For your collectible to belong to a Client, it would need to be a component of one of these. Since you want everyone to be able to view and interact with collectible, it needs to belong to Server so results of that interaction can be replicated to everyone else. Client can’t replicate anything to other Clients (everything is done through Server), so it wouldn’t work if collectible was owned by Client.

I’m not certain I understand what wouldn’t work this way. You shouldn’t need to create a new version of collectible for every player controller version. So if you have multiple types of player controller, each would utilize same call to your collectible. It references collectible instance (it’s passed Self from collectible that calls it). Why would you need multiple collectible versions for this? How does your interface work into this scenario? Is there something I’m missing with your setup?

in your setup you cast to a CollectiblePlayerController in order to call ClienttoServerCollect event. If a different player controller (say a sidekickController) would not be able to call ClientToServer call as it would fail cast.

My interface in this setup is to help work around this. I perform a check to see if class implements my interface first. This determines if client can interact with it at all. If it does then call appropriate function that implements custom based on who collected it. (Dr Jekyll collects it then heal, Mr Hyde collects it then hurt as an example.) same item but different implementations. For encapsulation item should take care of it’s own clean up. In this case animating and destroying itself.

I only see two options at this point. One is to have player controller call call a server function to implement clean up which breaks encapsulation as it makes communication two way rather than one way.

other is to create an adapter for client to server function calls through c++ using a special class of game instance. this way I can basically do same thing as event but pass it a function name and use object->findFunction method.

If you have other suggestions, I’m more than open to them.

Hi .

So I have been trying a few things. Specifically I created a new game instance to act as an interface for replication. this resulted in same result in end though.

I got to thinking though. Why does a RunOnServer event work on a player controller that isn’t replicated? Is there something about player controller that is special and allows for this to happen?

As a side note this documentations states that:

You can use Replicates checkbox for any Interfaces containing functions that need to replicate across server. This is found within Details tab by first clicking BlueprintProps.png button.

That would make this whole thing a whole lot easier.

Hi. I just wanted to check if there anyone had a chance to look at this about interface replication methods. That would fix everything.

At this point I’m guessing that this is a bit of a loss cause. Having implementation encapsulated for easy reuse doesn’t seem possible while interface replication is not implemented. I’ll post a new question regarding that and reference this post.