diff --git a/InsightLogParser.Client/Spider.cs b/InsightLogParser.Client/Spider.cs index 3a6fdad..5215c1f 100644 --- a/InsightLogParser.Client/Spider.cs +++ b/InsightLogParser.Client/Spider.cs @@ -66,6 +66,7 @@ public void SetServer(string serverAddress, DateTimeOffset timestamp) _sessionStart = timestamp; _serverTracker.Connected(serverAddress); _messageWriter.ConnectedToServer(serverAddress, timestamp); + _uiCommands.SetConnection(true, serverAddress); } public void ConnectingToServer(string serverAddress) @@ -78,6 +79,7 @@ public void EndSession(DateTimeOffset timestamp) _messageWriter.SessionEnded(timestamp, _serverAddress); _sessionStart = null; _serverAddress = null; + _uiCommands.SetConnection(false, string.Empty); } public async Task SessionBeingDisconnectedAsync() diff --git a/InsightLogParser.Client/Websockets/ISocketUiCommands.cs b/InsightLogParser.Client/Websockets/ISocketUiCommands.cs index 9eea1fd..871f5de 100644 --- a/InsightLogParser.Client/Websockets/ISocketUiCommands.cs +++ b/InsightLogParser.Client/Websockets/ISocketUiCommands.cs @@ -1,4 +1,5 @@ -using InsightLogParser.Common.PuzzleParser; +using System.Net.WebSockets; +using InsightLogParser.Common.PuzzleParser; using InsightLogParser.Common.World; namespace InsightLogParser.Client.Websockets; @@ -8,24 +9,37 @@ public interface ISocketUiCommands /// /// Sets the current target /// - /// The coordinate of the target + /// The coordinate of the target /// The target puzzle /// The number of the current route node or 0 if not on route /// The length of the route or 0 if not on route - void SetTarget(Coordinate coordinate, InsightPuzzle puzzle, int routeNumber, int routeLength); + /// The websocket to send to, or everyone if not specified + void SetTarget(Coordinate target, InsightPuzzle puzzle, int routeNumber, int routeLength, WebSocket? webSocket = null); /// /// Updates the player position /// - /// The coordinate of the last known player position - void MovePlayer(Coordinate coordinate); + /// The coordinate of the last known player position + /// The websocket to send to, or everyone if not specified + void MovePlayer(Coordinate destination, WebSocket? webSocket = null); + + /// + /// Updates the connection state + /// + /// Whether the user is connected to the game + /// The IP address of the server the user is connected to + /// The websocket to send to, or everyone if not specified + void SetConnection(bool isConnected, string ipAddress, WebSocket? webSocket = null ) { } } internal class DummySocketUiCommands : ISocketUiCommands { //No-op - public void SetTarget(Coordinate coordinate, InsightPuzzle puzzle, int routeNumber, int routeLength) { } + public void SetTarget(Coordinate target, InsightPuzzle puzzle, int routeNumber, int routeLength, WebSocket? webSocket) { } + + //No-op + public void MovePlayer(Coordinate destination, WebSocket? webSocket) { } //No-op - public void MovePlayer(Coordinate coordinate) { } + public void SetConnection(bool isConnected, string ipAddress, WebSocket? webSocket) { } } \ No newline at end of file diff --git a/InsightLogParser.Client/Websockets/Server.cs b/InsightLogParser.Client/Websockets/Server.cs index 742d164..a868558 100644 --- a/InsightLogParser.Client/Websockets/Server.cs +++ b/InsightLogParser.Client/Websockets/Server.cs @@ -17,6 +17,20 @@ internal class Server : ISocketUiCommands private ISocketParserCommands _parserCommands; private Task _listenerTask; + // setTarget data + private Coordinate _target = new Coordinate(0, 0, 0); + private PuzzleType _puzzleType = PuzzleType.Unknown; + private int _puzzleId = 0; + private int _routeNumber = 0; + private int _routeLength = 0; + + // movePlayer data + private Coordinate _destination = new Coordinate(0, 0, 0); + + // setConnected data + private bool _isConnected = false; + private string _ipAddress = string.Empty; + public Server(CancellationToken forcedCancellationToken) { _stopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(forcedCancellationToken); @@ -106,6 +120,14 @@ private async Task HandleWebSocketConnection(WebSocket webSocket, CancellationTo // Add the connection. _clients.Add(webSocket); + // Initialize the data for the UI. + if (webSocket.State == WebSocketState.Open) + { + SetTarget(_target, new InsightPuzzle { Type = _puzzleType, KrakenId = _puzzleId }, _routeNumber, _routeLength, webSocket); + MovePlayer(_destination, webSocket); + SetConnection(_isConnected, _ipAddress, webSocket); + } + while (webSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested) { var buffer = new byte[1024]; @@ -190,50 +212,84 @@ private async Task HandleWebSocketConnection(WebSocket webSocket, CancellationTo _clients.TryTake(out _); } - private async Task SendAsync(object message) + private async Task SendAsync(object message, WebSocket? webSocket = null) { // Encode the message. var messageBuffer = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message)); var messageSegment = new ArraySegment(messageBuffer); - // Send the message to all clients. - foreach (var client in _clients) + if (webSocket == null) + { + // Send the message to all clients. + foreach (var client in _clients) + { + if (client.State != WebSocketState.Open) continue; + await client.SendAsync(messageSegment, WebSocketMessageType.Text, true, CancellationToken.None); + } + } + else { - if (client.State != WebSocketState.Open) continue; - await client.SendAsync(messageSegment, WebSocketMessageType.Text, true, CancellationToken.None); + // Send the message to a specific client. + if (webSocket.State == WebSocketState.Open) + { + await webSocket.SendAsync(messageSegment, WebSocketMessageType.Text, true, CancellationToken.None); + } } } #region ISocketUiCommands - public void SetTarget(Coordinate coordinate, InsightPuzzle puzzle, int routeNumber, int routeLength) + public void SetTarget(Coordinate target, InsightPuzzle puzzle, int routeNumber, int routeLength, WebSocket? websocket) { + if (target.X == 0 && target.Y == 0 && target.Z == 0) return; + _ = SendAsync(new { type = "setTarget", target = new { - coordinate.X, - coordinate.Y, - coordinate.Z + target.X, + target.Y, + target.Z }, puzzleType = (int)puzzle.Type, puzzleId = puzzle.KrakenId, routeNumber = routeNumber, routeLength = routeLength, - }); + }, websocket); + + _target = target; + _puzzleType = puzzle.Type; + _puzzleId = puzzle.KrakenId; + _routeNumber = routeNumber; + _routeLength = routeLength; } - public void MovePlayer(Coordinate coordinate) + public void MovePlayer(Coordinate destination, WebSocket? websocket) { + if (destination.X == 0 && destination.Y == 0 && destination.Z == 0) return; + _ = SendAsync(new { type = "movePlayer", destination = new { - coordinate.X, - coordinate.Y, - coordinate.Z + destination.X, + destination.Y, + destination.Z } - }); + }, websocket); + + _destination = destination; } + public void SetConnection(bool isConnected, string ipAddress, WebSocket? websocket) + { + _ = SendAsync(new { + type = "setConnection", + isConnected = isConnected, + ipAddress = ipAddress + }, websocket); + + _ipAddress = ipAddress; + _isConnected = isConnected; + } #endregion } \ No newline at end of file diff --git a/InsightLogParser.UI/Main.Designer.cs b/InsightLogParser.UI/Main.Designer.cs index 8fa3706..2650ec0 100644 --- a/InsightLogParser.UI/Main.Designer.cs +++ b/InsightLogParser.UI/Main.Designer.cs @@ -32,17 +32,20 @@ private void InitializeComponent() { picArrow = new PictureBox(); lblPuzzleType = new Label(); lblID = new Label(); - tableLayoutPanel1 = new TableLayoutPanel(); - picMap = new PictureBox(); + pnlRoute = new TableLayoutPanel(); picScreenshot = new PictureBox(); + picMap = new PictureBox(); + strStatus = new StatusStrip(); + lblIP = new ToolStripStatusLabel(); pnlMain.SuspendLayout(); pnlTarget.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)picPuzzleType).BeginInit(); ((System.ComponentModel.ISupportInitialize)picCompass).BeginInit(); ((System.ComponentModel.ISupportInitialize)picArrow).BeginInit(); - tableLayoutPanel1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)picMap).BeginInit(); + pnlRoute.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)picScreenshot).BeginInit(); + ((System.ComponentModel.ISupportInitialize)picMap).BeginInit(); + strStatus.SuspendLayout(); SuspendLayout(); // // pnlMain @@ -50,7 +53,7 @@ private void InitializeComponent() { pnlMain.ColumnCount = 1; pnlMain.ColumnStyles.Add(new ColumnStyle()); pnlMain.Controls.Add(pnlTarget, 0, 0); - pnlMain.Controls.Add(tableLayoutPanel1, 0, 1); + pnlMain.Controls.Add(pnlRoute, 0, 1); pnlMain.Dock = DockStyle.Fill; pnlMain.Location = new Point(0, 0); pnlMain.Margin = new Padding(0); @@ -58,7 +61,7 @@ private void InitializeComponent() { pnlMain.RowCount = 2; pnlMain.RowStyles.Add(new RowStyle(SizeType.Absolute, 64F)); pnlMain.RowStyles.Add(new RowStyle()); - pnlMain.Size = new Size(800, 450); + pnlMain.Size = new Size(814, 447); pnlMain.TabIndex = 0; // // pnlTarget @@ -84,7 +87,7 @@ private void InitializeComponent() { pnlTarget.Name = "pnlTarget"; pnlTarget.RowCount = 1; pnlTarget.RowStyles.Add(new RowStyle()); - pnlTarget.Size = new Size(800, 64); + pnlTarget.Size = new Size(814, 64); pnlTarget.TabIndex = 0; // // lbl2DDistance @@ -166,25 +169,37 @@ private void InitializeComponent() { lblID.Location = new Point(192, 0); lblID.Margin = new Padding(0); lblID.Name = "lblID"; - lblID.Size = new Size(608, 65); + lblID.Size = new Size(622, 65); lblID.TabIndex = 6; lblID.TextAlign = ContentAlignment.TopRight; // - // tableLayoutPanel1 - // - tableLayoutPanel1.ColumnCount = 2; - tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33F)); - tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 67F)); - tableLayoutPanel1.Controls.Add(picScreenshot, 0, 0); - tableLayoutPanel1.Controls.Add(picMap, 0, 0); - tableLayoutPanel1.Dock = DockStyle.Fill; - tableLayoutPanel1.Location = new Point(0, 64); - tableLayoutPanel1.Margin = new Padding(0); - tableLayoutPanel1.Name = "tableLayoutPanel1"; - tableLayoutPanel1.RowCount = 1; - tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); - tableLayoutPanel1.Size = new Size(800, 386); - tableLayoutPanel1.TabIndex = 1; + // pnlRoute + // + pnlRoute.ColumnCount = 2; + pnlRoute.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33F)); + pnlRoute.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 67F)); + pnlRoute.Controls.Add(picScreenshot, 0, 0); + pnlRoute.Controls.Add(picMap, 0, 0); + pnlRoute.Dock = DockStyle.Fill; + pnlRoute.Location = new Point(0, 64); + pnlRoute.Margin = new Padding(0); + pnlRoute.Name = "pnlRoute"; + pnlRoute.RowCount = 2; + pnlRoute.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + pnlRoute.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F)); + pnlRoute.Size = new Size(814, 386); + pnlRoute.TabIndex = 1; + // + // picScreenshot + // + picScreenshot.Dock = DockStyle.Fill; + picScreenshot.Location = new Point(268, 0); + picScreenshot.Margin = new Padding(0); + picScreenshot.Name = "picScreenshot"; + picScreenshot.Size = new Size(546, 366); + picScreenshot.SizeMode = PictureBoxSizeMode.Zoom; + picScreenshot.TabIndex = 1; + picScreenshot.TabStop = false; // // picMap // @@ -193,29 +208,39 @@ private void InitializeComponent() { picMap.Location = new Point(0, 0); picMap.Margin = new Padding(0); picMap.Name = "picMap"; - picMap.Size = new Size(264, 386); + pnlRoute.SetRowSpan(picMap, 2); + picMap.Size = new Size(268, 386); picMap.SizeMode = PictureBoxSizeMode.Zoom; picMap.TabIndex = 0; picMap.TabStop = false; // - // picScreenshot + // strStatus // - picScreenshot.Dock = DockStyle.Fill; - picScreenshot.Location = new Point(264, 0); - picScreenshot.Margin = new Padding(0); - picScreenshot.Name = "picScreenshot"; - picScreenshot.Size = new Size(536, 386); - picScreenshot.SizeMode = PictureBoxSizeMode.Zoom; - picScreenshot.TabIndex = 1; - picScreenshot.TabStop = false; + strStatus.BackColor = Color.Black; + strStatus.Items.AddRange(new ToolStripItem[] { lblIP }); + strStatus.LayoutStyle = ToolStripLayoutStyle.Flow; + strStatus.Location = new Point(0, 447); + strStatus.Name = "strStatus"; + strStatus.Size = new Size(814, 20); + strStatus.SizingGrip = false; + strStatus.TabIndex = 1; + // + // lblIP + // + lblIP.BackColor = Color.Black; + lblIP.ForeColor = Color.White; + lblIP.Name = "lblIP"; + lblIP.Size = new Size(79, 15); + lblIP.Text = "Disconnected"; // // Main // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; BackColor = Color.Black; - ClientSize = new Size(800, 450); + ClientSize = new Size(814, 467); Controls.Add(pnlMain); + Controls.Add(strStatus); Name = "Main"; Text = "InsightLogParser.Client"; pnlMain.ResumeLayout(false); @@ -224,10 +249,13 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)picPuzzleType).EndInit(); ((System.ComponentModel.ISupportInitialize)picCompass).EndInit(); ((System.ComponentModel.ISupportInitialize)picArrow).EndInit(); - tableLayoutPanel1.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)picMap).EndInit(); + pnlRoute.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)picScreenshot).EndInit(); + ((System.ComponentModel.ISupportInitialize)picMap).EndInit(); + strStatus.ResumeLayout(false); + strStatus.PerformLayout(); ResumeLayout(false); + PerformLayout(); } #endregion @@ -241,8 +269,10 @@ private void InitializeComponent() { private PictureBox picArrow; private Label lblPuzzleType; private Label lblID; - private TableLayoutPanel tableLayoutPanel1; + private TableLayoutPanel pnlRoute; private PictureBox picMap; private PictureBox picScreenshot; + private StatusStrip strStatus; + private ToolStripStatusLabel lblIP; } } \ No newline at end of file diff --git a/InsightLogParser.UI/Main.cs b/InsightLogParser.UI/Main.cs index 5cb98b9..07a56b5 100644 --- a/InsightLogParser.UI/Main.cs +++ b/InsightLogParser.UI/Main.cs @@ -52,6 +52,12 @@ private async void WebSocketClient_OnMessageReceived(object sender, MessageRecei await SetTarget(location, (PuzzleType)puzzleType, puzzleId, routeNumber, routeLength); break; } + case "setConnection": { + var isConnected = data.RootElement.GetProperty("isConnected").GetBoolean(); + var ipAddress = data.RootElement.TryGetProperty("ipAddress", out var ipAddressElement) ? ipAddressElement.GetString() : string.Empty; + SetConnection(isConnected, ipAddress); + break; + } case "shutdown": Application.Exit(); break; @@ -123,6 +129,10 @@ await _webSocketClient.SendAsync(new { } } + private void SetConnection(bool isConnected, string ipAddress) { + lblIP.Text = isConnected ? $"Connected to {ipAddress}" : "Disconnected"; + } + private void UpdateTarget() { if (_target.X == 0 && _target.Y == 0 && _target.Z == 0) { return; diff --git a/InsightLogParser.UI/Main.resx b/InsightLogParser.UI/Main.resx index af32865..443fba1 100644 --- a/InsightLogParser.UI/Main.resx +++ b/InsightLogParser.UI/Main.resx @@ -117,4 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + + + True + \ No newline at end of file diff --git a/InsightLogParser.UI/Program.cs b/InsightLogParser.UI/Program.cs index 1bbbd8e..6a7b8e2 100644 --- a/InsightLogParser.UI/Program.cs +++ b/InsightLogParser.UI/Program.cs @@ -32,7 +32,7 @@ static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEv // Show exception message static void ShowException(Exception ex) { if (ex != null) { - MessageBox.Show(ex.Message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(ex.Message + " " + ex.StackTrace, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); } } diff --git a/InsightLogParser.UI/Websockets/Client.cs b/InsightLogParser.UI/Websockets/Client.cs index 18412fd..bc2cbbd 100644 --- a/InsightLogParser.UI/Websockets/Client.cs +++ b/InsightLogParser.UI/Websockets/Client.cs @@ -12,7 +12,7 @@ internal class Client { public async Task ConnectAsync(int port) { try { await _clientWebSocket.ConnectAsync(new Uri($"ws://localhost:{port}/ws/"), _cancellationTokenSource.Token); - } catch (Exception ex) { + } catch (Exception) { _cancellationTokenSource.Cancel(); } _ = ReceiveMessagesAsync();