Instanced Static Mesh replication issue

It is probably not really a replication issue but I don’t know better term for it. EDIT: no, I guess it was a replication issue after all.

I am making a forest in which every tree can be individually interacted with. I am using an actor with instanced static mesh component for my trees. When there is an interaction with a tree I spawn an actor with same model and transform as the corresponding instance and hide the instance by setting it’s scale to 0. It works just fine on the server, but on a client there are two issues.

First one is minor and I’ve read that it is a known bug that is supposed to be fixed in 4.9 so I can live with that for now. It is that when I set the transform of my new actor it doesn’t update scale on a client, but location and rotation are updated just fine. I could probably think of some workarounds and it doesn’t really affect much, I am only mentioning it because I think there is a chance that my real problem is somehow related to this bug, even though it’s unlikely.

Now the real one is that on a client my instances don’t get updated, their scale is not changed and they remain instead of being hidden. I tried to also change their location and rotation and there was no changes visible, that’s why I think it is a separate issue from the previous one. Plus there was the same behavior on the server before I checked “Mark render state dirty” in the Update Instance Transform node, so my guess is that even though it is marked, the client still doesn’t know that and it doesn’t get updated. I know that they’re actually updated on a client, just not visually, thanks to a lucky mistype: I accidentally set scale to 1000 instead of 0 and my players got launched off the map because of the collision. Collision gets scaled, just not the visual representation and everything gets scaled just fine on the server.

So, is there a way I could force instances to always be up to date for every client? Or maybe I am wrong and there is a different cause for this behavior? I got all replication checkboxes checked appropriately everywhere and all checks I placed say that things are replicated. Here is my blueprint just in case.

Well, just from the looks of it, you’re only telling the server what’s happening. You also need to tell the clients.

I just answered a similar question, here:

Maybe it can help you… Hope I understood your issue correctly

Thank you but there are no physics involved in my case, also everything gets replicated fine, except the one thing I asked about. Maybe I described it in a confusing way, that is because my understanding of the issue has progressed while I typed my initial post.

I know things are replicated because if I set scale to 100 or 1000 my characters both client and server are pushed away by scaled up collision bodies, it is just the visual that doesn’t update. I am pretty confident by now that it is caused by newly added in 4.8 option to only update instanced meshes when it is needed, which is set to false by default and even though I set it to true it it doesn’t work on a client. But of course I may be wrong and the solution lies completely elsewhere. Maybe I’ll install 4.7 to confirm my idea.

Yeah I knew it wasn’t physics related, but the main point of my answer on that post was that all clients need all information of whatever is happening/changing

So let me get this straight… You’re hitting a tree, and it’s supposed to get larger? And the clients can’t see this?

I am hitting a tree which is a instanced static mesh component, it is supposed to disappear because I am setting scale to 0, and another actor is supposed to appear in the same spot, looking exactly like that tree and immediately fall down (just rotation) because that’s all it does for now. And this is exactly what happens on the server. On a client all the same things happen, except the instanced tree doesn’t get scaled to 0, or to any other value, or moved, or rotated (I tried various things), except the collision. New tree actor appears and animates like it is supposed to on both server and client …

… well, I ran some more tests and it appears that I was wrong, looks like my instanced components do not replicate, I guess collision works because server manages that anyway. Tried it with 4.7, same things happen. I was too quick to jump to conclusions and now I am completely out of ideas. Maybe instanced static meshes just don’t replicate? Or at least any changes to them, because initial positions of trees are fine on the client.

EDIT: I got it to work by moving just the part that does tree appearance change to a new event which replicates as multicast while my main event that does tracing and determines if we hit a tree still server only. New event is called from within the old event. Now the problem is that I don’t completely understand what does it mean and if it is safe.

That’s exactly what I meant you should - just like I show in the answer I posted :slight_smile:

Multicast tells all clients info. Glad ya figured it out

Yes, I understood a bit later that it was just what you said in the first place, so thank you, I should have paid more attention and not discarded things right away because I had a different idea at the time. I just don’t understand why some things work from server only event, like my new tree spawns and animates, but other things have to be put in multicast.

This is a really confusing issue for me too, I really wish this was explained to me!

All I know is it works, not why it works. If you figure it out let me know.

My guess would be that spawning something is somehow different than transforming it in any way.

