void LateUpdate() { _ws.ProcessMessageQueue(this); if (_ws.ConnectionState == ClientState.Connected) { if (Time.time - _timeSinceLastSend > SendInterval) { _timeSinceLastSend = Time.time; QuantizedVector3 qPosition = BoundedRange.Quantize(_modelTransform.position, Constants.WORLD_BOUNDS); QuantizedQuaternion qRotation = SmallestThree.Quantize(_modelTransform.rotation); ushort qBestTime = HalfPrecision.Quantize(GameTimer.BestTime); _bitBuffer.Clear(); _bitBuffer.AddUInt(qPosition.x) .AddUInt(qPosition.y) .AddUInt(qPosition.z) .AddUInt(qRotation.m) .AddUInt(qRotation.a) .AddUInt(qRotation.b) .AddUInt(qRotation.c) .AddUShort(qBestTime) .ToArray(_byteBuffer); _ws.Send(new ArraySegment <byte>(_byteBuffer, 0, 28)); } } }
private void LateUpdate() { _webClient.ProcessMessageQueue(this); if (_webClient.ConnectionState == ClientState.Connected && Time.time >= _timeToSendNextUpdate) { _timeToSendNextUpdate = Time.time + (1f / Constants.CLIENT_TICKRATE); // GUARD, DONT SEND POSITION IF WE DIDN'T MOVE if (!_overrideDirtySendRule && (_previousPlayerPosition - LocalPlayerTransform.position).magnitude < 0.1f) { return; } // Send our position to server _bitBuffer.Clear(); _bitBuffer.AddByte(1); QuantizedVector3 qPosition = BoundedRange.Quantize(LocalPlayerTransform.position, Constants.WORLD_BOUNDS); _bitBuffer.AddUInt(qPosition.x); _bitBuffer.AddUInt(qPosition.y); _bitBuffer.ToArray(_buffer); _webClient.Send(new ArraySegment <byte>(_buffer, 0, 9)); _previousPlayerPosition = LocalPlayerTransform.position; _overrideDirtySendRule = false; } }
public bool TryParse(string input, out BoundedRange <T> result) { result = null; if (string.IsNullOrWhiteSpace(input)) { return(false); } Match match = regex.Match(input); if (!match.Success) { return(false); } string minValueCapture = match.Groups[MinValueGroupName].Value; string maxValueCapture = match.Groups[MaxValueGroupName].Value; T minValue, maxValue; if (!valueParser.TryParse(minValueCapture, out minValue) || !valueParser.TryParse(maxValueCapture, out maxValue)) { return(false); } result = new BoundedRange <T>(minValue, maxValue); return(true); }
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); }
public void New_PassZeroAsMinAndMaxValues_ShouldThrowBusinessRuleValidationException() { Assert.ThrowsException <BusinessRuleValidationException>(() => { var range = new BoundedRange <int>(0, BoundType.Exclude, 0, BoundType.Include); }); }
public void IsInRange_PassUpperLimit_ShouldReturnTrue() { var range = new BoundedRange <int>(0, BoundType.Exclude, 10, BoundType.Include); bool inRange = range.IsValueInRange(10); Assert.IsTrue(inRange); }
public void IsInRange_() { var range = new BoundedRange <int>(0, BoundType.Exclude, 10, BoundType.Include); bool inRange = range.IsValueInRange(5); Assert.IsTrue(inRange); }
public static Vector3 ReadVector3(this BitBuffer buffer, BoundedRange[] range) { var compressed = new CompressedVector3( buffer.ReadUInt(), buffer.ReadUInt(), buffer.ReadUInt()); return(BoundedRange.Decompress(compressed, range)); }
static CommandCompressors() { ClientCreateBeePositionXCompressor = new BoundedRange(-100, 100, 0.0001f); ClientCreateBeePositionYCompressor = new BoundedRange(-100, 100, 0.0001f); ClientCreateBeePositionZCompressor = new BoundedRange(-100, 100, 0.0001f); ClientCreateBeeDirectionCompressor = new BoundedRange(0, 360, 1f); ClientTestValueXCompressor = new BoundedRange(-1, 1, 0.01f); ClientTestValueYCompressor = new BoundedRange(-1, 1, 0.01f); ClientTestValueZCompressor = new BoundedRange(-1, -1, 0.01f); ServerTestValueXCompressor = new BoundedRange(-1, 1, 0.01f); ServerTestValueYCompressor = new BoundedRange(-1, 1, 0.01f); ServerTestValueZCompressor = new BoundedRange(-1, -1, 0.01f); }
public void New_Pass0AsLowerAnd10AsUpper_ShouldReturnNewInstance2() { var range = new BoundedRange <int>(new Bound <int>(0, BoundType.Exclude), new Bound <int>(10, BoundType.Include)); Assert.IsNotNull(range); }
private void WsOnonData(ArraySegment <byte> obj) { _bitBuffer.Clear(); _bitBuffer.FromArray(obj.Array, obj.Count); ushort messageId = _bitBuffer.ReadUShort(); switch (messageId) { case 0: { ushort id = _bitBuffer.ReadUShort(); if (_ghostCars.ContainsKey(id)) { Destroy(_ghostCars[id].gameObject); _ghostCars.Remove(id); } break; } case 1: { ushort count = _bitBuffer.ReadUShort(); for (int i = 0; i < count; i++) { ushort id = _bitBuffer.ReadUShort(); QuantizedVector3 qPosition = new QuantizedVector3(_bitBuffer.ReadUInt(), _bitBuffer.ReadUInt(), _bitBuffer.ReadUInt()); QuantizedQuaternion qRotation = new QuantizedQuaternion(_bitBuffer.ReadUInt(), _bitBuffer.ReadUInt(), _bitBuffer.ReadUInt(), _bitBuffer.ReadUInt()); ushort qBestTime = _bitBuffer.ReadUShort(); // Ignore it if it is the transform for my own car if (_myId == id || id == 0) { continue; } Vector3 postion = BoundedRange.Dequantize(qPosition, Constants.WORLD_BOUNDS); Quaternion rotation = SmallestThree.Dequantize(qRotation); if (!_ghostCars.ContainsKey(id)) { GameObject newCar = Instantiate(GhostCarPrefab, postion, rotation); _ghostCars[id] = newCar.GetComponent <GhostCarBehavior>(); } else { _ghostCars[id].UpdateTransform(postion, rotation); float bestTime = HalfPrecision.Dequantize(qBestTime); _ghostCars[id].UpdatebestTime(bestTime); } } break; } case 2: { ushort id = _bitBuffer.ReadUShort(); _myId = id; break; } } }
/// <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!"); } }
private AgeCategory(string name, BoundedRange <PersonAge> ageRange) { Name = name; AgeRange = ageRange; }
private static void DeleteYesterdaysEvents() { Console.WriteLine("Deleting yesterday's events"); DateTime yesterday = DateTime.Today.AddDays(-1); BoundedRange<Event> boundedRange = new BoundedRange<Event>("StartTime", e => e.StartTime, yesterday, DateTime.Today.AddMilliseconds(-1)); foreach (var e in repo.IterateOver<Event>(boundedRange)) repo.Delete(e); ScanYesterdaysEvents(); ScanEvents(); }
private static void DeleteTodaysEvents() { Console.WriteLine("Deleting today's events"); DateTime today = DateTime.Today; BoundedRange<Event> boundedRange = new BoundedRange<Event>("StartTime", e => e.StartTime, today, today.AddDays(1)); foreach (var e in repo.IterateOver<Event>(boundedRange)) repo.Delete(e); ScanTodaysEvents(); ScanEvents(); }
/// <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> /// Start this instance. /// </summary> public void Start() { //Set range for compression Range[0] = new BoundedRange(-RandomRange, RandomRange, 0.05f); Range[1] = new BoundedRange(-RandomRange, RandomRange, 0.05f); Range[2] = new BoundedRange(-RandomRange, RandomRange, 0.05f); //Create Akka actors system Console.WriteLine("Creating Actor System"); ActorSystem system = ActorSystem.Create("MyActorSystem"); Library.Initialize(); using (Host server = new Host()) { ENETCSharp.Address address = new ENETCSharp.Address(); Console.WriteLine("Server started!"); address.Port = portNumber; // 10 Channels // 10 Peers server.Create(address, 10, 10); Event netEvent; //Creating Actors Console.WriteLine("Creating Actors "); IActorRef ENETEventUntypedActor = system.ActorOf <ENETUntypedActor>("ENETEventUntypedActor"); while (!Console.KeyAvailable) { server.Service(0, out netEvent); switch (netEvent.Type) { case EventType.None: break; case EventType.Connect: Console.WriteLine("Client connected - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP); //Add Peer connected to General List AddClientPeer(netEvent.Peer, netEvent.Peer.ID); Console.WriteLine($"Numbers Peer(s): {server.PeersCount.ToString()}"); SendToSingleClient(CreateAnswerPacketLogin("OK", netEvent.Peer.ID), netEvent.Peer.ID); break; case EventType.Disconnect: Console.WriteLine("Client disconnected - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP); //Remove Peer disconnected / Timeouted to General List RemoveClientPeer(netEvent.Peer, netEvent.Peer.ID); Console.WriteLine($"Numbers Peer(s): {server.PeersCount.ToString()}"); break; case EventType.Timeout: Console.WriteLine("Client timeout - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP); //Remove Peer disconnected / Timeouted to General List RemoveClientPeer(netEvent.Peer, netEvent.Peer.ID); Console.WriteLine($"Numbers Peer(s): {server.PeersCount.ToString()}"); break; case EventType.Receive: Console.WriteLine("Packet received from - ID: " + netEvent.Peer.ID + ", IP: " + netEvent.Peer.IP + ", Channel ID: " + netEvent.ChannelID + ", Data length: " + netEvent.Packet.Length); //Process packet received! //ProcessPacket(netEvent); ENETEventUntypedActor.Tell(netEvent); //netEvent.Packet.Dispose(); break; } } server.Flush(); server.Dispose(); Library.Deinitialize(); //Exit 0 Environment.Exit(0); } }
/// <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!"); } } } } } }
private void WebClientOnonData(ArraySegment <byte> data) { _bitBuffer.Clear(); _bitBuffer.FromArray(data.Array, data.Count); byte messageId = _bitBuffer.ReadByte(); switch (messageId) { case 2: { _myId = _bitBuffer.ReadUShort(); // Put my name into _names too _names[_myId] = ConnectUIController.DisplayName; _currentState = (GameState)_bitBuffer.ReadByte(); // Read all the ids and names it gives me and store it into _names to be used when players get spawned ushort count = _bitBuffer.ReadUShort(); _scoreboardController.ResetScores(); for (int i = 0; i < count; i++) { ushort id = _bitBuffer.ReadUShort(); string name = _bitBuffer.ReadString(); short score = _bitBuffer.ReadShort(); _names[id] = name; Debug.Log("id: " + id + ", name: " + name); _scoreboardController.UpdateEntry(id, name, score); } _scoreboardController.DrawBoard(); StatusText.enabled = true; if (_currentState == GameState.Waiting) { StatusText.text = "Waiting for at least two players"; } else { StatusText.text = "Waiting for current round to end..."; _musicController.Pause(); } _handShakeComplete = true; break; } case 3: { // GUARD FROM SETTING PLAYER POSITIONS UNTIL WE HAVE OUR ID if (!_handShakeComplete) { break; } ushort count = _bitBuffer.ReadUShort(); for (int i = 0; i < count; i++) { ushort id = _bitBuffer.ReadUShort(); uint qX = _bitBuffer.ReadUInt(); uint qY = _bitBuffer.ReadUInt(); // GUARD FROM CHANGING LOCAL PLAYERS POSITION if (id == _myId) { continue; } QuantizedVector2 qPosition = new QuantizedVector2(qX, qY); Vector2 position = BoundedRange.Dequantize(qPosition, Constants.WORLD_BOUNDS); if (!_otherPlayers.ContainsKey(id)) { // Create new player GameObject newPlayer = Instantiate(OtherPlayerPrefab, position, Quaternion.identity); Destroy(newPlayer.GetComponent <Rigidbody2D>()); Destroy(newPlayer.GetComponent <CircleCollider2D>()); Destroy(newPlayer.GetComponent <PlayerController>()); Destroy(newPlayer.GetComponent <MusicController>()); PositionInterp positionInterp = newPlayer.GetComponent <PositionInterp>(); positionInterp.enabled = true; _otherPlayers[id] = positionInterp; newPlayer.GetComponent <Nametag>().SetName(_names[id]); _overrideDirtySendRule = true; } // Update the other players position _otherPlayers[id].PushNewPosition(position); } break; } case 4: { ushort id = _bitBuffer.ReadUShort(); if (_otherPlayers.ContainsKey(id)) { Destroy(_otherPlayers[id].gameObject); _otherPlayers.Remove(id); } _scoreboardController.RemoveEntry(id); _scoreboardController.DrawBoard(); break; } case 5: { _currentState = (GameState)_bitBuffer.ReadByte(); HandleStateChange(_currentState); break; } case 7: { ushort count = _bitBuffer.ReadUShort(); _scoreboardController.ResetScores(); for (int i = 0; i < count; i++) { ushort id = _bitBuffer.ReadUShort(); short points = _bitBuffer.ReadShort(); _scoreboardController.UpdateEntry(id, _names[id], points); } _scoreboardController.DrawBoard(); break; } case 9: { ushort id = _bitBuffer.ReadUShort(); string name = _bitBuffer.ReadString(); _names[id] = name; // Add this new guy to the scoreboard _scoreboardController.UpdateEntry(id, name, 0); _scoreboardController.DrawBoard(); break; } case 13: { ushort id = _bitBuffer.ReadUShort(); if (_myId != id) { _otherPlayers[id].GetComponent <PlayerAnimationController>().Explode(); _audioSource.PlayOneShot(ExplodeSound); } break; } } }
/// <summary> /// Datas the received. /// </summary> /// <param name="sender">Sender.</param> /// <param name="args">Arguments.</param> private static void DataReceived(object sender, DataReceivedEventArgs args) { Console.WriteLine("Received (" + string.Join <byte>(", ", args.Bytes) + ") from " + connection.EndPoint.ToString()); //Decode parse received data //Remove first byte (type) //https://stackoverflow.com/questions/31550484/faster-code-to-remove-first-elements-from-byte-array byte SendTypeBuffer = args.Bytes[0]; byte[] NewBufferReceiver = new byte[args.Bytes.Length - 1]; Array.Copy(args.Bytes, 1, NewBufferReceiver, 0, NewBufferReceiver.Length); //Check SendType if ((SendTypeBuffer == (byte)SendType.SENDTOALL) || (SendTypeBuffer == (byte)SendType.SENDTOOTHER)) { //Deserialize message using NetStack //Reset bit buffer for further reusing data.Clear(); 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); //Show DATA received if (DEBUG) { Console.WriteLine("ID RECEIVED: " + IDObject.ToString()); Console.WriteLine("TYPE RECEIVED: " + TypeBuffer.ToString()); Console.WriteLine("UID RECEIVED: " + OwnerPlayer); Console.WriteLine("IsKINE 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("VEL RECEIVED: " + VelocityReceived.X.ToString() + ", " + VelocityReceived.Y.ToString() + ", " + VelocityReceived.Z.ToString()); Console.WriteLine("INTERPOLATION TIME: " + InterpolationTime.ToString()); } if ((byte)PacketId.PLAYER_JOIN == TypeBuffer) { Console.WriteLine("Add new Player!"); //Code for new Player //Spawn something? YES //Using Dispatcher? NO //PlayerSpawn SendMessage(SendType.SENDTOOTHER, PacketId.PLAYER_SPAWN, 0, UID + ";" + AvatarName, true, lastPosition, lastRotation, VelocityDefaultZero, 0f); //TODO: Using Reliable UDP?? } else if ((byte)PacketId.OBJECT_MOVE == TypeBuffer) { Console.WriteLine("OBJECT MOVE"); } else if ((byte)PacketId.PLAYER_MOVE == TypeBuffer) { Console.WriteLine("PLAYER MOVE"); } else if ((byte)PacketId.PLAYER_SPAWN == TypeBuffer) { Console.WriteLine("PLAYER SPAWN"); } else if ((byte)PacketId.OBJECT_SPAWN == TypeBuffer) { Console.WriteLine("OBJECT SPAWN"); //Rez Object Received //RezObject(OwnerPlayer.Split(';')[1], OwnerPlayer.Split(';')[0], false); } else if ((byte)PacketId.OBJECT_UNSPAWN == TypeBuffer) { Console.WriteLine("OBJECT UNSPAWN"); //De Rez Object Received //DeRezObject(OwnerPlayer.Split(';')[1], OwnerPlayer.Split(';')[0], false, ObjectReceived.ID); } } else if (SendTypeBuffer == (byte)SendType.SENDTOSERVER) { //Deserialize message using NetStack //Reset bit buffer for further reusing data.Clear(); 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); if ((byte)CommandType.LOGIN == CommandTypeBuffer) { if (Answer != String.Empty) { UID = Answer; //Set UID for Your Avatar ME //UnityMainThreadDispatcher.Instance().Enqueue(SetUIDInMainThread(HMessageReceived.Answer)); Console.WriteLine("UID RECEIVED: " + Answer); //PLAYER_JOIN MESSAGE (SENDTOOTHER) SendMessage(SendType.SENDTOOTHER, PacketId.PLAYER_JOIN, 0, UID + ";" + AvatarName, true, lastPosition, lastRotation, VelocityDefaultZero, 0f); //TO DO: Using Reliable UDP?? } else { Console.WriteLine("UID RECEIVED is EMPTY (NOT VALID PASSWORD): " + Answer); //Disconnect if (connection != null) { Console.WriteLine("DisConnecting from: " + connection.EndPoint.ToString()); connection.Close(); } } } else if ((byte)CommandType.DISCONNECTEDCLIENT == CommandTypeBuffer) { //Debug Disconnected UID Console.WriteLine("UID RECEIVED and TO DESTROY: " + Answer); } } args.Recycle(); }