void Update() { // if server then always sync to others. if (isServer) { // just use OnSerialize via SetDirtyBit only sync when position // changed. set dirty bits 0 or 1 SetDirtyBit(HasMovedOrRotated() ? 1UL : 0UL); } // no 'else if' since host mode would be both if (isClient) { // send to server if we have local authority (and aren't the server) // -> only if connectionToServer has been initialized yet too if (!isServer && hasAuthority && connectionToServer != null) { // check only each 'syncInterval' if (Time.time - lastClientSendTime >= syncInterval) { if (HasMovedOrRotated()) { // serialize NetworkWriter writer = new NetworkWriter(); SerializeIntoWriter(writer, targetComponent.transform.position, targetComponent.transform.rotation, compressRotation); // send message to server TransformMessage message = new TransformMessage(); message.netId = netId; message.componentIndex = componentIndex; message.payload = writer.ToArray(); connectionToServer.Send((short)MsgType.LocalPlayerTransform, message); } lastClientSendTime = Time.time; } } // apply interpolation on client for all players // except for local player if he has authority and handles it himself if (!(isLocalPlayer && hasAuthority)) { // received one yet? (initialized?) if (goal != null) { // teleport or interpolate if (NeedsTeleport()) { ApplyPositionAndRotation(goal.position, goal.rotation); } else { ApplyPositionAndRotation(InterpolatePosition(start, goal, targetComponent.transform.position), InterpolateRotation(start, goal, targetComponent.transform.rotation)); } } } } }
// local authority client sends sync message to server for broadcasting // note: message is registered in NetworkServer.RegisterMessageHandlers // because internal messages can't be registered from the outside // TODO make this a [Command] later (Weaver can't weave this as long as // it's still in the same DLL) public static void OnClientToServerSync(NetworkMessage netMsg) { // read message TransformMessage message = netMsg.ReadMessage <TransformMessage>(); // find that NetworkIdentity NetworkIdentity identity; if (!NetworkIdentity.spawned.TryGetValue(message.netId, out identity)) { Debug.LogError("Received NetworkTransform data for GameObject that doesn't exist"); return; } NetworkTransformBase[] foundSyncs = identity.GetComponents <NetworkTransformBase>(); if (foundSyncs == null || foundSyncs.Length == 0 || message.componentIndex > foundSyncs.Length - 1) { Debug.LogError("HandleTransform null target"); return; } NetworkTransformBase foundSync = foundSyncs[message.componentIndex]; if (!foundSync.localPlayerAuthority) { Debug.LogError("HandleTransform no localPlayerAuthority"); return; } if (netMsg.conn.clientOwnedObjects == null) { Debug.LogError("HandleTransform object not owned by connection"); return; } if (netMsg.conn.clientOwnedObjects.Contains(message.netId)) { // deserialize payload NetworkReader reader = new NetworkReader(message.payload); foundSync.DeserializeFromReader(reader); // server-only mode does no interpolation to save computations, // but let's set the position directly if (foundSync.isServer && !foundSync.isClient) { foundSync.ApplyPositionAndRotation(foundSync.goal.position, foundSync.goal.rotation); } // set dirty so that OnSerialize broadcasts it foundSync.SetDirtyBit(1UL); } else { Debug.LogWarning("HandleTransform netId:" + message.netId + " is not for a valid player"); } }