There is a new one, which is actually the old one just in new circumstances.
If a player joins when game is in progress and some trees have been cut down he still sees the initial state of things. I need to somehow update the state of my instances to the newly joining client. I don’t think multicast would be appropriate because I only need to update one specific player, but I tried it anyway and it doesn’t work. I tried many things and my blueprint piled up to a huge mess but here is a cleaned up version of it. It is probably very wrong. I am not even sure that I should use event BeginPlay.

Trying to figure out the same thing.

One idea was to create a smaller array that is replicated that stores the state change from default. In my tests, it seems every instanced foliage actor has the same ID on both client and server so you could have one array that only stores which tree is currently chopped down. If you have more than 2048 chopped down trees you might run into replication issues (based on my searches that UE4 culls dynamic arrays over 2048 length for replication)

Ideally that array only needs to be transferred once. on game load. Then multicast takes over for future updates.

Another idea which requires C++ would be to transfer that initial state via TCP. No idea how to do it but it could work! I am going to keep hammering at it and post when I find some answers.

I got it to work!!!

Here is my best explanation:

I am using the procedural foliage generator from 4.8. I have the server store a non replicated array of hidden trees. You don’t need to know the state of all trees, just the hidden ones.

I made a replicated BP called ResourceNodeHandler that has functions to help edit the Instanced Static Mesh from the procedural foliage generator. The array of “dead” trees is not replicated.

When you hit a tree (run on server) add the dead tree’s instance ID to the non-replicated array in ResourceNodeHandler. Then multicast to hide that particular mesh for all connected clients.

Now to new clients joining mid game. On your PlayerController create an event that is Run On Owning Client with a input for an array of ints. This will be your dead trees. On that event just handle looping through and hiding all the dead ones.

In your GameMode event OnPostLogin you will cast the player and then run that new PlayerController event you made. Pass in the InstanceIDs and you are good to go! You will probably need to add a delay loop for OnPostLogin because its possible some actors haven’t spawned yet on the client.

GameMode Blueprint

PlayerController Event to handling incoming data. Only runs on client.

**ResourceHandler Actor that does keeps track of dead tree array on server and does multicast on active clients.
**

**After PlayerController gets the array of dead trees, loop through it and hide them.
**

Hey,

sorry that I have to revive this thread but I’m struggling to get something like this to work. I’ve setup a BP with Hierarchical Instanced Static Mesh Components. I save all the transform information (+ other stuff like random humidity etc.) in an array of structs and then I MultiCast to each Client and Update the Transforms. Now since replication does not work for HISMs how can I update only when the BP is relevant for a specific client ? I mean, I can’t just MultiCast every 5 minutes and update the state of each tree individually when there are thousands of them. This means replacing them with “dry” or “overwatered” versions etc. etc. (by just manipulating the scale to 0,0,0 and spawning another instance for a different “overwatered” HISM Component included in this BP)

Is there any tutorial out there that covers this particular topic ? If I can’t do that in a proper and performance efficient way I can stop developing my project altogether. Please help :frowning: Also Executing on owning Client doesn’t work for me, it seems like the server is always the owner of that BP. Or do I need to do this in the Player Controller then ? Updating trees in range maybe ? I’m so confused…

No one here who knows how to do something like that ? :frowning:

You’ll need to figure out a way to filter which clients need to know about what you’re doing now and which don’t. You could possibly set up a bunch of overlap volumes that track when players enter / exit a specific area. If a player is in the overlap volume, send them the info, otherwise wait until they enter the area to send it to them.

As for your execute on owning client problem, I got around that by creating a component that I attach to players and within that component is where i handle all of my “owning client” code. It turns into spagetti code, but it works.

something like
server-side HISM_BP calls server-side Player_Component_BP and says hey do “something”.
server-side Player_Component_bp then makes a replicated event call to it’s self via “execute on owning client” to do “something” client-side.

Just be mindful when doing this that “something” needs to be done both on the server and on the client and the order in which that happens is important.

[edit: i’ll look later today or tomorrow and post an pic example]

Thanks for the helpful information! I’ve set it up so I have multiple very large “rain” areas which “include” about 3-4 “Foliage_BP” - forests (just to be able to change the individual tree state depending on the rain “heavyness” in that particular area and so I don’t have too many instances at once that change). So lets say the rain area in the west of my island is active. Then a property named humidity increments by 10 every 5 minutes in the foliage structs of all “foliage_bp” - forests that are within that rain area and get updated on the server (in a replicated array of structs).

