A very simple script for keeping non-controlled objects in synchronization with the prediction system.
Many games will require physics bodies to be networked, even if not controlled by players or the server. These objects can also work along-side the new state system by adding a basic prediction script on them.
It's worth noting that you can also 'control' non-owned objects on the server by using base.HasAuthority. This was discussed previously here.
Sample Script
Below is a full example script to synchronize a non-controlled rigidbody. Since the rigidbody is only reactive, input polling is not needed. Otherwise you'll find the data structures are near identical to the ones where we took input.
It is strongly recommended to review the controlling objects guide for additional notes in understanding the code below.
publicclassRigidbodySync:NetworkBehaviour{ //Replicate structure.publicstructReplicateData:IReplicateData { //The uint isn't used but Unity C# version does not //allow parameter-less constructors we something //must be set as a parameter.publicReplicateData(uint unused) :this() {}privateuint _tick;publicvoidDispose() { }publicuintGetTick() => _tick;publicvoidSetTick(uint value) => _tick = value; } //Reconcile structure.publicstructReconcileData:IReconcileData {publicPredictionRigidbody PredictionRigidbody;publicReconcileData(PredictionRigidbody pr) :this() { PredictionRigidbody = pr; }privateuint _tick;publicvoidDispose() { }publicuintGetTick() => _tick;publicvoidSetTick(uint value) => _tick = value; } //Forces are not applied in this example but you //could definitely still apply forces to the PredictionRigidbody //even with no controller, such as if you wanted to bump it //with a player.privatePredictionRigidbody PredictionRigidbody;privatevoidAwake() { PredictionRigidbody =ObjectCaches<PredictionRigidbody>.Retrieve();PredictionRigidbody.Initialize(GetComponent<Rigidbody>()); }privatevoidOnDestroy() {ObjectCaches<PredictionRigidbody>.StoreAndDefault(ref PredictionRigidbody); } //In this example we do not need to use OnTick, only OnPostTick. //Because input is not processed on this object you only //need to pass in default for RunInputs, which can safely //be done in OnPostTick.publicoverridevoidOnStartNetwork() { base.TimeManager.OnPostTick+= TimeManager_OnPostTick; }publicoverridevoidOnStopNetwork() { base.TimeManager.OnPostTick-= TimeManager_OnPostTick; }privatevoidTimeManager_OnPostTick() {RunInputs(default);CreateReconcile(); } [Replicate] private void RunInputs(ReplicateData md, ReplicateState state = ReplicateState.Invalid, Channel channel = Channel.Unreliable)
{ //If this object is free-moving and uncontrolled then there is no logic. //Just let physics do it's thing. } //Create the reconcile data here and call your reconcile method.publicoverridevoidCreateReconcile() {ReconcileData rd =newReconcileData(PredictionRigidbody);ReconcileState(rd); } [Reconcile]privatevoidReconcileState(ReconcileData data,Channel channel =Channel.Unreliable) { //Call reconcile on your PredictionRigidbody field passing in //values from data.PredictionRigidbody.Reconcile(data.PredictionRigidbody); }}