Hey, I have ships which are Ghosts with parts of them spawning as separate Ghosts (fake childs).
This works in general but there’s one thing broken: The parts are fixed to the parent and there’s no reason to send it’s LocalTransform. This prevents the parts from getting their positions rolled back on the server and thus raycasts hit their colliders in the past.
The manual states that if a variable is relevant to the simulation (and needs to be rolled back) it must either be marked as GhostField or not depend on the previous value. This sounds to me like the ship (parent) having its LocalTransform serialized and send and then the child inheriting it’s position via Parent/Child during rollback should be valid. Or there should be a simulation system I can add to manually do this in this case.
What I tried:
Marking the LocalTransform of the parts as serialize Position&Rotation - 3D (just to test, these would be a big amount of wasted bytes) → Looks like sending LT + Parent breaks something, it’s worse
Have the parts as actual children → Because physics does not allow multiple Rigidbodies and unparents them, I have to remove the childs RB and change the logic of the parent to handle the clients; side rant: I hate that this is not supported, makes complex physics objects less modular and more convoluted → this might be the solution I have to go with, it’s just really really bad
Instead of using the Parent/Child logic I tried calculating the the parts world position myself but with prediction/interpolation/… this is not easy → seems to me like this would be the “proper” solution
It is not really clear what you are trying to achieve by having seperate entity ghosts. Are the parts swappable? Will that change the collision of the ship? Can the parts move in relation to the ship?
Having no rigid body will have the parts static, and cause rebuild of static physics world each time you try to move them.
Depending on what you are trying to achieve you could maybe prebake different collider setups, try to use joints or as you suggested just offset the child rigidbodies as kinematics.
I have a base ship. It’s predicted on all clients, can be driven by a player and has a velocity. I want to attach other Entities to this ship - currently cannons and armor. There can be any number of these as there are different ship types. The parts are destructible. In the case of cannons they need to have their own owner (another player). All parts are predicted and need to follow the ships velocity. They need to be predicted because the CCs of other players need to be predicted and for that to work the platform aka the ships need to be predicted. Their position is fixed relative to the ship.
Currently I have spawners on the ship spawning parts during runtime. They are seperate Ghosts and the client receives the Entity only. This works except for rollback - because the ship parts LocalTransform is not marked for network serialization and subsequently does not get rolled back.
I think BuildCharacterPredictedRotationSystem from the OnlineFPS sample does something similar. I’ll try to do the same. Conceptually, I need to be able to tell the Transform system of some Entities to update during rollback because the value I need to recompute is transforms.
Or… shouldn’t this be just working when physics lag compensation is active?
Still not clear what you mean with destructible. If they can’t be singled out targeted or the detail of the collision or events (e.g hit point or siluette) is not as important you can do a calculation on what part should be damaged when something is hitting the ship collider.
If it is important and you want it dynamically swappable as you say. I think looking at fixed joint Joints | Unity Physics | 1.3.5 , not sure if only baked from non-dots physics component?, would be a good start to try to set up in runtime.
Like I said, the parts already work by creating and parenting them at runtime. The part that does not work is server-side rollback for bullet raycasts (probably because the LocalTransform of parts is not marked for network serialization and thus not recorded and rolled back). I’m all for a joint but I fail to see how joints are going to fix this.
The most viable solution here is probably to have the colliders as part of the ship and update that as parts gets destroyed/repaired. I had hoped there was a more modular solution but I see how there need to be some restrictions for the netcode to work well.
I don’t think lag compensation is the issue here, it is simply storing the physics world from previous ticks. So it shouldn’t be connected to what you sync to clients and should work out of the box.
It’s probably helpful if you haven’t already to use the physics debug drawers to see where your colliders are in the world & draw some lines for your bullet rays.
Hmm, you might be right. The server-side looks way too far behind at 200ms ping. Hmm…
I’m using the Online FPS sample as a basis so I would assume the shooting/raycast is fine.
This idea sounds correct. To achieve it, my understanding is that you’d need to do the following:
For all fake children, disable their LocalTransform replication (as you’re already doing) via DontSerializeVariant on the GhostAuthoringInspectionComponent.
Write a system that runs just after the GhostUpdateSystem - inside the GhostSimulationSystemGroup - as the GhostUpdateSystem sets all GhostFields on the Predicted ghosts to their first predicted tick, including the LocalTransform.
Inside this new system, iterate over all boats, iterate through all FakeChildren “attached” to the boats, and set their LocalTransform as needed to the newly calculated world position.
Each PredictedSimulationSystemGroup tick will also need to be set to update the FakeParent childrens position.
Lag Compensation should work as the fake parenting will be updated correctly.
For all interpolated ghosts, I believe it should also work the same, as interpolated ghosts are also updated by the GhostUpdateSystem.
Unfortunately we haven’t got samples for this type of thing.
Yeah fair points. And yeah - netcode cannot reason about dynamic children unfortunately, as we cannot find out which GhostFields /GhostComponents exist on them at bake time, thus we cannot write a serializer for them. Thus, to support GhostFields, children have to either be static, or you add the logic to an IBufferElementData on the root ghost.