Beispiel #1
0
 public void TestVector2()
 {
     Vector2[] inputs =
     {
         Vector2.right,
         Vector2.up,
         Vector2.zero,
         Vector2.one,
         Vector2.positiveInfinity,
         new Vector2(0.1f, 3.1f)
     };
     foreach (Vector2 input in inputs)
     {
         NetworkWriter writer = new NetworkWriter();
         writer.WriteVector2(input);
         NetworkReader reader = new NetworkReader(writer.ToArray());
         Vector2       output = reader.ReadVector2();
         Assert.That(output, Is.EqualTo(input));
     }
 }
Beispiel #2
0
 public void TestVector4()
 {
     Vector4[] inputs =
     {
         Vector3.right,
         Vector3.up,
         Vector4.zero,
         Vector4.one,
         Vector4.positiveInfinity,
         new Vector4(0.1f, 3.1f, 1.4f, 4.9f)
     };
     foreach (Vector4 input in inputs)
     {
         var writer = new NetworkWriter();
         writer.WriteVector4(input);
         var     reader = new NetworkReader(writer.ToArray());
         Vector4 output = reader.ReadVector4();
         Assert.That(output, Is.EqualTo(input));
     }
 }
Beispiel #3
0
        public void TestSetLengthZeroes()
        {
            NetworkWriter writer = new NetworkWriter();

            writer.WriteString("I saw");
            writer.WriteInt64(0xA_FADED_DEAD_EEL);
            writer.WriteString("and ate it");
            int position = writer.Position;

            writer.SetLength(10);
            // Setting length should set position too
            Assert.That(writer.Position, Is.EqualTo(10));
            // lets grow it back and check there's zeroes now.
            writer.SetLength(position);
            byte[] data = writer.ToArray();
            for (int i = position; i < data.Length; i++)
            {
                Assert.That(data[i], Is.EqualTo(0), $"index {i} should have value 0");
            }
        }
Beispiel #4
0
        public void AddPlayerMessageTest()
        {
            // try setting value with constructor
            AddPlayerMessage message = new AddPlayerMessage
            {
                value = new byte[] { 1, 2 }
            };

            // serialize
            NetworkWriter writer = new NetworkWriter();

            message.Serialize(writer);
            byte[] writerData = writer.ToArray();

            // deserialize the same data - do we get the same result?
            AddPlayerMessage fresh = new AddPlayerMessage();

            fresh.Deserialize(new NetworkReader(writerData));
            Assert.That(fresh.value, Is.EqualTo(message.value));
        }
        public void Roundtrip()
        {
            NetworkWriter w = new NetworkWriter();

            w.Write(new ChildMessage
            {
                parentValue = 3,
                childValue  = 4
            });

            byte[] arr = w.ToArray();

            NetworkReader r        = new NetworkReader(arr);
            ChildMessage  received = new ChildMessage();

            received.Deserialize(r);

            Assert.AreEqual(3, received.parentValue);
            Assert.AreEqual(4, received.childValue);
        }
Beispiel #6
0
 public void TestColor()
 {
     Color[] inputs = {
         Color.black,
         Color.blue,
         Color.cyan,
         Color.yellow,
         Color.magenta,
         Color.white,
         new Color(0.401f,0.2f,1.0f,0.123f)
     };
     foreach (Color input in inputs)
     {
         NetworkWriter writer = new NetworkWriter();
         writer.WriteColor(input);
         NetworkReader reader = new NetworkReader(writer.ToArray());
         Color output = reader.ReadColor();
         Assert.That(output, Is.EqualTo(input));
     }
 }
Beispiel #7
0
        public void ObjectHideMessageTest()
        {
            // try setting value with constructor
            ObjectHideMessage message = new ObjectHideMessage
            {
                netId = 42,
            };

            // serialize
            NetworkWriter writer = new NetworkWriter();

            message.Serialize(writer);
            byte[] writerData = writer.ToArray();

            // deserialize the same data - do we get the same result?
            ObjectHideMessage fresh = new ObjectHideMessage();

            fresh.Deserialize(new NetworkReader(writerData));
            Assert.That(fresh.netId, Is.EqualTo(message.netId));
        }
