public static BitBuffer AddVector3(this BitBuffer buffer, Vector3 value, BoundedRange[] range) { var compressed = BoundedRange.Compress(value, range); buffer.AddUInt(compressed.x).AddUInt(compressed.y).AddUInt(compressed.z); return(buffer); }
/// <summary> /// Consumers the thread. /// </summary> /// <param name="arg">Argument.</param> private static void ConsumerThread(object arg) { ClientMessageReceived item; //while (true) Console.WriteLine("Queue: " + Server.QueueMessages.Count.ToString()); while (!Server.QueueMessages.IsEmpty) { bool isSuccessful = Server.QueueMessages.TryDequeue(out item); Console.WriteLine("Dequeue: " + isSuccessful); if (isSuccessful) { //https://stackoverflow.com/questions/943398/get-int-value-from-enum-in-c-sharp //https://msdn.microsoft.com/it-it/library/system.enum.getvalues(v=vs.110).aspx //http://csharp.net-informations.com/statements/enum.htm if (((byte)SendType.SENDTOALL).ToString() == item.MessageBytes.GetValue(0).ToString()) //0 { //BROADCAST (SENDTOALL) Console.WriteLine("BROADCAST (SENDTOALL)"); //Send data received to all client in List foreach (var conn in Server.clients) { if (true) { conn.Value.SendBytes(item.MessageBytes, item.SOClientConnected); Console.WriteLine("Send to: " + conn.Value.EndPoint.ToString()); } } } else if ((byte)SendType.SENDTOOTHER == (byte)item.MessageBytes.GetValue(0)) //1 { //BROADCAST (SENDTOOTHER) Console.WriteLine("BROADCAST (SENDTOOTHER)"); //Call Objects Table var col = db.GetCollection <Objects>("objects"); //Parser Message //Remove first byte (type) //https://stackoverflow.com/questions/31550484/faster-code-to-remove-first-elements-from-byte-array byte STypeBuffer = item.MessageBytes[0]; byte[] NewBufferReceiver = new byte[item.MessageBytes.Length - 1]; Array.Copy(item.MessageBytes, 1, NewBufferReceiver, 0, NewBufferReceiver.Length); //Deserialize message using NetStack //Reset bit buffer for further reusing BitBuffer data = new BitBuffer(1024); data.FromArray(NewBufferReceiver, NewBufferReceiver.Length); byte TypeBuffer = data.ReadByte(); string OwnerPlayer = data.ReadString(); bool isKine = data.ReadBool(); uint IDObject = data.ReadUInt(); CompressedVector3 position = new CompressedVector3(data.ReadUInt(), data.ReadUInt(), data.ReadUInt()); CompressedQuaternion rotation = new CompressedQuaternion(data.ReadByte(), data.ReadShort(), data.ReadShort(), data.ReadShort()); // Read Vector3 Compress Velocity //ushort compressedVelocityX = HalfPrecision.Compress(speed); Vector3 VelocityReceived = new Vector3(HalfPrecision.Decompress(data.ReadUShort()), HalfPrecision.Decompress(data.ReadUShort()), HalfPrecision.Decompress(data.ReadUShort())); //Read Float InterpolationTime float InterpolationTime = HalfPrecision.Decompress(data.ReadUShort()); // Check if bit buffer is fully unloaded Console.WriteLine("Bit buffer is empty: " + data.IsFinished); //Decompress Vector and Quaternion //Create a new BoundedRange array for Vector3 position, each entry has bounds and precision BoundedRange[] worldBounds = new BoundedRange[3]; worldBounds[0] = new BoundedRange(-50f, 50f, 0.05f); // X axis worldBounds[1] = new BoundedRange(0f, 25f, 0.05f); // Y axis worldBounds[2] = new BoundedRange(-50f, 50f, 0.05f); // Z axis //Decompress position data Vector3 decompressedPosition = BoundedRange.Decompress(position, worldBounds); // Decompress rotation data Quaternion decompressedRotation = SmallestThree.Decompress(rotation); if (Server.DEBUG) { Console.WriteLine("RECEIVED DATA: "); Console.WriteLine("TYPE RECEIVED: " + TypeBuffer.ToString()); Console.WriteLine("IDObject RECEIVED: " + IDObject.ToString()); Console.WriteLine("UID RECEIVED: " + OwnerPlayer); Console.WriteLine("isKinematic RECEIVED: " + isKine.ToString()); Console.WriteLine("POS RECEIVED: " + decompressedPosition.X.ToString() + ", " + decompressedPosition.Y.ToString() + ", " + decompressedPosition.Z.ToString()); Console.WriteLine("ROT RECEIVED: " + decompressedRotation.X.ToString() + ", " + decompressedRotation.Y.ToString() + ", " + decompressedRotation.Z.ToString() + ", " + decompressedRotation.W.ToString()); Console.WriteLine("PosX: " + decompressedPosition.X); Console.WriteLine("PosY: " + decompressedPosition.Y); Console.WriteLine("PosZ: " + decompressedPosition.Z); Console.WriteLine("VEL RECEIVED: " + VelocityReceived.X.ToString() + ", " + VelocityReceived.Y.ToString() + ", " + VelocityReceived.Z.ToString()); Console.WriteLine("INTERPOLATION TIME: " + InterpolationTime.ToString()); //var ReceiveMessageFromGameObjectBuffer = new ReceiveMessageFromGameObject(); //NOT USED! } //Check if ObjectReceived.ID <> 0 if (IDObject != 0) { var MVobject = new Objects { IDObject = (int)IDObject, isKine = isKine, PosX = decompressedPosition.X, PosY = decompressedPosition.Y, PosZ = decompressedPosition.Z, RotX = decompressedRotation.X, RotY = decompressedRotation.Y, RotZ = decompressedRotation.Z, RotW = decompressedRotation.W, UID = IDObject.ToString() + ";" + OwnerPlayer }; //Debug Console.WriteLine("MVobject PosX: " + MVobject.PosX); Console.WriteLine("MVobject PosY: " + MVobject.PosY); Console.WriteLine("MVobject PosZ: " + MVobject.PosZ); if ((byte)PacketId.OBJECT_SPAWN == TypeBuffer) { // Insert new customer document (Id will be auto-incremented) col.Insert(MVobject); // Create unique index in Name field col.EnsureIndex(x => x.UID, true); Console.WriteLine("OBJECT SPAWN SAVED"); } else if ((byte)PacketId.OBJECT_MOVE == TypeBuffer) { //Check if record exist if (col.Count(Query.EQ("UID", IDObject.ToString() + ";" + OwnerPlayer)) == 1) { //Search and update // Now, search for document your document var ObjectsFinded = col.FindOne(x => x.UID == IDObject.ToString() + ";" + OwnerPlayer); //Update data ObjectsFinded.isKine = isKine; ObjectsFinded.PosX = decompressedPosition.X; ObjectsFinded.PosY = decompressedPosition.Y; ObjectsFinded.PosZ = decompressedPosition.Z; ObjectsFinded.RotX = decompressedRotation.X; ObjectsFinded.RotY = decompressedRotation.Y; ObjectsFinded.RotZ = decompressedRotation.Z; ObjectsFinded.RotW = decompressedRotation.W; //Save data to Objects DB if (col.Update(ObjectsFinded)) { Console.WriteLine("UPDATE OBJECT IN DB"); } else { Console.WriteLine("*NOT* UPDATED OBJECT IN DB"); } } else { col.Insert(MVobject); //Insert data to Objects DB col.EnsureIndex(x => x.UID, true); //Create unique index in Name field Console.WriteLine("INSERT OBJECT IN DB"); } Console.WriteLine("OBJECT MOVE"); } else if ((byte)PacketId.OBJECT_UNSPAWN == TypeBuffer) { if (col.Count(Query.EQ("UID", IDObject.ToString() + ";" + OwnerPlayer)) == 1) { col.Delete(Query.EQ("UID", IDObject.ToString() + ";" + OwnerPlayer)); //Save data to Objects DB Console.WriteLine("DELETE OBJECT FROM DB"); } else { Console.WriteLine("OBJECT UNSPAWN NOT IN DB");; } Console.WriteLine("OBJECT UNSPAWN"); } } // END Check ObjectReceived.ID <> 0 //Send data received to all other client in List Console.WriteLine("SEND MESSAGE TO OTHER CLIENTS"); foreach (var conn in Server.clients) { if (conn.Value != item.ClientConnected) //SENDTOOTHER { conn.Value.SendBytes(item.MessageBytes, item.SOClientConnected); Console.WriteLine("Send to: " + conn.Value.EndPoint.ToString()); } } } else if ((byte)SendType.SENDTOSERVER == (byte)item.MessageBytes.GetValue(0)) //2 { //FOR NOW ECHO SERVER (SENDTOSERVER) Console.WriteLine("CLIENT TO SERVER (SENDTOSERVER)"); //Parser Message //Remove first byte (type) //https://stackoverflow.com/questions/31550484/faster-code-to-remove-first-elements-from-byte-array byte STypeBuffer = item.MessageBytes[0]; byte[] NewBufferReceiver = new byte[item.MessageBytes.Length - 1]; Array.Copy(item.MessageBytes, 1, NewBufferReceiver, 0, NewBufferReceiver.Length); //Deserialize message using NetStack //Reset bit buffer for further reusing BitBuffer data = new BitBuffer(1024); data.FromArray(NewBufferReceiver, NewBufferReceiver.Length); byte CommandTypeBuffer = data.ReadByte(); string Answer = data.ReadString(); // Check if bit buffer is fully unloaded Console.WriteLine("Bit buffer is empty: " + data.IsFinished); String UIDBuffer = String.Empty; if (STypeBuffer == 2) { if ((sbyte)CommandType.LOGIN == CommandTypeBuffer) { //Cerca e restituisci il tutto foreach (var conn in Server.clients) { if (conn.Value == item.ClientConnected) //SENDTOSERVER { //DONE: Check here if user exist and password correct //Get users collection var col = db.GetCollection <Users>("users"); Console.WriteLine("COMMAND RECEIVED: " + Answer); //Parse HMessageReceived string[] words = Answer.Split(';'); //words[0] = Login; words[1] = Password if (col.Count(Query.EQ("UserName", words[0])) == 1) { var results = col.Find(Query.EQ("UserName", words[0])); string UserPasswordRecord = string.Empty; foreach (var c in results) { Console.WriteLine("#{0} - {1}", c.Id, c.UserName); UserPasswordRecord = c.UserPassword; } //Verify password ScryptEncoder encoder = new ScryptEncoder(); //Check password if (encoder.Compare(words[1], UserPasswordRecord)) { //OK UIDBuffer = conn.Key; Console.WriteLine("UID: " + UIDBuffer); } else { //*NOT* OK UIDBuffer = string.Empty; Console.WriteLine("UID: ERROR PASSWORD" + UIDBuffer); } } else { UIDBuffer = string.Empty; Console.WriteLine("UID: USER NOT EXISTS!" + UIDBuffer); } } } } } //Reset bit buffer for further reusing data.Clear(); data.AddByte((byte)CommandType.LOGIN) .AddString(UIDBuffer); byte[] BufferNetStack = new byte[data.Length]; data.ToArray(BufferNetStack); data.Clear(); //SEND MESSAGE // Add type! //https://stackoverflow.com/questions/5591329/c-sharp-how-to-add-byte-to-byte-array byte[] newArray = new byte[BufferNetStack.Length + 1]; BufferNetStack.CopyTo(newArray, 1); newArray[0] = (byte)SendType.SENDTOSERVER; item.ClientConnected.SendBytes(newArray, item.SOClientConnected); if (DEBUG) { Console.WriteLine("Data Lenghts: " + newArray.Length.ToString()); Console.WriteLine("Data Lenghts NetStack: " + BufferNetStack.Length.ToString()); Console.WriteLine("Data Lenghts BitBuffer: " + data.Length.ToString()); Console.WriteLine("Message sent!"); } Console.WriteLine("Send to: " + item.ClientConnected.EndPoint.ToString()); //HERE SEND TO ALL CLIENTS OBJECTS DB //DONE: Add code to send all clients Console.WriteLine("SEND ALL OBJECTS TO CLIENT"); //Call Objects Table var col_objects = db.GetCollection <Objects>("objects"); //Recovers all objects in the table var results_objects = col_objects.Find(Query.GT("_id", 0)); //Foreach send them to the client connected foreach (var o in results_objects) { Console.WriteLine("SEND IDOBJECT: " + o.IDObject.ToString()); //SEND USING NETSTACK SERIALIZATION // Create a new BoundedRange array for Vector3 position, each entry has bounds and precision BoundedRange[] worldBounds = new BoundedRange[3]; worldBounds[0] = new BoundedRange(-50f, 50f, 0.05f); // X axis worldBounds[1] = new BoundedRange(0f, 25f, 0.05f); // Y axis worldBounds[2] = new BoundedRange(-50f, 50f, 0.05f); // Z axis //Convert from HazelUDPTestClient.Vector3 at System.Numerics.Vector3 System.Numerics.Vector3 InternalPos = new System.Numerics.Vector3(o.PosX, o.PosY, o.PosZ); //Compress position data CompressedVector3 compressedPosition = BoundedRange.Compress(InternalPos, worldBounds); // Read compressed data Console.WriteLine("Compressed position - X: " + compressedPosition.x + ", Y:" + compressedPosition.y + ", Z:" + compressedPosition.z); //Convert from HazelUDPTestClient.Quaternion at System.Numerics.Quaternion System.Numerics.Quaternion InternalRot = new System.Numerics.Quaternion(o.RotX, o.RotY, o.RotZ, o.RotW); // Compress rotation data CompressedQuaternion compressedRotation = SmallestThree.Compress(InternalRot); // Read compressed data Console.WriteLine("Compressed rotation - M: " + compressedRotation.m + ", A:" + compressedRotation.a + ", B:" + compressedRotation.b + ", C:" + compressedRotation.c); //Add Velocity Vector (0,0,0) Vector3 velocity = Vector3.Zero; //Add and compress Interporlation Time ushort compressedTimeInterpolation = HalfPrecision.Compress(0f); //Reset bit buffer for further reusing data.Clear(); //Serialization data.AddByte((byte)PacketId.OBJECT_MOVE) .AddString(o.UID.Split(';')[1]) //OwnerPlayer .AddBool(o.isKine) .AddUInt((uint)o.IDObject) .AddUInt(compressedPosition.x) .AddUInt(compressedPosition.y) .AddUInt(compressedPosition.z) .AddByte(compressedRotation.m) .AddShort(compressedRotation.a) .AddShort(compressedRotation.b) .AddShort(compressedRotation.c) //Add dummy date (0,0,0) .AddUShort(HalfPrecision.Compress(velocity.X)) .AddUShort(HalfPrecision.Compress(velocity.Y)) .AddUShort(HalfPrecision.Compress(velocity.Z)) .AddUShort(compressedTimeInterpolation); Console.WriteLine("BitBuffer: " + data.Length.ToString()); byte[] BufferNetStackObject = new byte[data.Length]; data.ToArray(BufferNetStackObject); data.Clear(); //https://discordapp.com/channels/515987760281288707/515987760281288711/527744788745814028 //MA soprattutto: https://discordapp.com/channels/515987760281288707/515987760281288711/536428267851350017 //Okay guys, after some debugging I've found the mistake in the original BitBuffer implementation, //Alex forgot to check index boundaries during conversion so this is why + 4 bytes was required for shifting. //Now it's fixed and no longer needed I hope //https://github.com/nxrighthere/NetStack/commit/f381a88751fa0cb72af2cad7652a973d570d3dda //SEND MESSAGE // Add type! //https://stackoverflow.com/questions/5591329/c-sharp-how-to-add-byte-to-byte-array byte[] newArrayObject = new byte[BufferNetStackObject.Length + 1]; //Create +1 NewArrayObject BufferNetStackObject.CopyTo(newArrayObject, 1); //Coping start from position 1 (NOT 0) newArrayObject[0] = (byte)SendType.SENDTOOTHER; //Coping position 0 byte SendType item.ClientConnected.SendBytes(newArrayObject, item.SOClientConnected); //Send new packet if (DEBUG) { Console.WriteLine("Data Lenghts: " + newArray.Length.ToString()); Console.WriteLine("Data Lenghts NetStack: " + BufferNetStack.Length.ToString()); Console.WriteLine("Message sent!"); } } } } } }
/// <summary> /// Sends the message. /// </summary> /// <param name="SType">SType.</param> /// <param name="Type">Type.</param> /// <param name="IDObject">IDObject.</param> /// <param name="OwnerPlayer">Owner player.</param> /// <param name="isKine">If set to <c>true</c> is kinematic.</param> /// <param name="Pos">Position.</param> /// <param name="Rot">Rotation.</param> public static void SendMessage(SendType SType, PacketId Type, ushort IDObject, string OwnerPlayer, bool isKine, Vector3 Pos, Quaternion Rot) { sbyte TypeBuffer = 0; byte STypeBuffer = 0; //Choose who to send message switch (SType) { case SendType.SENDTOALL: STypeBuffer = 0; break; case SendType.SENDTOOTHER: STypeBuffer = 1; break; case SendType.SENDTOSERVER: STypeBuffer = 2; break; default: STypeBuffer = 0; break; } //Console.WriteLine("SENDTYPE SENT: " + STypeBuffer); //DEBUG //Choose type message (TO Modify) switch (Type) { case PacketId.PLAYER_JOIN: TypeBuffer = 0; break; case PacketId.OBJECT_MOVE: TypeBuffer = 1; break; case PacketId.PLAYER_SPAWN: TypeBuffer = 2; break; case PacketId.OBJECT_SPAWN: TypeBuffer = 3; break; case PacketId.PLAYER_MOVE: TypeBuffer = 4; break; case PacketId.MESSAGE_SERVER: TypeBuffer = 5; break; default: TypeBuffer = 1; break; } //Debug.Log("TYPE SENT: " + TypeBuffer); //DEBUG // Create flatbuffer class FlatBufferBuilder fbb = new FlatBufferBuilder(1); StringOffset SOUIDBuffer = fbb.CreateString(OwnerPlayer); HazelTest.Object.StartObject(fbb); HazelTest.Object.AddType(fbb, TypeBuffer); HazelTest.Object.AddOwner(fbb, SOUIDBuffer); HazelTest.Object.AddIsKine(fbb, isKine); HazelTest.Object.AddID(fbb, IDObject); HazelTest.Object.AddPos(fbb, Vec3.CreateVec3(fbb, Pos.X, Pos.Y, Pos.Z)); HazelTest.Object.AddRot(fbb, Vec4.CreateVec4(fbb, Rot.X, Rot.Y, Rot.Z, Rot.W)); if (DEBUG) { Console.WriteLine("ID SENT: " + IDObject.ToString()); Console.WriteLine("TYPE SENT: " + TypeBuffer.ToString()); Console.WriteLine("UID SENT: " + OwnerPlayer); Console.WriteLine("IsKINE SENT: " + isKine.ToString()); Console.WriteLine("POS SENT: " + Pos.X.ToString() + ", " + Pos.Y.ToString() + ", " + Pos.Z.ToString()); Console.WriteLine("ROT SENT: " + Rot.X.ToString() + ", " + Rot.Y.ToString() + ", " + Rot.Z.ToString() + ", " + Rot.W.ToString()); } var offset = HazelTest.Object.EndObject(fbb); HazelTest.Object.FinishObjectBuffer(fbb, offset); using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset)) { //Add type! //https://stackoverflow.com/questions/5591329/c-sharp-how-to-add-byte-to-byte-array byte[] newArray = new byte[ms.ToArray().Length + 1]; ms.ToArray().CopyTo(newArray, 1); newArray[0] = STypeBuffer; connection.SendBytes(newArray, SendOption.None); //WARNING: ALL MESSAGES ARE NOT RELIABLE! if (DEBUG) { Console.WriteLine("Data Lenghts: " + newArray.Length.ToString()); Console.WriteLine("Message sent!"); } } //Add example in NetStack // Create a new BoundedRange array for Vector3 position, each entry has bounds and precision BoundedRange[] worldBounds = new BoundedRange[3]; worldBounds[0] = new BoundedRange(-50f, 50f, 0.05f); // X axis worldBounds[1] = new BoundedRange(0f, 25f, 0.05f); // Y axis worldBounds[2] = new BoundedRange(-50f, 50f, 0.05f); // Z axis //Convert from HazelUDPTestClient.Vector3 at System.Numerics.Vector3 System.Numerics.Vector3 InternalPos = new System.Numerics.Vector3(Pos.X, Pos.Y, Pos.Z); //Compress position data CompressedVector3 compressedPosition = BoundedRange.Compress(InternalPos, worldBounds); // Read compressed data Console.WriteLine("Compressed position - X: " + compressedPosition.x + ", Y:" + compressedPosition.y + ", Z:" + compressedPosition.z); //Convert from HazelUDPTestClient.Quaternion at System.Numerics.Quaternion System.Numerics.Quaternion InternalRot = new System.Numerics.Quaternion(Rot.X, Rot.Y, Rot.Z, Rot.W); // Compress rotation data CompressedQuaternion compressedRotation = SmallestThree.Compress(InternalRot); // Read compressed data Console.WriteLine("Compressed rotation - M: " + compressedRotation.m + ", A:" + compressedRotation.a + ", B:" + compressedRotation.b + ", C:" + compressedRotation.c); // Create a new bit buffer with 128 chunks BitBuffer data = new BitBuffer(128); data.AddByte((byte)TypeBuffer) .AddString(OwnerPlayer) .AddBool(isKine) .AddUInt(IDObject) .AddUInt(compressedPosition.x) .AddUInt(compressedPosition.y) .AddUInt(compressedPosition.z) .AddByte(compressedRotation.m) .AddInt(compressedRotation.a) .AddInt(compressedRotation.b) .AddInt(compressedRotation.c); Console.WriteLine("BitBuffer: " + data.Length.ToString()); //byte[] BufferNetStack = new byte[data.Length+1]; byte[] BufferNetStack = new byte[data.Length + 3]; data.ToArray(BufferNetStack); if (DEBUG) { Console.WriteLine("Data Lenghts NetStack: " + BufferNetStack.Length.ToString()); PrintByteArray(BufferNetStack); Console.WriteLine("Message sent!"); } }
/// <summary> /// Sends the message. /// </summary> /// <param name="SType">ST ype.</param> /// <param name="Type">Type.</param> /// <param name="IDObject">IDO bject.</param> /// <param name="OwnerPlayer">Owner player.</param> /// <param name="isKine">If set to <c>true</c> is kine.</param> /// <param name="Pos">Position.</param> /// <param name="Rot">Rot.</param> public static void SendMessage(SendType SType, PacketId Type, ushort IDObject, string OwnerPlayer, bool isKine, Vector3 Pos, Quaternion Rot, Vector3 Vel, float InterTime) { byte TypeBuffer = 0; byte STypeBuffer = 0; //Choose who to send message switch (SType) { case SendType.SENDTOALL: STypeBuffer = 0; break; case SendType.SENDTOOTHER: STypeBuffer = 1; break; case SendType.SENDTOSERVER: STypeBuffer = 2; break; default: STypeBuffer = 0; break; } //Console.WriteLine("SENDTYPE SENT: " + STypeBuffer); //DEBUG //Choose type message (TO Modify) switch (Type) { case PacketId.PLAYER_JOIN: TypeBuffer = 0; break; case PacketId.OBJECT_MOVE: TypeBuffer = 1; break; case PacketId.PLAYER_SPAWN: TypeBuffer = 2; break; case PacketId.OBJECT_SPAWN: TypeBuffer = 3; break; case PacketId.PLAYER_MOVE: TypeBuffer = 4; break; case PacketId.MESSAGE_SERVER: TypeBuffer = 5; break; default: TypeBuffer = 1; break; } //Debug.Log("TYPE SENT: " + TypeBuffer); //DEBUG //SEND USING NETSTACK SERIALIZATION // Create a new BoundedRange array for Vector3 position, each entry has bounds and precision BoundedRange[] worldBounds = new BoundedRange[3]; worldBounds[0] = new BoundedRange(-50f, 50f, 0.05f); // X axis worldBounds[1] = new BoundedRange(0f, 25f, 0.05f); // Y axis worldBounds[2] = new BoundedRange(-50f, 50f, 0.05f); // Z axis //Convert from HazelUDPTestClient.Vector3 at System.Numerics.Vector3 System.Numerics.Vector3 InternalPos = new System.Numerics.Vector3(Pos.X, Pos.Y, Pos.Z); //Compress position data CompressedVector3 compressedPosition = BoundedRange.Compress(InternalPos, worldBounds); // Read compressed data Console.WriteLine("Compressed position - X: " + compressedPosition.x + ", Y:" + compressedPosition.y + ", Z:" + compressedPosition.z); //Convert from HazelUDPTestClient.Quaternion at System.Numerics.Quaternion System.Numerics.Quaternion InternalRot = new System.Numerics.Quaternion(Rot.X, Rot.Y, Rot.Z, Rot.W); //Compress rotation data CompressedQuaternion compressedRotation = SmallestThree.Compress(InternalRot); //Read compressed data Console.WriteLine("Compressed rotation - M: " + compressedRotation.m + ", A:" + compressedRotation.a + ", B:" + compressedRotation.b + ", C:" + compressedRotation.c); //Add and compress Vector3 Velocity ushort compressedVelocityX = HalfPrecision.Compress(Vel.X); ushort compressedVelocityY = HalfPrecision.Compress(Vel.Y); ushort compressedVelocityZ = HalfPrecision.Compress(Vel.Z); //Add and compress Interporlation Time ushort compressedTimeInterpolation = HalfPrecision.Compress(InterTime); //Reset bit buffer for further reusing data.Clear(); data.AddByte((byte)TypeBuffer) .AddString(OwnerPlayer) .AddBool(isKine) .AddUInt(IDObject) .AddUInt(compressedPosition.x) .AddUInt(compressedPosition.y) .AddUInt(compressedPosition.z) .AddByte(compressedRotation.m) .AddInt(compressedRotation.a) .AddInt(compressedRotation.b) .AddInt(compressedRotation.c) .AddUShort(compressedVelocityX) .AddUShort(compressedVelocityY) .AddUShort(compressedVelocityZ) .AddUShort(compressedTimeInterpolation); Console.WriteLine("BitBuffer: " + data.Length.ToString()); //byte[] BufferNetStack = new byte[data.Length+1]; //https://discordapp.com/channels/515987760281288707/515987760281288711/527744788745814028 //MA soprattutto: https://discordapp.com/channels/515987760281288707/515987760281288711/536428267851350017 //Okay guys, after some debugging I've found the mistake in the original BitBuffer implementation, //Alex forgot to check index boundaries during conversion so this is why + 4 bytes was required for shifting. //Now it's fixed and no longer needed I hope //https://github.com/nxrighthere/NetStack/commit/f381a88751fa0cb72af2cad7652a973d570d3dda byte[] BufferNetStack = new byte[data.Length]; data.ToArray(BufferNetStack); //SEND MESSAGE // Add type! //https://stackoverflow.com/questions/5591329/c-sharp-how-to-add-byte-to-byte-array byte[] newArray = new byte[BufferNetStack.Length + 1]; BufferNetStack.CopyTo(newArray, 1); newArray[0] = STypeBuffer; connection.SendBytes(newArray, SendOption.None); //WARNING: ALL MESSAGES ARE NOT RELIABLE! if (DEBUG) { Console.WriteLine("Data Lenghts: " + newArray.Length.ToString()); Console.WriteLine("Data Lenghts NetStack: " + BufferNetStack.Length.ToString()); PrintByteArray(BufferNetStack); Console.WriteLine("Message sent!"); } }