Ok I’ve found a solution. I feel like it wastes resources but if I don’t do it exactly as I show it, it doesn’t work so it’s probably all necessary. Anyway, at the end of my Event Tick code, I added the following:
After defining Ball Slot Transform on the client side and then force updating the server to match instead of replicating the variable, I add the following to the end of the Golf Swing code shown above:
I also moved bBombAttached so that it goes false before I run Detach From Actor.
If you’re having similar issues, here’s what’s happening here, as I understand it:
The client knows where the component I attach the actor to is SUPPOSED to be, and since I snap the actor to that target, they share the same location and rotation. So if I want to be sure the Server puts the ball where the client wants it when the client is no longer constantly updating its location (while its attached), I need to store that parent component’s location and rotation info (Ball Slot on my golf club Blueprint) as a Transform variable.
When I tried replicating the variable normally, the server would, on occasion, update the client instead of the other way around. But whether you replicate a variable or not, the server knows you should have that variable, so if you tell the Server to use your copy, it will. The problem is, though, that once you stop, the server goes right back to setting that variable to what it thinks it should be. That’s the drawback of not replicating it, but the code does not work as otherwise shown if I replicate the transform variable, so that part was necessary.
So, as soon as the “Bomb Attached” variable goes false, I have the client run the code one last time with the Do Once node. However, we don’t want the Ball Slot transform data this time, we want whatever the transform data was from the previous tick. Done the other way, there’s about a 50/50 chance the server puts the location it has the Ball Slot component at instead of continuing to read the client data, which results in things looking like that video linked in the original post.
Finally, at the point the ball is detached, I add a 0.01-second delay which gives the server time to catch up with you, and then I run Set Actor Location and Rotation based on the transform data from the last Tick the variable was updated on the client.
This took a LOT of trial and error, attempts to simplify it make it either not work at all or only work sometimes, but when done exactly like this, it runs as intended. You don’t even see the ball appearing onscreen incorrectly as its stored on the server, it just appears where it’s supposed to. The other benefit is, since the last bit is just server code, if you run it as the Host or in a standalone game, the results either don’t run or don’t show up on screen for anyone, so it doesn’t break singleplayer either.