Beispiel #8
0
 public void TestVector2Int()
 {
     Vector2Int[] inputs = {
         Vector2Int.down,
         Vector2Int.up,
         Vector2Int.left,
         Vector2Int.zero,
         new Vector2Int(-1023,-999999),
         new Vector2Int(257,12345),
         new Vector2Int(0x7fffffff,-12345),
     };
     foreach (Vector2Int input in inputs)
     {
         NetworkWriter writer = new NetworkWriter();
         writer.WriteVector2Int(input);
         NetworkReader reader = new NetworkReader(writer.ToArray());
         Vector2Int output = reader.ReadVector2Int();
         Assert.That(output, Is.EqualTo(input));
     }
 }
Beispiel #9
0
 public void TestVector3()
 {
     Vector3[] inputs = {
         Vector3.right,
         Vector3.up,
         Vector3.zero,
         Vector3.one,
         Vector3.positiveInfinity,
         Vector3.forward,
         new Vector3(0.1f,3.1f,1.4f)
     };
     foreach (Vector3 input in inputs)
     {
         NetworkWriter writer = new NetworkWriter();
         writer.WriteVector3(input);
         NetworkReader reader = new NetworkReader(writer.ToArray());
         Vector3 output = reader.ReadVector3();
         Assert.That(output, Is.EqualTo(input));
     }
 }
Beispiel #10
0
        //Write the position and rotation to the data structure
        public virtual void Tick(ref RecordData data)
        {
            if (writer == null)
            {
                writer = new NetworkWriter();
            }
            else
#if ENABLE_MIRROR
            { writer.Position = 0; }
#else
            { writer.SeekZero(); }
#endif
            writer.Write(transform.position);
            writer.Write(transform.rotation);
#if ENABLE_MIRROR
            data.bytes = writer.ToArray();
#else
            data.bytes = writer.AsArray();
#endif
        }
Beispiel #11
0
        public CharData_Msg Serialize()
        {
            NetworkWriter write = new NetworkWriter();

            write.Write(index);
            write.Write(players.Count);
            for (int p = 0; p < players.Count; p++)
            {
                write.Write(players[p].nick);
                write.Write(players[p].sessionID);
                write.Write(players[p].sceneID);
                write.Write(players[p].HPMax);
            }

            CharData_Msg data = new CharData_Msg();

            data.array = write.ToArray();

            return(data);
        }
    // Send client position data every so often to those connected
    IEnumerator SendPositionCoroutine()
    {
        NetworkWriter nr = new NetworkWriter();

        while (true)
        {
            yield return(new WaitForSeconds(0.1f));

            // Anything to do?
            if (clientList.Count == 0)
            {
                continue;
            }

            // Reset stream
            nr.SeekZero();

            nr.Write((byte)PacketTypeEnum.Position);
            foreach (var item in clientList)
            {
                nr.Write(item.obj.GetInstanceID());
                nr.Write(item.obj.transform.position);

                // Don't pack too much
                // Fix me! Send more than one packet instead
                if (nr.Position > 1300)
                {
                    break;
                }
            }

            // Send data out
            byte[] buffer = nr.ToArray();
            byte   error;
            //Debug.Log(string.Format("Sending data size {0}", buffer.Length));
            foreach (var item in clientList)
            {
                NetworkTransport.Send(m_hostId, item.connectionId, reliableChannel, buffer, buffer.Length, out error);
            }
        }
    }
