Actor ownership when spawned by Server at request of Client

Context:

Player uses a card, which spawns an Ability Blueprint (lets call it AbilityBP). The design of this ability is to show the player a translucent version of a Pillar (which is really a pawn) at his mouse location, and when he clicks to confirm the spawn location, the server is asked to spawn a Pillar (let’s call it PillarBP). The AbilityBP is then destroyed as it is only used during the ability use.

The problem:

When the card is used, I have the server spawn AbilityBP, which is then replicated back to the client since it is set to replicate. The reason I need AbilityBP to replicate is that the spawning of PillarBP is done in AbilityBP, so if the client plays the card, AbilityBP needs to also exist on the server, otherwise the Run On Server RPC will never fire.

Where things stop working is at the Run on Server RPC that tells the server to spawn PillarBP, if it’s the client playing (see AB ServerSpawnPillar in the 2nd screenshot below). I assume that this is because Run On Server only works if the client executing it owns the actor its being executed on, and in this case since AbilityBP was spawned by the server, the server owns it.

How do I get around this? Is everything spawned by the server, automatically owned by the server, even if it was spawned at the request of a client?

I think one approach would be getting the user input in player controller or anything the player owns, “with the actor parameter” requesting something like:

"I(client) want you(server) to execute this function on this actor",

then, you can get that on the server side player controller (or wherever it was), and behave accordingly, checking user access…etc…

instead of calling on an actor something like:

CastSpell(spell)

you call on player controller:

CastSpellFromActor(actor, spell)

if it is “your” spell, then just pass ‘this/self’ as the actor.

This way actually you can implement GM functionality easily. - Because, they should be basically do most of the things on a specific actor.

Thanks.

The reason I wanted to do as much of the processing in the ability itself is to not clutter my controller with ability-related stuff, but since all I need is to spawn a class, I went with your suggestion since I can reuse the same function for all of the abilities that spawn things (and then the rest of the ability-specific stuff can be on that new spawned class’ begin play).

For reference this is what it looks like now in AbilityBP, and then the Event itself is in the local controller, which the client owns.

Just a thought, I do not think you should pass the “Owning Team”. I do not know your setup, but, I’m guessing the server “knows” the “Owning Team” of the player controller eventually. Might create a security issue.

I have to assign a Team to the units I spawn, which is based on the Player Team variable in each player controller. That Player Team variable is assigned by the server on Post Login in the GameMode.

Since the server is spawning the unit (Sentry/Pillar in this case), I’m not sure how else the server would be able to get the team of the player who requested the spawn.

Maybe by doing Switch Has Authority → If Authority get Player Controller 0’s Player Team value, and if Remote get Player Controller 1’s Player Team value?

It’s a 2 player game so the above should work since Remote is guaranteed to be the same client every time, but I am trying to stay away from locking myself into a 2 player only setup as much as possible in case we decide to go with more than two players later on.

The function is going to be handled on server side player controller…right?
On that node you can call:

"self->GetOwningTeam"

instead of getting it as a parameter. Because it is “that” player controller who actually made the request. Passing an information like, “Hey I’m on this team!” from client side smells hacky:)

Looks like you’re right, I can get the team off the player controller directly instead.

I’m still not 100% comfortable with replication, I thought that Run On Server events were executed on the server’s player controller, not the server’s version of the client’s controller.

Thanks!