So i am trying to create a tree chopping system. I can’t find what seems wrong with my Blueprint. It works on single player. It’s a simple line trace that gets the instanced’s mesh and it’s id it then replaces the instanced mesh with an actor and simply removes it afterwards. Whenever i try to delete the BP Actor it won’t get replicated on the clients.
You don’t need to multicast the destroy. The server should be the only proxy doing the trace and destroy. The tree (TreeBP001) should be ticked “replicates”.
Clearing the Foliage Instance mesh you need to have every client do that part. Then only the server spawn the tree BP. This actor needs to be set to replicate. The replication system will handle replicating it out to all in net cull distance of it.
Being ticked to replicate, the server destroying it will be rep’d out to everyone.
I think i got it to work. For anyone else having the same problem i am gonna leave my BP here.
Thank you
A few things wrong here, but you’re close.
Each clients instance index will be different. On your client it maybe 1, on another it maybe 212. It’s just the way it is based on how the instances are generated and stored per client.
The next issue is you’re logic has All clients & server spawn the tree.
Too many multicasts also. One is enough. Each multicast is an RPC that eats bandwidth and adds to the network saturation. Combine as much logic as you can to reduce this hit.
Multi Set Tree:
Trace → Set instance Index → Cast → Set Component Ref → Get instance transform → Set Transform var → Remove Instance…
Branch (Is Server or Dedicated Server) [True]: → Get Data table row → Spawn Actor.
Pack all of that into a Function and use local variables in the function.
Something along the lines of:
Just pack it all in a function, use local vars to reduce overhead and baggage.
I’m having the exact same issue as the OP such that sometimes (but not always) instanced static meshes fail at a Remove Instance node, which is the only thing that is Multicast. I was going to try your approach above, but while you mention using only one Multicast, I can’t see that in the graph. Do you just execute Mcast Replace Instance on client (but don’t show this in the screenshot). I tried running on server only (with ISM replicated) but the client copy isn’t removed on the client.
The code shown is all that I use. Only 1 multicast. The only code not shown is the client input event that calls Srv Replace Instance.
Srv Replace Instance (Run on Server event) calls MCast Replace Instance…which is executed on the server and all clients.
The actor that I’m spawning is a replicated actor, thus only the server spawns it…hence the is server checks.
Works with no issues on my end as long as the actor being hit by the trace is an Instanced Static Mesh. Optimally one that was added via Foliage tool. But it works with Procedural and other actors using ISM’s.
Debug your code via print strings at every cast and branch.
Thank you for answering. I just couldn’t see the denoted multicast (mine shows “Executes on All” on the node). I’ve spent 8 days on this problem but I only register the server hit on the ISM, then the client trace can’t see it (but the ISM (a tree) stays visible in game like a ghost copy). My BP below, except for extra noise from all the print strings it’s based on your solution. I get same issue with PCG or foliage ISMs. Note the code is swapping the ISM for the actor on server (and allowing harvest and destroy on that) - the only issue is the lingering original ISM on client. I’ve confirmed indexes of ISMs are same on server and client too, not that it should matter how this is setup with repeated trace.
ISM Indexes can vary client to client and server. Don’t pass a value. Each has to remove its own corresponding ISM.
Here’s a demo of a more advanced version (multi-instance replacement) using an overlap collision.
The main issues with this approach for multiplayer is latency. Server is spawning the replacement and replicating it out to all in the same multicast…no delays. So clients are hitting the replacement. Therefore It’s getting to clients at the same time the client trace rpc.
RPC’s etc are bundled and sent with regular updates. Start of following Tick.
Latency is what it is, so you have to work around it.
One trick is in the replacement class is to by default have collision/physics disabled. Use begin play → delay → set collision/physics enabled. This will allow latent clients get the trace off and remove the local ISM. But you still run into issues where the server doesn’t hit what you hit.
e.g. sprint up to a tree and hit it as fast as possible.
There’s a good chance the servers authoritative proxy isn’t in range to hit, so it misses, but your autonomous doesn’t. Poof, your local is gone, but the servers isn’t, so no replacement.
Noting this there is a better approach, more work. After I get my job work done this evening I’ll whip up a demo.
Once again thanks for taking time to explain. I’m finding this a frustrating bug but you make some interesting points. My original code did a single trace and passed the value to a multicast remove instance, as I’d done testing and confirmed the instance indexes were the same on client and server (see image from a box trace), but I gather there’s more to it. And am now doing a trace for each run (client and server) so that should be fine. Except for your other point - that the server has replaced the ISM with an actor before the client gets it’s turn to find and remove the ISM - that would explain the bug, including it’s apparent randomness (as it doesn’t happen every time - I guess due to latency. Eg, often it won’t happen on a fresh UE session but will start to happen once the PC does some work). So if I understand you correctly, a whole new approach to replacing instances in a replicated environment needs to be sought. I’d sure welcome some pointers on that but otherwise will put my mind to how to overcome the latency problem - perhaps by trying to remove the client instances first. I know some others claim to have got this working by running the whole process only on the server, with exception of the multicast instance remove (but nothing more, and assuming the instances are identical). That wouldn’t seem to work all the time - even if they think it does!
See output below, initial output is box trace showing ISM names and indexes. Then it does the instance removal on server and client, success on server but fail on client. On screen, the ISM remains visible (and doubled up with the server spawned actor).
To assist here’s a video grab of the ISM removal, with the spawn working but the client instance remaining. At the very end I’m “walking through” the rock, as it doesn’t exist on server so I can glitch into it.
I worked on it a bit and have a multiplayer demo in working order. Just a few minor tweaks to be made on my end for it to feel right to me (fx mostly).
Anyway, What I’m doing is having the server remove its ISM then spawn a “replicated” actor in its place. The spawned actor removes the clients ISM. This mitigates latency hitches/bugs visual garbage.
Key factor on my end is I’m not spamming the network with server rpc calls. Server is only called when I get a hit and it (hit component) successfully casts to an ISM component.
Here’s the Event Graph in it’s entirety.
Everything else is functions and the replacement actor.
Could use a bit of clean up. I’m sure when I have a clear head I could refactor this to work better with less nodes. Quick and dirty including the meshes.
This is really innovative. I think I follow the logic, although a bit thrown in that it seems your initial event (H press) kicks off on the client (even though you describe " Anyway, What I’m doing is having the server remove its ISM then spawn…") :
As I say I think I roughly follow the idea, but wondering if for completeness it might be better if you could show the complete BPs via https://blueprintue.com/ ?
If not, the last screenshot has the start cut off but would be the Client ISM trace event, correct? Where is Srv Replace ISM called from ? Where is the variable “Client Location” set ? I’m really grateful but there’s a few bits here I can’t gel together.
Lastly, your approach clearly works - but unsure on theory re spawned actor interfering with traces, as if I unpin the nodes which create the BP actor, the issue with removal of client instance still remains regardless. And if latency related, if client instance has been removed why does it remain on screen ? And if not removed, why doesn’t it come through on the trace. Doesn’t make sense. Maybe just the domain of glitchiness…
The H input is the equivalent of you inputting an action to swing an axe/hammer. Purpose is to get a “Hit result” on the target tree. Your axe/hammer does this.
Client ISM trace calls the Srv Replace ISM. It’s noted in the bubble comment above the function.
Last Function Pic is only cutting off the Function Start and Return nodes… no pins on these.
RPC’s and Inputs are not sent (packets) on immediate execution. They are buffered until the next tick start.
Therefore a Multicast event and the servers spawned a “replicated actor” would be bundled in a single packet to clients.
If I receive a new actor in my world (replicated replacement actor) its collision will block all attempts at the client trying to trace for an ism to remove.
Clients cannot remove it without auth from the server. Doing so regardless results in a timespan in which there isn’t a representative actor rendered.
I removed my ism, now I wait for the server to spawn one and replicate it to me. If I have a 150ms ping, that’s a minimum 75ms delay (roughly 6 frames @ 60FPS).
Anyway, I’m going to do a walkthrough vid covering this setup in detail. Be back in a bit.
Many thanks for your invaluable advice … so little material on the web covering these nuances so I’m very appreciative. I’m going to try and write my own code from scratch using the concepts you’ve shared, will let you know how I go. Tx again.
Just to update you, I’ve overcome the original problem. So many thanks. I think it’s well worth doing a walkthrough vid as there’s little out there on this kind of issue. I didn’t actually do much of what you did, just ensured the server and client trace were happening properly and at least a tick apart, and it appears to work. I’ll keep testing in case the spawned BP does interfere with the client trace but so far it doesn’t appear to be. Many thanks my friend !
NICE!
Here’s the walkthrough. It’s lengthy but I try to explain the reasons for the approach in a decent amount of detail. I do ramble, so bumping the playback speed to 1.5x will help.
Thanks again, great video - not rambling imo, and better to go slow than skip stuff and talk too fast. I posted more comments on YT and a bit of a random question if you get a moment to consider it. Anyways, I can now progress further with my project after the ~2 week blockage ! TY
Excellent video! I was having the same issue and was able to implement your solution into my code. It seems to be working great! Thank you so much for taking the time to put this together and explain things so clearly!