Problem with Dynamic Material Instance replication

Hello,
I have an object, and I need to change it’s color during runtime. I first create the DMI from a material that has a vector parameter as the color and save it to a variable. I also have a variable OwningPlayerColor which stores the color it is supposed to have (defaults to none). Later, when I click on the object, I want it to change it’s color to the color of the player controller that clicked it (every controller has a color assigned to it when it joins the game). This means I have to update the OwningPlayerColor. This happens correctly. The trouble starts now, but first I will say what is set to replicate:

  • The actor itself and the mesh component the material is on
  • The OwningPlayerColor variable.
  • The variable that saves the DMI

Now, I run an event which sets the parameter of the DMI to match OwningPlayerColor.

Event set to Multicast: Host can see changes from self, but not from client’s side. Clients can see both from host and self, but not from other clients.

Event set to Run on Server: Host can see changes from self and all clients, but clients can’t see changes from host, other clients and self. There is also another issue - I spawn the actors at runtime and the spawning is bound to a hotkey. When I spawn the actor, this warning appears: LogNetPackageMap: Warning: FNetGUIDCache::SupportsObject: MaterialInstanceDynamic /Engine/Transient.MaterialInstanceDynamic_1198 NOT Supported. Happens for both clients and server.

I have spend a couple hours on this, and can’t figure out why is it doing what it’s doing. I found this post, but nothing said there worked for me. I know this is a lot, but would really appreciate any help : )

Replicating the DMI variable is useless, you cannot replicate material instances.

You have to replicate the color variable and then create/update the DMI locally for each client. Use RepNotify for that, so your clients get notified whenever the variable changed value. It essentially acts as a multicast so you don’t need an additional multicast event.

Here’s roughly what you want to do :

  1. On actor clicked, call PlayerController->ServerSetOwningPlayerColor

  2. event ServerSetOwningPlayerColor (run on server) → set the value of variable OwningPlayerColor on the actor

  3. Make sure that variable Replicates with RepNotify

  4. In function OnRep_OwningPlayerColor (should be created automatically) → use “SetVectorParameterValueOnMaterials” which automatically creates or update the DMI with new value


Once you get it working you might notice a little delay between click and change of color on clients with ping. If you don’t need any validation logic, you can remove the delay (for the clicker) by changing color immediately upon click without waiting for round-trip replication to server. In the first step, before calling the Server function, you can immediately set OwningPlayerColor on the actor and manually call OnRep_OwningPlayerColor.

1 Like

Thanks for the reply @Chatouille ! Could I ask you one more thing? This works better, however another issue arose… Clearly the variable that saves the DMI does not replicate properly. I have it set to Replicate, but when setting the color in RepNotify, it always throws an error for clients (server is OK) and it fails to validate. If I try and print the object name, server prints for example MaterialInstanceDynamic_385, and client prints MaterialInstanceDynamic_386. Same happens when I have it set to RepNotify and print the object name. I save the DMI right away when I create it, which is in BeginPlay on the actor (or rather the child of the actor, but everything else I mentioned here is done/declared in it’s parent). I tried running it on server or multicast, it however didn’t work. Any idea what’s going on? (Sorry for the dumb (I think) questions, I’m not new to replication :confused: )

When I set the color of the actor right after I spawn it, there does not seem to be a problem as it replicates properly to everyone and from everyone. Still got no clue why it wasn’t working when changing the parameter a couple seconds after the actor spawned : /