RPC doesn't work on repicated UObject

I’ve set up my UObject derived class properly (like recomended here). And property replication works good, BUT I can’t call RPC on this object. On server side I’ve tried to call method marked as UFUNCTION(NetMulticast, Reliable). And it didn’t work.
When I rederived this my class from UActorComponent (instead of simple UObject with setted up replication), this method started work.
What have I missed? Why didn’t it work?

Hi there,

I am researching this topic as well and also implemented your referenced link.
I’ve looked right into the engine code and interestingly enough “CallRemoteFunction” of UObject simply returns false, while Actor and ActorComponent are implementing the function like this:

bool UActorComponent::CallRemoteFunction( UFunction* Function, void* Parameters, FOutParmRec* OutParms, FFrame* Stack )
{
	if (AActor* MyOwner = GetOwner())
	{
		UNetDriver* NetDriver = MyOwner->GetNetDriver();
		if (NetDriver)
		{
			NetDriver->ProcessRemoteFunction(MyOwner, Function, Parameters, OutParms, Stack, this);
			return true;
		}
	}

	return false;
}

First of all, I do not really know how RPCs are exactly created from the written code. But since UObject is not able to do RPCs, while Actor and ActorComponents can and these two inherit from UObject, there must be some function(s) which override(s) something from UObject to allow the known behaviour of RPCs.

As you can see there is a need of an Owner and further along if you want to differ your Role between ROLE_Authority or ROLE_… you will realize that UObject does not have a role. Problem is UObject does neither contain Owner nor a Role.

Thank you. Please, make your answer realy “answer” to let me accept it.

Changed it.

Erm since the “answer” is only an answer to your question as to why it doesn´t work, assuming that you would actually like to know how you can make it work and have a proper visual demonstration of what works and what doesn´t work as a cheatsheet from the actual documentation, see here: http://prntscr.com/bz6o5l

Reference: RPCs | Unreal Engine Documentation

So to sum up - if you want this to work, you don´t use NetMulticast - but use Server.

I don’t really get your “sum up”-point.

How I understood it, OP wanted to create a UObject as a Subobject of an Actor. Furthermore he wanted to call a NetMulticast-Function from this Subobject(UObject, not Actor!).

The problem which is highlighted in this question is to actually understand why UObjects won’t allow RPCs.

I think, you currently assume, that he tries to call a NetMulticast-Function from the client. And then you are right. This function would only get executed on the client.
So first you(the client) would sent a Server RPC to the server. And then the server sends a NetMulticast to broadcast this info to all clients.

if i call the rpc function of uobject in playercontroller in server , the uobject alse cant netmulitcast to other clients? why ?

You would have to execute a NetMultiCast funtion which is defined in an Actor or ActorComponent. (e.g. your PlayerController from server)

This function would call the function of the UObject.

I guess you tried to tag the Function in your UObject as NetMultiCast and execute this function from your PlayerController. However it doesn’t really matter from where you try to call this function.

Point is, that the compiler tries to create an event from your ‘NetMultiCast’-tagged function. UObject alone is not able to create such an event without further help. Thus you have to create such RPC-Functions in classes like Actor, ActorComponent which can correctly transform your RPC-Functions into actual Events.

… or you have to figure out what you have to change at a UObject so that it can transform such a function to an event. I would be really interested in this.

So, I also need to call RPC events and found solution…

As smara mentioned above, CallRemoteFunction() returns false, but if you copy logic from AActor Component, you should get True. But there is another problem… When function calls, it reaches GetFunctionCallspace(), wich returns Local by default from UObject. You have to override it as well…

My version:

bool USpecialAction::IsSupportedForNetworking() const
{
	return true;
}

bool UMyObject::CallRemoteFunction(UFunction * Function, void * Parms, FOutParmRec * OutParms, FFrame * Stack)
{
    AActor* Owner = Cast<AActor>(GetOuter());
    if (!Owner) return false;
    UNetDriver* NetDriver = Owner->GetNetDriver();
    if (!NetDriver) return false;

    NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this);

    return true;
}

int32 UMyObject::GetFunctionCallspace(UFunction * Function, void * Parameters, FFrame * Stack)
{
    AActor* Owner = Cast<AActor>(GetOuter());
    return (Owner ? Owner->GetFunctionCallspace(Function, Parameters, Stack) : FunctionCallspace::Local);
}

NOTE, that your Outer must be an Actor, that replicates this object! If you need to call Server functions (from client), Outer should be you an Actor, wich is owned by your player controller.

1 Like

Thanks, this was immensely helpful.