Implemented sprite loading

This commit is contained in:
Brychan Dempsey 2021-10-17 16:04:08 +13:00
parent 53aa75df2b
commit 5d518428e7
4 changed files with 140 additions and 8 deletions

View File

@ -18,8 +18,9 @@ namespace RBG_Server
/// </summary>
public partial class App : Application
{
public static App Context { get; private set; }
public GameServer BoardGameServer {get;}
public CommunicationHandler communicationHandler { get; private set;}
public CommunicationHandler GameCommunicationHandler { get; private set;}
protected static readonly SolidColorBrush RED_BRUSH = new(Color.FromRgb(255, 0, 0));
protected static readonly SolidColorBrush BLUE_BRUSH = new(Color.FromRgb(0, 0, 255));

View File

@ -8,12 +8,12 @@
d:DesignHeight="450" d:DesignWidth="800"
Title="ConnectionPage" MinWidth="1024" MinHeight="762">
<Grid x:Name="RootGrid">
<Grid x:Name="RootGrid" IsEnabled="False">
<StackPanel x:Name="ServerSelectPanel" HorizontalAlignment="Center" VerticalAlignment="Center" d:IsHidden="True" >
<Button x:Name="HostButton" Content="Host a Game" Margin="0,0,0,5" Click="HostButton_Click"/>
<Button x:Name="ConnectButton" Content="Connect to Server" Margin="0,5,0,0" Click="ConnectButton_Click"/>
</StackPanel>
<Grid x:Name="ServerGrid">
<Grid x:Name="ServerGrid" d:IsHidden="True">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="400"/>
<ColumnDefinition/>
@ -50,6 +50,21 @@
<Grid x:Name="PreviewImageOverlay" HorizontalAlignment="Center" VerticalAlignment="Center" Width="{Binding ActualWidth, ElementName=PreviewImage}" Height="{Binding ActualHeight, ElementName=PreviewImage}"/>
</Grid>
</Grid>
<Grid x:Name="ClientGrid">
<StackPanel>
<Button x:Name="ClientBackButton" Content="Back" Margin="0,5,0,0" HorizontalAlignment="Center" Click="ClientBackButton_Click"/>
<TextBlock Text="Server Address:" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="ServerAddressConnectBox" TextWrapping="Wrap" Text="rbg.software.kauripeak.co.nz" MinWidth="300" HorizontalAlignment="Center"/>
<TextBlock Text="Server Port:" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="ServerPortConnectBox" TextWrapping="Wrap" Text="20000" MinWidth="300" HorizontalAlignment="Center"/>
<Button x:Name="ClientServerConnectButton" Content="Connect to Server" Margin="0,5,0,0" HorizontalAlignment="Center" Click="ClientServerConnectButton_Click"/>
<TextBlock x:Name="StatusTextBlock" Text="Waiting to connect..." TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" HorizontalAlignment="Center" Visibility="Hidden"/>
<ProgressBar x:Name="StatusProgressBar" HorizontalAlignment="Center" MinWidth="400" MinHeight="10" Visibility="Hidden" />
<UniformGrid x:Name="ClientLoadedSprites" Columns="6" Rows="6" MinHeight="120" HorizontalAlignment="Center" MinWidth="400" />
<Image x:Name="BoardPreviewImage" MinWidth="120" MinHeight="120" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button x:Name="ClientStartGameButton" Content="Join Game" HorizontalAlignment="Center" Background="#955FF17A" Foreground="White" Padding="5,5,5,5"/>
</StackPanel>
</Grid>
</Grid>

View File

@ -1,6 +1,9 @@
using System;
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;
@ -35,6 +38,8 @@ namespace RBG_Server_WPF
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)
@ -43,5 +48,115 @@ namespace RBG_Server_WPF
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<CommunicationHandler.ProgressData> progress = new Progress<CommunicationHandler.ProgressData>();
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();
}
});
}
/// <summary>
/// Callback that updates the UI with the new images, once downloaded
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
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
};
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);
}
}
}
}

View File

@ -109,7 +109,7 @@ namespace RBG_Server
}
struct ProgressData
public struct ProgressData
{
/// <summary>
/// Current activity being processed
@ -128,7 +128,7 @@ namespace RBG_Server
Finished,
}
public Activity CurrentActivity;
public string Message;
public int Progress;
}
@ -138,7 +138,7 @@ namespace RBG_Server
/// <param name="dataStream"></param>
/// <param name="progressUpdates"></param>
/// <returns></returns>
private async Task InitDataLoader(NetworkStream dataStream, IProgress<ProgressData> progressUpdates)
public async Task InitDataLoader(NetworkStream dataStream, IProgress<ProgressData> progressUpdates)
{
byte[] buffer = new byte[] { 2, 0, 0, 0, 128, 0 }; // Get image collection names
dataStream.Write(buffer, 0, buffer.Length);
@ -185,6 +185,7 @@ namespace RBG_Server
progressUpdates.Report(new ProgressData()
{
CurrentActivity = ProgressData.Activity.MessageReceived,
Message = item,
Progress = i,
});
}