using RBG_Server; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace RBG_Server_WPF { /// /// Interaction logic for ConnectionPage.xaml /// public partial class ConnectionPage : Page { public ConnectionPage() { InitializeComponent(); } private void HostButton_Click(object sender, RoutedEventArgs e) { // Draw host window ServerGrid.Visibility = Visibility.Visible; ServerSelectPanel.Visibility = Visibility.Collapsed; } private void ConnectButton_Click(object sender, RoutedEventArgs e) { // Draw client window ClientGrid.Visibility = Visibility.Visible; ServerSelectPanel.Visibility = Visibility.Collapsed; } private void BackButton_Click(object sender, RoutedEventArgs e) { // Hide host view, show connect view ServerGrid.Visibility = Visibility.Collapsed; ServerSelectPanel.Visibility = Visibility.Visible; } private void ClientBackButton_Click(object sender, RoutedEventArgs e) { ClientGrid.Visibility = Visibility.Collapsed; ServerSelectPanel.Visibility = Visibility.Visible; } private void ClientServerConnectButton_Click(object sender, RoutedEventArgs e) { // Run an async connection task // This task establishes a connection, then Task clientConnect = new Task( async () => { TcpClient client = new TcpClient(); try { await client.ConnectAsync(ServerAddressConnectBox.Text, int.Parse(ServerPortConnectBox.Text)); if (client.Connected) { // Invoke the display to update Dispatcher.Invoke(() => { StatusTextBlock.Text = "Connected!"; StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255)); }); // Run image downloading for the sprite // This task is contained in the CommunicationHandler class Progress progress = new Progress(); Task t = App.Context.GameCommunicationHandler.InitDataLoader(client.GetStream(), progress); progress.ProgressChanged += Progress_ProgressChanged; t.Start(); // t is asynchronous; we don't need to monitor/await progress as it fires its progress through the assigned handler // We should, however, ensure that we don't make requests on client until progress is completed } else { Dispatcher.Invoke(() => { StatusTextBlock.Text = "Connection Failed"; StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)); }); } } catch (Exception ex) { Dispatcher.Invoke(() => { StatusTextBlock.Text = ex.Message[..(128 < ex.Message.Length ? 128 : ex.Message.Length)]; StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)); }); client?.Dispose(); } }); } /// /// Callback that updates the UI with the new images, once downloaded /// /// /// /// private void Progress_ProgressChanged(object sender, CommunicationHandler.ProgressData e) { // Load sprites as they arrive if (e.CurrentActivity == CommunicationHandler.ProgressData.Activity.ImageDownloaded) { Dispatcher.Invoke(() => StatusTextBlock.Text = $"Downloaded {e.Progress} of {App.Context.GameCommunicationHandler.ImageList.Count} images."); App.Context.GameCommunicationHandler.ImageCollection.TryGetValue(e.Message, out CachedByteArray cachedByteArray); BitmapImage image = new(); image.BeginInit(); image.StreamSource = new MemoryStream(cachedByteArray, false); image.EndInit(); Image spriteImage = new() { Source = image }; if (e.Message == App.Context.GameCommunicationHandler.BoardName) { // Image is the board image Dispatcher.Invoke(() =>BoardPreviewImage.Source = image); } else { // Image is a sprite, load it LoadedSpriteGrid loadedSprite = null; foreach (LoadedSpriteGrid item in ClientLoadedSprites.Children) { if (item.Equals(e.Message)) { loadedSprite = item; break; } } if (loadedSprite == null) loadedSprite = new LoadedSpriteGrid(spriteImage, e.Message); // Add the loaded image into the view Dispatcher.Invoke(() => ClientLoadedSprites.Children.Add(loadedSprite)); } } } internal class LoadedSpriteGrid : Grid { string imageName; public LoadedSpriteGrid(Image spriteImage, string imageName) { Children.Add(spriteImage); this.imageName = imageName; } public new bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return false; } return imageName.Equals(((LoadedSpriteGrid)obj).imageName); } } } }