Beispiel #13
0
 public void TestColor32()
 {
     Color32[] inputs = new Color32[] {
         Color.black,
         Color.blue,
         Color.cyan,
         Color.yellow,
         Color.magenta,
         Color.white,
         new Color32(0xab, 0xcd, 0xef, 0x12),
         new Color32(125, 126, 0, 255)
     };
     foreach (Color32 input in inputs)
     {
         NetworkWriter writer = new NetworkWriter();
         writer.Write(input);
         NetworkReader reader = new NetworkReader(writer.ToArray());
         Color32       output = reader.ReadColor32();
         Assert.That(output, Is.EqualTo(input));
     }
 }
        public void TestOverwritingData()
        {
            NetworkWriter writer = new NetworkWriter();

            writer.WriteMatrix4x4(Matrix4x4.identity);
            writer.WriteDecimal(1.23456789m);
            writer.Position += 10;
            writer.WriteVector3(Vector3.negativeInfinity);
            writer.Position = 46;
            // write right at the boundary before SetLength
            writer.WriteInt64(0xfeed_babe_c0ffee);
            // test that SetLength clears data beyond length
            writer.SetLength(50);
            // check that jumping leaves 0s between
            writer.Position = 100;
            writer.WriteString("no worries, m8");
            writer.Position = 64;
            writer.WriteBoolean(true);
            // check that clipping off the end affect ToArray()'s length
            writer.SetLength(128);
            byte[] output = writer.ToArray();
            //Debug.Log(BitConverter.ToString(output));
            byte[] expected =
            {
                0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xEE, 0xFF, 0xC0, 0xBE,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x0F, 0x00, 0x6E, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x72, 0x69,
                0x65, 0x73, 0x2C, 0x20, 0x6D, 0x38, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            };
            Assert.That(output, Is.EqualTo(expected));
        }
Beispiel #15
0
    public void SendMessage(string targetObjectName, string methodName, object param, object param2, object param3, object param4, object param5, object param6, object param7, MsgType msgType = MsgType.Reliable)
    {
        if (debugRPC)
        {
            LogUI("CAVE2 SendMessage (Param 9)'" + methodName + "' on " + targetObjectName);
        }

        NetworkWriter writer = new NetworkWriter();

        writer.StartMessage(207);
        writer.Write(targetObjectName);
        writer.Write(methodName);
        writer.Write(7);

        ParamToByte(writer, param);
        ParamToByte(writer, param2);
        ParamToByte(writer, param3);
        ParamToByte(writer, param4);
        ParamToByte(writer, param5);
        ParamToByte(writer, param6);
        ParamToByte(writer, param7);

        writer.FinishMessage();

        ServerSendMsgToClients(writer.ToArray(), msgType);

#if USING_GETREAL3D
        if (getReal3D.Cluster.isMaster)
        {
            getReal3D.RpcManager.call("SendCAVE2RPC9", targetObjectName, methodName, param, param2, param3, param4, param5, param6, param7);
        }
        else
        {
            SendCAVE2RPC9(targetObjectName, methodName, param, param2, param3, param4, param5, param6, param7);
        }
#else
        SendCAVE2RPC9(targetObjectName, methodName, param, param2, param3, param4, param5, param6, param7);
#endif
    }
        public void TestPackedUInt32()
        {
            NetworkWriter writer = new NetworkWriter();

            writer.WritePackedUInt32(0);
            writer.WritePackedUInt32(234);
            writer.WritePackedUInt32(2284);
            writer.WritePackedUInt32(67821);
            writer.WritePackedUInt32(16777210);
            writer.WritePackedUInt32(16777219);
            writer.WritePackedUInt32(UInt32.MaxValue);

            NetworkReader reader = new NetworkReader(writer.ToArray());

            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(0));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(234));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(2284));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(67821));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(16777210));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(16777219));
            Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(UInt32.MaxValue));
        }
