static void WebServerOnConnect(int id) { _connectedIds.Add(id); _playerDatas[id] = new PlayerData() { id = (ushort)id }; // Tell new client their id _bitBuffer.Clear(); _bitBuffer.AddByte(2); _bitBuffer.AddUShort((ushort)id); _bitBuffer.ToArray(_buffer); _webServer.SendOne(id, new ArraySegment <byte>(_buffer, 0, 3)); }
private void WebClientOnonConnect() { Debug.Log("Client connected"); _wasConnected = true; // Hide the connect screen ConnectUIController.HideConnectScreen(); // Setup your own nametag LocalPlayerTransform.GetComponent <Nametag>().SetName(ConnectUIController.DisplayName); // Send server your name and potentially some character customization stuff _bitBuffer.Clear(); _bitBuffer.AddByte(8); _bitBuffer.AddString(ConnectUIController.DisplayName); _bitBuffer.ToArray(_buffer); _webClient.Send(new ArraySegment <byte>(_buffer, 0, 22)); }
private static void StateUpdateTimerOnElapsed(Object source, ElapsedEventArgs e) { _bitBuffer.Clear(); _bitBuffer.AddByte(3); _bitBuffer.AddUShort((ushort)_dataToSend.Count); foreach (PlayerData playerData in _dataToSend) { } }
private static void StateUpdateTimerOnElapsed(Object source, ElapsedEventArgs e) { _bitBuffer.Clear(); _bitBuffer.AddByte(3); _bitBuffer.AddUShort((ushort)_dataToSend.Count); foreach (PlayerData playerData in _dataToSend) { _bitBuffer.AddUShort(playerData.id); _bitBuffer.AddUInt(playerData.qX); _bitBuffer.AddUInt(playerData.qY); } _bitBuffer.ToArray(_buffer); _webServer.SendAll(_connectedIds, new ArraySegment <byte>(_buffer, 0, 3 + 10 * _dataToSend.Count)); }
public override BitBuffer PackVariable(BitBuffer buffer) { // cannot send nulls if (Value == null) { Value = ""; } int len = Value.Length; buffer.AddInt(len); for (int i = 0; i < len; i++) { buffer.AddByte((byte)Value[i]); } return(buffer); }
/// <summary> /// Clients the disconnect handler. /// </summary> /// <param name="sender">Sender.</param> /// <param name="args">Arguments.</param> private void ClientDisconnectHandler(object sender, DisconnectedEventArgs args) { Connection connection = (Connection)sender; Console.WriteLine("Connection from " + connection.EndPoint + " lost"); String UIDBuffer = String.Empty; //Cerca e restituisci il tutto foreach (var conn in clients) { if (conn.Value == connection) //SENDTOSERVER { UIDBuffer = conn.Key; Console.WriteLine("UID TO DESTROY: " + UIDBuffer); } } //https://stackoverflow.com/posts/1608949/revisions //Debug //Delete client disconnected clients.RemoveAll(item => item.Value.Equals(connection)); BitBuffer data = new BitBuffer(1024); data.AddByte((byte)CommandType.DISCONNECTEDCLIENT) .AddString(UIDBuffer); Console.WriteLine("BitBuffer: " + data.Length.ToString()); byte[] BufferNetStack = new byte[data.Length]; data.ToArray(BufferNetStack); data.Clear(); //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; foreach (var conn in clients) { conn.Value.SendBytes(newArray, SendOption.Reliable); Console.WriteLine("Send to: " + conn.Value.EndPoint.ToString()); } args.Recycle(); }
static void Main(string[] args) { _rand = new Random(Environment.TickCount); SslConfig sslConfig; TcpConfig tcpConfig = new TcpConfig(true, 5000, 20000); Console.WriteLine("Setting up secure server"); sslConfig = new SslConfig(true, "cert.pfx", "", SslProtocols.Tls12); _webServer = new SimpleWebServer(10000, tcpConfig, 16 * 1024, 3000, sslConfig); _webServer.Start(Constants.GAME_PORT); Console.WriteLine("Server started"); _webServer.onConnect += WebServerOnConnect; _webServer.onData += WebServerOnData; _webServer.onDisconnect += WebServerOnDisconnect; Timer stateUpdateTimer = new Timer(1f / Constants.SERVER_TICKRATE * 1000); stateUpdateTimer.Elapsed += StateUpdateTimerOnElapsed; stateUpdateTimer.AutoReset = true; stateUpdateTimer.Enabled = true; while (!Console.KeyAvailable) { _webServer.ProcessMessageQueue(); // GUARD, DONT DO STATE STUFF IF WE ARE WAITING if (_waitingOnStateTimer) { continue; } switch (_currentState) { case GameState.Waiting: { if (_handshakenClientCount >= 2 && _connectedIds.Count >= 2) { _currentState = GameState.Begin; SendStateUpdate(_currentState); } break; } case GameState.Begin: { // Set timer to go to builder state beginTimer = new Timer(SECONDS_WAITING_IN_BEGIN * 1000); beginTimer.AutoReset = false; beginTimer.Start(); _waitingOnStateTimer = true; beginTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _movedObjects = new Dictionary <ushort, Tuple <ushort, ushort> >(); _currentState = GameState.Builder; SendStateUpdate(_currentState); }; break; } case GameState.Builder: { // Set timer to go to builder state buildTimer = new Timer(SECONDS_WAITING_IN_BUILD * 1000); buildTimer.AutoReset = false; buildTimer.Start(); _waitingOnStateTimer = true; buildTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; // Reset everyones guesses foreach (PlayerData playerData in _playerDatas.Values) { playerData.guesses.Clear(); } // Make sure builder actually moved something, // if he didnt, goto scoring and give everyone else a point if (_movedObjects.Count > 0) { _currentState = GameState.Search; } else { foreach (PlayerData data in _playerDatas.Values) { if (data.id != _builderId) { data.points += 1; } _playerDatas[_builderId].points -= (ushort)_handshakenClientCount; } _currentState = GameState.Scoring; } SendStateUpdate(_currentState); }; break; } case GameState.Search: { // Set timer to go to scoring state searchTimer = new Timer(SECONDS_WAITING_IN_SEARCH * 1000); searchTimer.AutoReset = false; searchTimer.Start(); _waitingOnStateTimer = true; searchTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _currentState = GameState.Scoring; SendStateUpdate(_currentState); }; break; } case GameState.Scoring: { // Set timer to wait for points to come in from clients scoringTimer = new Timer(SECONDS_WAITING_IN_SCORING * 1000); scoringTimer.AutoReset = false; scoringTimer.Start(); _waitingOnStateTimer = true; scoringTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; // Tell everyone everyones scores _bitBuffer.Clear(); _bitBuffer.AddByte(7); _bitBuffer.AddUShort((ushort)_playerDatas.Count); foreach (PlayerData data in _playerDatas.Values) { _bitBuffer.AddUShort(data.id); _bitBuffer.AddShort(data.points); } _bitBuffer.ToArray(_buffer); _webServer.SendAll(_connectedIds, new ArraySegment <byte>(_buffer, 0, 3 + 4 * _playerDatas.Count)); if (_handshakenClientCount >= 2 && _connectedIds.Count >= 2) { _currentState = GameState.Begin; } else { _currentState = GameState.Waiting; } SendStateUpdate(_currentState); }; break; } } } Console.WriteLine("Closing server"); _webServer.Stop(); }
static void Main(string[] args) { _rand = new Random(Environment.TickCount); SslConfig sslConfig; TcpConfig tcpConfig = new TcpConfig(true, 5000, 20000); Console.WriteLine("Setting up secure server"); sslConfig = new SslConfig(true, "cert.pfx", "", SslProtocols.Tls12); _webServer = new SimpleWebServer(10000, tcpConfig, 16 * 1024, 3000, sslConfig); _webServer.Start(Constants.GAME_PORT); Console.WriteLine("Server started"); _webServer.onConnect += WebServerOnConnect; _webServer.onData += WebServerOnData; _webServer.onDisconnect += WebServerOnDisconnect; Timer stateUpdateTimer = new Timer(1f / Constants.SERVER_TICKRATE * 1000); stateUpdateTimer.Elapsed += StateUpdateTimerOnElapsed; stateUpdateTimer.AutoReset = true; stateUpdateTimer.Enabled = true; while (!Console.KeyAvailable) { _webServer.ProcessMessageQueue(); // GUARD, DONT DO STATE STUFF IF WE ARE WAITING if (_waitingOnStateTimer) { continue; } switch (_currentState) { case GameState.Waiting: { if (_connectedIds.Count >= 2) { _currentState = GameState.Begin; SendStateUpdate(_currentState); } break; } case GameState.Begin: { // Set timer to go to builder state beginTimer = new Timer(SECONDS_WAITING_IN_BEGIN * 1000); beginTimer.AutoReset = false; beginTimer.Start(); _waitingOnStateTimer = true; beginTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _movedObjects = new List <ushort>(); _currentState = GameState.Builder; SendStateUpdate(_currentState); }; break; } case GameState.Builder: { // Set timer to go to builder state buildTimer = new Timer(SECONDS_WAITING_IN_BUILD * 1000); buildTimer.AutoReset = false; buildTimer.Start(); _waitingOnStateTimer = true; buildTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; // Reset everyones guesses foreach (PlayerData playerData in _playerDatas.Values) { playerData.guesses.Clear(); } _currentState = GameState.Search; SendStateUpdate(_currentState); }; break; } case GameState.Search: { // Set timer to go to scoring state searchTimer = new Timer(SECONDS_WAITING_IN_SEARCH * 1000); searchTimer.AutoReset = false; searchTimer.Start(); _waitingOnStateTimer = true; searchTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _currentState = GameState.Scoring; SendStateUpdate(_currentState); }; break; } case GameState.Scoring: { short builderPoints = 0; _bitBuffer.Clear(); _bitBuffer.AddByte(7); _bitBuffer.AddUShort((ushort)_playerDatas.Count); foreach (var playerData in _playerDatas.Values) { // GUARD, DON'T SCORE THE BUILDER THIS WAY if (playerData.id == _builderId) { continue; } // Free points for objects builder couldnt move // A point for a correct guess, minus point for a wrong guess int numCorrect = _movedObjects.Distinct().Intersect(playerData.guesses).Count(); int newPoints = (numCorrect * 2) - playerData.guesses.Count + (NUMBER_OF_MOVEABLE_OBJECTS - _movedObjects.Count); playerData.points += (short)newPoints; // Builder gets a point for each player who couldnt find any differences if (numCorrect == 0) { builderPoints += 1; } _bitBuffer.AddUShort(playerData.id); _bitBuffer.AddShort(playerData.points); } _playerDatas[_builderId].points += builderPoints; _bitBuffer.AddUShort((ushort)_builderId); _bitBuffer.AddShort(_playerDatas[_builderId].points); _bitBuffer.ToArray(_buffer); _webServer.SendAll(_connectedIds, new ArraySegment <byte>(_buffer, 0, 3 + 2 * _playerDatas.Count)); if (_connectedIds.Count >= 2) { _currentState = GameState.Begin; } else { _currentState = GameState.Waiting; } SendStateUpdate(_currentState); break; } } } Console.WriteLine("Closing server"); _webServer.Stop(); }
/// <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!"); } } } } } }
static void Main(string[] args) { _rand = new Random(Environment.TickCount); SslConfig sslConfig; TcpConfig tcpConfig = new TcpConfig(true, 5000, 20000); Console.WriteLine("Setting up secure server"); sslConfig = new SslConfig(true, "cert.pfx", "", SslProtocols.Tls12); _webServer = new SimpleWebServer(10000, tcpConfig, 16 * 1024, 3000, sslConfig); _webServer.Start(Constants.GAME_PORT); Console.WriteLine("Server started"); _webServer.onConnect += WebServerOnConnect; _webServer.onData += WebServerOnData; _webServer.onDisconnect += WebServerOnDisconnect; Timer stateUpdateTimer = new Timer(1f / Constants.SERVER_TICKRATE * 1000); stateUpdateTimer.Elapsed += StateUpdateTimerOnElapsed; stateUpdateTimer.AutoReset = true; stateUpdateTimer.Enabled = true; while (!Console.KeyAvailable) { _webServer.ProcessMessageQueue(); // GUARD, DONT DO STATE STUFF IF WE ARE WAITING if (_waitingOnStateTimer) { continue; } switch (_currentState) { case GameState.Waiting: { if (_connectedIds.Count >= 2) { _currentState = GameState.Begin; SendStateUpdate(_currentState); } break; } case GameState.Begin: { // Set timer to go to builder state beginTimer = new Timer(SECONDS_WAITING_IN_BEGIN * 1000); beginTimer.AutoReset = false; beginTimer.Start(); _waitingOnStateTimer = true; beginTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _movedObjects = new HashSet <ushort>(); _currentState = GameState.Builder; SendStateUpdate(_currentState); }; break; } case GameState.Builder: { // Set timer to go to builder state buildTimer = new Timer(SECONDS_WAITING_IN_BUILD * 1000); buildTimer.AutoReset = false; buildTimer.Start(); _waitingOnStateTimer = true; buildTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; // Reset everyones guesses foreach (PlayerData playerData in _playerDatas.Values) { playerData.guesses.Clear(); } _currentState = GameState.Search; SendStateUpdate(_currentState); }; break; } case GameState.Search: { // Set timer to go to scoring state searchTimer = new Timer(SECONDS_WAITING_IN_SEARCH * 1000); searchTimer.AutoReset = false; searchTimer.Start(); _waitingOnStateTimer = true; searchTimer.Elapsed += delegate(Object source, ElapsedEventArgs e) { _waitingOnStateTimer = false; _currentState = GameState.Scoring; SendStateUpdate(_currentState); }; break; } case GameState.Scoring: { short builderPoints = 0; _bitBuffer.Clear(); _bitBuffer.AddByte(7); _bitBuffer.AddUShort((ushort)_playerDatas.Count); _bitBuffer.ToArray(_buffer); _webServer.SendAll(_connectedIds, new ArraySegment <byte>(_buffer, 0, 3 + 2 * _playerDatas.Count)); if (_connectedIds.Count >= 2) { _currentState = GameState.Begin; } else { _currentState = GameState.Waiting; } SendStateUpdate(_currentState); break; } } } Console.WriteLine("Closing server"); _webServer.Stop(); }
private static void StateUpdateTimerOnElapsed(Object source, ElapsedEventArgs e) { _bitBuffer.Clear(); _bitBuffer.AddByte(3); }
/// <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!"); } }