According to your post I just have to create a trigger box and a custom event that is executed on the owning client once that player enters the trigger box(since all other players don’t need to know the updates when they are miles away). Problem is that the foliage_BPs must be placed already in the editor (I can’t spawn them for each player at runtime). Could it work if I run that custom event in the affected player controller ? Then the owner should always be the controlling client right ? Maybe then I can update the instances individually ?

Honestly I’m not 100% sure that it will work, but I am 99%.

You’ll need to interface your custom bp, the trigger boxes, and the clients together.

Inside the trigger boxes I would just keep an array of players that are inside that trigger box area. When a player BeginOverlaps with the trigger box, add the player to the list of active players in that zone, and when they EndOverlap, remove them from the list. You’ll also want to make a function called something like GetActivePlayerList that returns the array of active players. You’ll need to set it up so you can call this triggerbox function from inside your custom blueprint, then you can loop through that blueprint can send data to players that are only inside that zone.

Now since your custom blueprint does not have a net owner, you’ll need to do the trickery that I mentioned earlier. You can put the functions directly in your player’s blueprint or controller blueprint (what ever works for your game), but I prefer to set it up through a custom component so the “system” can be more or less dropped into any project that you use without requiring very much setup (since you, for the most part, will just need to add the component to your player or controller).

An example of how I do this in my project (a foliage resource gathering system based on foliage painted onto the map with the in-editor foliage tool).

Note: This isn’t a 100% “correct” example. In the last image you’ll see that I made a call to the foliage component (via client side … which is perfectly legal). If I ever refine this system, I’ll simply use my Network Handler component as a “wrapper class” where the foliage component will tell the client to call a network handler component function, and that (client-side) function will directly make a call to the client-side version of the foliage component (so no actual “code” happens inside the network handler … it just acts as a “wrapper class”).

Note2: In my first or second image you’ll see I have an Array of Network Client Components. In my project, i’m more or less just multicasting the function connected to it (since I had to be as general as possible in my project) … but I pre-build the network client components array everytime someone hit’s a foliage instance. In other words you can do something similar … where everytime clients need to know something about a change that you make to your component, you can get a list of active players inside that zone and pre-build an array that consists of only those players. When players freshly enter that zone, you can have them request information from the server regarding your component’s state and have the server send back to that specific client the info that they need. Honestly I don’t “know” if using trigger boxes is the best approach, but that’s how I was planning on doing it (on a “tiled” map with trigger boxes that tell the client to load / unload map chunks / foliage instance state / etc… as they enter / exit the trigger volume).

Note3: Inside the BeginPlay event, in your custom blueprint and the trigger volumes you can use a “Get All Actors of Class” node and through code figure out which trigger volumes / custom bps need to know about each other.

To me personally it all seems a bit “hackish” … but from my experience (as a hobbyist programmer for many years … “hackish” things in games are normal).

Also if I confused you at all and you need more clarification on something … let me know (I’m good at confusing people lol).

It’s not confusing at all, actually it’s kinda funny since I see a lot of the same logic in your screenshots I “hacked” myself in my project as well :D. Thanks a lot for the in-depth explanation of your system! I will try to create a component that will handle all this just as you said so it is more like a “module” that can be used in any project by just migrating the component. I just need to make the “run on owning client” thing work but if I do all of that in the character or controller it should work I hope.

I think it’s hacky just because replication is not supported out of the box for instances. But Instances are so powerful you can do all kinds of stuff with them, it’s crazy! Excited to give it a try, thanks a bunch man! :slight_smile:

That’s the beauty of doing it through a “network” component. Once you attach it to a net owning client, it inherits the “net owning client” ability.

And you’re probably right about it being hackish because it deals with instances. This was my first attempt at replication … honestly I have no clue how you’re “supposed” to replicate things lol.

I got it working.

Although an ISMC variable can’t be replicated like a normal variable, a function from the user’s main PlayerController (which can be a class which inherits ACharacter) can be called for all relevant clients.

To get a client to update the server and all clients, the client’s input should call a normal function that passes info to a UFUNCTION with Server that calls a UFUNCTION with NetMulticast.

I got this working with help from the the C++ example: https://wiki.unrealengine.com/Replic…function_calls. Not sure how to do in blueprints.