Beispiel #17
0
        public void NetworkPongMessageTest()
        {
            // try setting value with constructor
            NetworkPongMessage message = new NetworkPongMessage
            {
                clientTime = DateTime.Now.ToOADate(),
                serverTime = DateTime.Now.ToOADate(),
            };

            // serialize
            NetworkWriter writer = new NetworkWriter();

            message.Serialize(writer);
            byte[] writerData = writer.ToArray();

            // deserialize the same data - do we get the same result?
            NetworkPongMessage fresh = new NetworkPongMessage();

            fresh.Deserialize(new NetworkReader(writerData));
            Assert.That(fresh.clientTime, Is.EqualTo(message.clientTime));
            Assert.That(fresh.serverTime, Is.EqualTo(message.serverTime));
        }
        /// <summary>
        /// Serialize input data.
        /// </summary>
        /// <returns></returns>
        public byte[] Serialize()
        {
            if (m_InputData == null || m_InputData.Count <= 0)
            {
                return(null);
            }

            NetworkWriter writer = new NetworkWriter();

            writer.Write((short)m_InputData.Count);

            for (int i = 0; i < m_InputData.Count; i++)
            {
                InputData inputData = m_InputData[i];

                writer.WriteBytesAndSize(inputData.GetData());
            }

            m_InputData.Clear();

            return(writer.ToArray());
        }
        public void OnDeserializeSafelyShouldDetectAndHandleDeSerializationMismatch()
        {
            // create a networkidentity with our test components
            GameObject      gameObject = new GameObject();
            NetworkIdentity identity   = gameObject.AddComponent <NetworkIdentity>();
            SerializeTest1NetworkBehaviour    comp1    = gameObject.AddComponent <SerializeTest1NetworkBehaviour>();
            SerializeMismatchNetworkBehaviour compMiss = gameObject.AddComponent <SerializeMismatchNetworkBehaviour>();
            SerializeTest2NetworkBehaviour    comp2    = gameObject.AddComponent <SerializeTest2NetworkBehaviour>();

            // set some unique values to serialize
            comp1.value = 12345;
            comp2.value = "67890";

            // serialize
            NetworkWriter ownerWriter     = new NetworkWriter();
            NetworkWriter observersWriter = new NetworkWriter();

            identity.OnSerializeAllSafely(true, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten);

            // reset component values
            comp1.value = 0;
            comp2.value = null;

            // deserialize all
            NetworkReader reader = new NetworkReader(ownerWriter.ToArray());

            LogAssert.ignoreFailingMessages = true; // warning log because of serialization mismatch
            identity.OnDeserializeAllSafely(reader, true);
            LogAssert.ignoreFailingMessages = false;

            // the mismatch component will fail, but the one before and after
            // should still work fine. that's the whole point.
            Assert.That(comp1.value, Is.EqualTo(12345));
            Assert.That(comp2.value, Is.EqualTo("67890"));

            // clean up
            GameObject.DestroyImmediate(gameObject);
        }
        public void SerializeAreAddedWhenEmptyInStruct()
        {
            NetworkWriter writer = new NetworkWriter();

            const int someValue = 3;

            writer.Write(new SomeStructMessage
            {
                someValue = someValue,
            });

            byte[] arr = writer.ToArray();

            NetworkReader     reader   = new NetworkReader(arr);
            SomeStructMessage received = reader.Read <SomeStructMessage>();

            Assert.AreEqual(someValue, received.someValue);

            int writeLength = writer.Length;
            int readLength  = reader.Position;

            Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n    writeLength={writeLength}\n    readLength={readLength}");
        }
        void Update()
        {
            CheckForDirtyFsmVariables();


            if (!isServer && hasAuthority && observed != null && synchDirection == SyncDirection.ClientToServer)
            {
                CurrentStatus = Status.IsWriting;

                if (Time.realtimeSinceStartup - _lastClientToServerSynch > m_SendInterval)
                {
                    _lastClientToServerSynch = Time.realtimeSinceStartup;

                    Debug.Log("Synching from Client to Server");
                    _nw = new NetworkWriter();
                    PlayMakerUnetUtils.WriteStreamFromFsmVars(this, _nw, observed.Fsm, NetworkSynchVariableLOT, true);
                    this.Cmd_SerializeData(_nw.ToArray());
                }
            }
            else if (isServer && hasAuthority)
            {
            }
        }
