Announcement

Collapse
No announcement yet.

Instanced Static Mesh replication issue

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    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.

    Click image for larger version

Name:	blueprint_replication.jpg
Views:	1
Size:	427.2 KB
ID:	1154279
    Last edited by VRLtqq; 06-24-2015, 06:15 PM.

    #2
    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:

    https://answers.unrealengine.com/que...y-physics.html

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

    Comment


      #3
      Originally posted by vanlacke View Post
      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:

      https://answers.unrealengine.com/que...y-physics.html

      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.

      Comment


        #4
        Originally posted by VRLtqq View Post
        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?

        Comment


          #5
          Originally posted by vanlacke View Post
          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.
          Last edited by VRLtqq; 06-24-2015, 06:10 PM.

          Comment


            #6
            Originally posted by VRLtqq View Post
            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

            Multicast tells all clients info. Glad ya figured it out

            Comment


              #7
              Originally posted by vanlacke View Post
              That's exactly what I meant you should - just like I show in the answer I posted

              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.

              Comment


                #8
                Originally posted by VRLtqq View Post
                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.

                Comment


                  #9
                  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.
                  Click image for larger version

Name:	blueprint_replication2.jpg
Views:	1
Size:	222.2 KB
ID:	1080623

                  Comment


                    #10
                    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.

                    Comment


                      #11
                      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

                      Click image for larger version

Name:	6-26-2015-8-24-37-PM-3b0e.png
Views:	1
Size:	161.7 KB
ID:	1080734

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

                      Click image for larger version

Name:	6-26-2015-8-27-15-PM-b205.png
Views:	1
Size:	180.3 KB
ID:	1080735

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

                      Click image for larger version

Name:	6-26-2015-8-26-30-PM-5e05.png
Views:	1
Size:	187.4 KB
ID:	1080736

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

                      Click image for larger version

Name:	6-26-2015-8-27-27-PM-17d3.png
Views:	1
Size:	90.3 KB
ID:	1080737
                      Last edited by Zeetu; 06-26-2015, 11:30 PM.

                      Comment


                        #12
                        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 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....
                        Last edited by IceDealer; 03-21-2017, 08:59 PM.

                        Comment


                          #13
                          No one here who knows how to do something like that ?

                          Comment


                            #14
                            Originally posted by IceDealer View Post
                            No one here who knows how to do something like that ?
                            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]
                            Last edited by axenation; 03-22-2017, 09:01 AM.

                            Comment


                              #15
                              Originally posted by axenation View Post
                              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 ?
                              Last edited by IceDealer; 03-22-2017, 04:31 PM.

                              Comment

                              Working...
                              X