Core Sync Components
The following are some of the premade components that can be dropped into a scene
and should just work for most situations.
All Sync Components derive from the Sync Object base class,
or the further derived
SyncObjectTFrame base class which includes state buffer handling.
- SyncState Component
- SyncTransform Component
- Transform Crusher
- SyncAnimator Component
This is the base class of all Sync components. This base class isn't needed to tie into the entire Simple system but this class does make a good starting point for making components.
SyncAnimator etc all are derived from the
These objects self register with the callback timing system of NetMaster.
Shared fields among sync components:
It is recommended that you not change this.
Most SyncObjects do not make this value adjustable and have it set internally with constants. The order in which components on a network object run, in order from lowest to highest. This is used to ensure things that regardless of component order, certain things will always happen first. Some Transform and Animator setups may prefer one or the other to happen first. When components have the same Apply Order value, then the order in the gameobject hierarchy is used.
These SyncObject components work using mono-directional broadcasts (Owner -> Others). As such it is possible to reduce data by using keyframes. When no changes occur to elements of synced objects, they will send a 1 bit false flag indicating no content, rather than sending the same data every update. This does mean that loss and late joining players (in the case of PUN2) may have out of date values for a short period. Keyframes ensure eventual consistency when using delta frames. The greater the value the more data savings, but also a greater risk of odd behavior when packet loss is encountered.
If bandwidth is less of a concern, set this value to 1, and every update will contain a complete compressed state. Setting Keyframes to 0 indicates that data should only be sent when values have changed and that entire Tick Update sent for all components will be forced Reliable.
When enabled, this SyncObject will not wait for a complete update before marking itself as Ready. When disabled, this SyncObject will report as not-ready, which will prevent the NetObject from reporting itself as Ready with the INetObjectReady callbacks. Ready indicates that the object is synchronized enough to be made visible to users.
SyncObject, this adds default handling for state buffers.
The TFrame type must be a derived FrameBase class, where the fields of the state for the SyncObject can be defined.
This component standardizes and synchronizes the handling of NetObject state information, such as:
- Attachment to other NetObject Mounts
- Owner Changes
SyncState is not a required component, but other components like
may require it if they specifically are making use of the
SyncState interacts with SyncTransform and SyncOwner to synchronize parent/mount/owner changes with proper teleport handling.
Developers interact with SyncState using the methods:
- QueueStateChange() - Queues the state change and defers applying it until the next CaptureCurrentState timing. This is generally the recommended method as it ensures better deterministic order.
- ChangeState() - Immediately applies the state change locally, however it will not be captured and synced until the next net tick.
This is a helper component for SyncState that responds to OnStateChange events to automatically trigger timers for Spawn/Respawn/Despawn.
The Simple replacement for PhotonTransformView, use this to sync the states of Transform TRS values.
- None - Objects will snap to the networked states, without lerping.
- Linear - Basic Lerp/Slerp are used to interpolate between networked frames. This is likely the mode you want.
- Catmull Rom - (Experimental) A more sophisticated lerp that uses 3 points, producing a more naturally curved and accurate path than a basic lerp.
Extrapolation occurs when the tick advances but no frame info has arrived yet on clients for this object. The synced object now has to guess what the next frame's values are. Extrapolation uses the last two values to extrapolate the new frame. The Ratio is the t value used by LerpUnclamped and acts as a dampener of extrapolation. So for sequential missing frames the extrapolation gets reduced on a curve.
- 0.0 = no extrapolation - object will not move on empty buffer.
- 0.5 = evenly dampened - object will lerp less with each tick.
- 1.0 = full extrapolation - no damping, will extrapolate until a frame arrives or object is destroyed (disconnect).
The distance in units between frame updates that will trigger a teleport. This exists just to have parity with other transform syncing tools. Teleporting can have different meanings in different games, so ideally you will want to code teleport handling yourself.
Forces this client's entire outgoing tick to be reliable when a teleport occurs.
TRS data (Position, Rotation, Scale) are compressed using my Transform Crusher library, which has its own documentation.
SyncTransform uses the IOnTeleport callback interface that allows components such as
SyncTransform that an object has been teleported.
You can call OnTeleport() manually when you want an object to Teleport.
Teleporting disables interpolation and tweening momentarily to allow for objects to be moved great distances in one tick without lerping. In order to do this BEFORE you move the object to its new position call:
Or if you already have a cached reference to the transform sync component:
SyncTransform responds to this by capturing the current transform state and flags the next outgoing state as being a teleport.
That outgoing frame will contain two transform states, one for the value before teleport and one after.
Having both values allows interpolation to work correctly without causing objects to freeze for a tick when teleports occur.
Call this BEFORE you move the object that is being teleported.
The primary PhotonAnimatorView replacement component.
Index Animator Names
One of the primary compression methods of this component is the indexing of all State and Trigger names, so that rather than sending 32 bit hash values for states and ticks every update, MUCH smaller (1-5 bits) indexes are sent instead.
The indexing happens automatically behind the scenes but it may not always fire (since it can't be forced during the build process).
You may see warnings in the log asking you to press this button. It never hurts to press it, especially after making changes to your Animator Controller.
If at runtime an index isn't found, it will just fall back to sending the full 32bit hash. Things will still work, but your network usage will increase.
Sync Pass Through Methods
If you call SetTrigger(), Play(), CrossFadeInFixedTime() and such through this component, it will network those calls and pass along the command locally to the Animator. This often can give the most in sync result, for a relatively low network cost (less than a byte typically).
This syncs the 'snapshot' state of the animator and enabling this can sometimes be useful for ensuring agreement with clients. Typically if you are making use of Pass-through methods and parameters, it is not needed.
If you are using layers and want them synced, turn this on. Disable if you are not to save some data.
Sync Layer Weights
If you are animating layer weights, enable this. If you are not animating them however, be sure to turn it off to conserve data and processing time.
You can globally or selectively select which parameters to sync. Interpolation, Extrapolation and default values can be set, but generally you will just want to leave the defaults.
Anywhere normalized values are used (normalizedTime and layerWeights) an option is given for how much to compress these. Half 16 is the failsafe. Lower values can be tried to see how low you can get before seeing any artifacts.
SyncAnimator Advanced Parameter Settings
(for advanced/pro/super users)
When Use Global Settings is disabled each parameter can have its own compression settings.
Per parameter settings are not pretty to look at, but they do let you get into the specifics of which parameters are synced and gives the ability to indicate how they are interpolated, extrapolated, what their default values are (when needed for the interpolation/extrapolation settings).
Basic compression settings options for Ints and Floats appear on the second row when available. They include:
- Pack Signed - This is useful if your values typically stay reasonably close to zero but you don't actually know how high or low they can go. This is the default codec as it will always just work.
- Pack Unsigned - if you know the numbers will only be positive, this is better than PackSigned as it skips the ZigZag operation on the sign bit.
- Range - If you know the range your int will stay in, this will give the best compression. Just indicate the min and max values, and the compressor will handle the rest. Any values outside of the given range will be clamped.
- Full 32 - No compression. Don't use this.
- Half 16 - Greatly reduced accuracy from float32, but typically will be good enough for most things. This is the default float codec.
- Range - If you know the range your float will stay in, this will give the best compression. Just indicate the min and max values, and the number of bits you want to limit compression to. Any values outside of the given range will be clamped. Play with the BitsX setting to find the lowest number that gives you acceptable results. I may add some context info in the future to indicate the precision.
- Accurate Center toggle - because of the nature of bits, there will always be an even number of quantized steps to compression. Enabling Accurate Center reduces the compressed range by 1 creating an odd number of steps - thus allowing a value exactly between min and max to be reproducible after lossy compression.
By default Triggers are not synced as parameters, as they should be synced using the PassThrough methods. They are only included for completeness.