Beispiel #22
0
        public void SendsVauesInParentAndChildClass()
        {
            var writer = new NetworkWriter();

            writer.Write(new ChildMessage
            {
                parentValue = 3,
                childValue  = 4
            });

            byte[] arr = writer.ToArray();

            var          reader   = new NetworkReader(arr);
            ChildMessage received = reader.Read <ChildMessage>();

            Assert.AreEqual(3, received.parentValue);
            Assert.AreEqual(4, received.childValue);

            int writeLength = writer.Length;
            int readLength  = reader.Position;

            Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n    writeLength={writeLength}\n    readLength={readLength}");
        }
Beispiel #23
0
        public void TestSynchronizingObjects()
        {
            // set up a "server" object
            var player1 = CreateBehaviour <MockPlayer>();
            var myGuild = new MockPlayer.Guild
            {
                name = "Back street boys"
            };

            player1.guild = myGuild;

            // serialize all the data as we would for the network
            player1.Identity.OnSerializeAll(true, ownerWriter, observersWriter);

            // set up a "client" object
            var player2 = CreateBehaviour <MockPlayer>();

            // apply all the data from the server object
            reader.Reset(ownerWriter.ToArray());
            player2.Identity.OnDeserializeAll(reader, true);

            // check that the syncvars got updated
            Assert.That(player2.guild.name, Is.EqualTo("Back street boys"), "Data should be synchronized");
        }
Beispiel #24
0
    public static void Send(int hostId, int connectionId, int channelId, MessageBase message, short messageType)
    {
        NetworkWriter writer = new NetworkWriter();

        writer.StartMessage(messageType);
        message.Serialize(writer);
        writer.FinishMessage();
        byte[] writerData   = writer.ToArray();
        int    bufferLength = P2PController.bufferLength;

        NetworkTransport.Send(hostId, connectionId, channelId, writerData, P2PController.bufferLength, out P2PController.error);
        P2PController.CheckError("Send");


        if (Recorder.session != null)
        {
            Recorder.session.messagesSent++;
            Recorder.session.AddLeavingBandwidth(bufferLength);
            if (channelId == P2PChannels.ReliableChannelId)
            {
                Recorder.session.importantMessagesSent++;
            }
        }
    }
Beispiel #25
0
        public void WriteUShortAfterReset()
        {
            ushort value1 = 0b0101;
            ushort value2 = 0x1000;

            // write first value
            writer.WriteUInt16(value1);

            reader.Reset(writer.ToArray());
            ushort out1 = reader.ReadUInt16();

            Assert.That(out1, Is.EqualTo(value1));

            // reset and write 2nd value
            writer.Reset();

            writer.WriteUInt16(value2);

            reader.Reset(writer.ToArray());
            ushort out2 = reader.ReadUInt16();

            Assert.That(out2, Is.EqualTo(value2), "Value 2 was incorrect");
        }
Beispiel #26
0
        public void TestResetSetsPotionAndLength()
        {
            writer.WriteString("I saw");
            writer.WriteInt64(0xA_FADED_DEAD_EEL);
            writer.WriteString("and ate it");
            writer.Reset();

            Assert.That(writer.BitPosition, Is.EqualTo(0));
            Assert.That(writer.ByteLength, Is.EqualTo(0));

            byte[] data = writer.ToArray();
            Assert.That(data, Is.Empty);
        }
    /// <summary>
    /// Using in thread
    /// </summary>
    /// <param name="obj"></param>
    static void CreateRoomsList(object obj)
    {
        Room[] rooms = (Room[])obj;

        int           w           = 0;
        NetworkWriter wr          = new NetworkWriter();
        NetworkWriter constructor = new NetworkWriter();

        byte[] buffer;

        for (int i = 0; i < rooms.Length; i++)
        {
            if (w == 10)
            {
                wr.StartMessage(Networking_msgType_Sr.RoomList);
                wr.Write(w);
                buffer = constructor.ToArray();
                foreach (byte b in buffer)
                {
                    wr.Write(b);
                }
                wr.FinishMessage();
                result.Add(wr);
                w = 0;
            }

            if (w == 0)
            {
                wr          = new NetworkWriter();
                constructor = new NetworkWriter();
            }

            if (rooms[i] != null)
            {
                if (rooms[i].maxPlayerNumber > rooms[i].playerNumber)
                {
                    Room room = rooms[i];
                    constructor.Write(i);
                    constructor.Write(room._name);
                    constructor.Write(room.mapID);
                    constructor.Write((short)room.playerNumber);
                    constructor.Write((short)room.maxPlayerNumber);
                    if (room.password)
                    {
                        constructor.Write(true);
                    }
                    else
                    {
                        constructor.Write(false);
                    }

                    w++;
                }
            }

            if (i + 1 == rooms.Length)
            {
                wr.StartMessage(Networking_msgType_Sr.RoomList);
                wr.Write(w);
                buffer = constructor.ToArray();
                foreach (byte b in buffer)
                {
                    wr.Write(b);
                }
                wr.FinishMessage();
                result.Add(wr);
            }
        }
    }
Beispiel #28
0
 byte[] MsgToByte(MessageBase msg)
 {
     _writer.SeekZero();
     _writer.Write(msg);
     return(_writer.ToArray());
 }
Beispiel #29
0
        public void MakeNextBatch_OneMessage()
        {
            // add message
            byte[] message = { 0x01, 0x02 };
            batcher.AddMessage(new ArraySegment <byte>(message));

            // make batch
            bool result = batcher.MakeNextBatch(writer);

            Assert.That(result, Is.EqualTo(true));
            Assert.That(writer.ToArray().SequenceEqual(message));
        }
Beispiel #30
0
    void Update()
    {
        // detect move mode
        bool hasPath = false;

        if (agent != null)
        {
            hasPath = HasPath();
        }

        // server should detect teleports / react if we got too far off
        // do this BEFORE isLocalPlayer actions so that agent.ResetPath can be
        // detected properly? otherwise localplayer wasdmovement cmd may
        // overwrite it
        if (isServer)
        {
            // neither click or wasd movement, but position changed further than 'speed'?
            // then we must have teleported, no other way to move this fast.
            if (entity.GetType() == typeof(Player))
            {
                // just use OnSerialize via SetDirtyBit only sync when position
                // changed. set dirty bits 0 or 1
                SetDirtyBit((uint)(HasMovedOrRotated() ? 1 : 0));

                // find out if another component modifed transform.position since
                // last time. we check it before modiying the position again.
                // -> this is necessary because the server might reset the position
                //    after respawning, but the client actually has authority over
                //    the position. we still need to be able to force it somewhere.
                if (!isLocalPlayer)
                {
                    //Debug.Log(name + " warpcheckDistance=" + Vector3.Distance(lastInternalServerPosition, transform.position)  + " / " + rubberbandDistance);
                    // != check is not good enough because precision might be lost
                    // over the network, especially when compressing. so check the
                    // distance
                    if (Vector3.Distance(lastInternalServerPosition, transform.position) > rubberbandDistance)
                    {
                        // force position on clients
                        RpcForcePosition(transform.position);

                        // reset interpolation points on server too so we don't
                        // interpolate from pre-teleport position to new one
                        start = null;
                        goal  = null;
                    }
                }
            }
            else
            {
                if (!hasPath && agent.velocity == Vector3.zero &&
                    Vector3.Distance(transform.position, lastServerPosition) > agent.speed)
                {
                    // set NetworkNavMeshAgent dirty so that onserialize is
                    // triggered and the client receives the position change
                    SetDirtyBit(1);
                    //Debug.Log(name + " teleported!");
                }

                // different destination than the one that we received from the
                // client? then set dirty so it gets synced to others
                // (epsilon comparison needed for float precision over the network)
                if (HasPath() && Vector3.Distance(agent.destination, lastReceivedDestination) > epsilon)
                {
                    // set dirty so onserialize notifies others
                    SetDirtyBit(1);
                    //Debug.Log(name + " destination changed");

                    // reset last received destination so we don't detect it again
                    // until it changes again
                    lastReceivedDestination = agent.destination;
                }

                // detect agent.Reset:
                // - had a path before but not anymore?
                // - and we never reached the planned destination even though path was canceled?
                // (epsilon comparison needed for float precision over the network)
                if (hadPath && !hasPath && Vector3.Distance(transform.position, lastReceivedDestination) > epsilon)
                {
                    // set dirty so onserialize notifies others
                    SetDirtyBit(1);
                    //Debug.Log(name + " path was reset");

                    // reset last received destination so we don't detect it again
                    // until it changes again
                    lastReceivedDestination = agent.destination;

                    // send target rpc to the local player so he doesn't ignore it
                    // -> better than a 'bool forceReset' flag for OnSerialize
                    //    because new Cmds might come in before OnSerialize was
                    //    called, which could lead to race conditions
                    // -> not in host mode (!isLocalPlayer)
                    if (!isLocalPlayer)
                    {
                        TargetResetMovement(connectionToClient);
                    }
                }

                lastServerPosition = transform.position;
                hadPath            = hasPath;
            }
        }

        // local player can move freely
        // (do nothing if in host mode though. don't want to overwrite the
        //  player's destination with Cmds here.)
        if (isClient)
        {
            if (entity.GetType() == typeof(Player))
            {
                // always send to server if we and arent the server
                // (like NetworkTransform localAuthority mode)
                // -> only if connectionToServer has been initialized yet too
                if (!isServer && isLocalPlayer && connectionToServer != null)
                {
                    // check only each 'sendinterval', otherwise we send at whatever
                    // the player's tick rate is, which is like DDOS
                    if (Time.time - lastClientSendTime >= GetNetworkSendInterval())
                    {
                        if (HasMovedOrRotated())
                        {
                            // send message to server
                            NetworkWriter writer = new NetworkWriter();
                            SerializeIntoWriter(writer, true, transform.position, transform.rotation, compressRotation, syncRotationX, syncRotationY, syncRotationZ);
                            CmdClientToServerSync(writer.ToArray());
                        }
                        lastClientSendTime = Time.time;
                    }
                }

                // apply interpolation on client for all players
                // except for local player if he has authority and handles it himself
                if (!isLocalPlayer)
                {
                    // received one yet? (initialized?)
                    if (goal != null)
                    {
                        // teleport or interpolate
                        if (NeedsTeleport())
                        {
                            SetPositionAndRotation(goal.position, goal.rotation);
                        }
                        else
                        {
                            SetPositionAndRotation(InterpolatePosition(start, goal, transform.position), InterpolateRotation(start, goal, transform.rotation));
                        }
                    }
                }
            }
            else
            {
                if (isLocalPlayer && !isServer)
                {
                    // click movement and destination changed since last sync?
                    // then send the latest DESTINATION
                    if (hasPath && agent.destination != lastSentDestination)
                    {
                        // don't send all the time to not DDOS the server
                        // note: if we check time BEFORE detecting move then moves are
                        //       detected very late and cause additional latency and
                        //       might cause move->idle->move effect if second move
                        //       doesn't come in fast enough, etc.
                        if (NetworkTime.time > lastSentTime + GetNetworkSendInterval())
                        {
                            //CmdMovedClick(agent.destination, agent.stoppingDistance);
                            lastSentDestination = agent.destination;
                            lastSentTime        = NetworkTime.time;
                        }
                    }
                    // wasd movement and velocity changed since last sync?
                    // then send the latest POSITION (not velocity)
                    // why is velocity not zero after stopping?
                    else if (!hasPath && agent.velocity != Vector3.zero && transform.position != lastSentPosition)
                    {
                        // don't send all the time to not DDOS the server
                        // note: if we check time BEFORE detecting move then moves are
                        //       detected very late and cause additional latency and
                        //       might cause move->idle->move effect if second move
                        //       doesn't come in fast enough, etc.
                        if (NetworkTime.time > lastSentTime + GetNetworkSendInterval())
                        {
                            CmdMovedWASD(transform.position, transform.rotation);
                            lastSentPosition = transform.position;
                            lastSentTime     = NetworkTime.time;
                        }
                    }
                }
            }
        }
    }