Refactored App and Connection Page, and fixed a few issues

This commit is contained in:
Brychan Dempsey 2021-10-18 11:48:10 +13:00
parent adce10609a
commit 236af4e9ab
3 changed files with 156 additions and 97 deletions

View File

@ -26,6 +26,11 @@ namespace RBG_Server
protected static readonly SolidColorBrush BLUE_BRUSH = new(Color.FromRgb(0, 0, 255)); protected static readonly SolidColorBrush BLUE_BRUSH = new(Color.FromRgb(0, 0, 255));
protected static readonly SolidColorBrush GREEN_BRUSH = new(Color.FromRgb(0, 255, 0)); protected static readonly SolidColorBrush GREEN_BRUSH = new(Color.FromRgb(0, 255, 0));
public const string MIP_LOW = "_mip_low";
public const string MIP_MEDIUM = "_mip_med";
public const string MIP_HIGH = "_mip_high";
public const string MIP_RAW = "_mip_raw";
/// <summary> /// <summary>
/// Loads the specified files from disk, creating mip maps as appropriate /// Loads the specified files from disk, creating mip maps as appropriate
/// </summary> /// </summary>
@ -74,26 +79,26 @@ namespace RBG_Server
{ {
double scaleRate = 32 / (double)Math.Max(height, width); double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(decoder.Thumbnail, scaleRate); MemoryStream ms = ScaleImage(decoder.Thumbnail, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_low" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
else else
{ {
double scaleRate = 32 / (double)Math.Max(height, width); double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(frames[0], scaleRate); MemoryStream ms = ScaleImage(frames[0], scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_low" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
// The remaining mips are animated // The remaining mips are animated
if (width >= 128 || height >= 128) if (width >= 128 || height >= 128)
{ {
double scaleRate = 128 / (double)Math.Max(height, width); double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate); MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_med" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 512 || height >= 512) if (width >= 512 || height >= 512)
{ {
double scaleRate = 512 / (double)Math.Max(height, width); double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate); MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_high" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 512 || height >= 512) if (width >= 512 || height >= 512)
{ {
@ -105,7 +110,7 @@ namespace RBG_Server
} }
MemoryStream ms = new(); MemoryStream ms = new();
encoder.Save(ms); encoder.Save(ms);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_raw" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
} }
@ -132,25 +137,25 @@ namespace RBG_Server
{ {
double scaleRate = 32 / (double)Math.Max(height, width); double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_low" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 128 || height >= 128) if (width >= 128 || height >= 128)
{ {
double scaleRate = 128 / (double)Math.Max(height, width); double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_med" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 512 || height >= 512) if (width >= 512 || height >= 512)
{ {
double scaleRate = 512 / (double)Math.Max(height, width); double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_high" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 512 || height >= 512) if (width >= 512 || height >= 512)
{ {
MemoryStream ms = new(); MemoryStream ms = new();
source.CopyTo(ms); source.CopyTo(ms);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_raw" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
} }
else else
@ -163,25 +168,25 @@ namespace RBG_Server
{ {
double scaleRate = 128 / (double)Math.Max(height, width); double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_low" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 512 || height >= 512) if (width >= 512 || height >= 512)
{ {
double scaleRate = 512 / (double)Math.Max(height, width); double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_med" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 2048 || height >= 2048) if (width >= 2048 || height >= 2048)
{ {
double scaleRate = 2048 / (double)Math.Max(height, width); double scaleRate = 2048 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate); MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_high" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
if (width >= 2048 || height >= 2048) if (width >= 2048 || height >= 2048)
{ {
MemoryStream ms = new(); MemoryStream ms = new();
source.CopyTo(ms); source.CopyTo(ms);
_ = communicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + "_mip_raw" + Path.GetExtension(path), new CachedByteArray(ms.ToArray())); _ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
} }
} }
} }

View File

@ -61,6 +61,8 @@
<TextBlock x:Name="StatusTextBlock" Text="Waiting to connect..." TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" HorizontalAlignment="Center" Visibility="Hidden"/> <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" /> <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" /> <UniformGrid x:Name="ClientLoadedSprites" Columns="6" Rows="6" MinHeight="120" HorizontalAlignment="Center" MinWidth="400" />
<TextBlock Text="Player Name:" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" HorizontalAlignment="Center"/>
<TextBox x:Name="PlayerNameBox" TextWrapping="Wrap" Text="Player" MinWidth="300" HorizontalAlignment="Center" LostFocus="PlayerNameBox_LostFocus"/>
<Image x:Name="BoardPreviewImage" MinWidth="120" MinHeight="120" HorizontalAlignment="Center" VerticalAlignment="Center"/> <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"/> <Button x:Name="ClientStartGameButton" Content="Join Game" HorizontalAlignment="Center" Background="#955FF17A" Foreground="White" Padding="5,5,5,5"/>
</StackPanel> </StackPanel>

View File

@ -28,6 +28,11 @@ namespace RBG_Server_WPF
InitializeComponent(); InitializeComponent();
} }
// ************************************************************
// ****************** Visibility Toggles **********************
// ************************************************************
#region visibility toggles
private void HostButton_Click(object sender, RoutedEventArgs e) private void HostButton_Click(object sender, RoutedEventArgs e)
{ {
// Draw host window // Draw host window
@ -55,111 +60,124 @@ namespace RBG_Server_WPF
ServerSelectPanel.Visibility = Visibility.Visible; ServerSelectPanel.Visibility = Visibility.Visible;
} }
#endregion
// ************************************************************
// *************** Client Connection Logic *******************
// ************************************************************
#region client connection logic
TcpClient client;
/// <summary>
/// Connect to server buttonm runs an asynchronous task that attempts to connect to a server,
/// and load the thumbnails from the server
/// </summary>
private void ClientServerConnectButton_Click(object sender, RoutedEventArgs e) private void ClientServerConnectButton_Click(object sender, RoutedEventArgs e)
{ {
// Run an async connection task // Run an async connection task
// This task establishes a connection, then // This task establishes a connection, then
Task clientConnect = new Task( async () => Task clientConnect = new(async () =>
{ {
TcpClient client = new TcpClient(); client = new();
try try
{ {
await client.ConnectAsync(ServerAddressConnectBox.Text, int.Parse(ServerPortConnectBox.Text)); await client.ConnectAsync(ServerAddressConnectBox.Text, int.Parse(ServerPortConnectBox.Text));
if (client.Connected) if (client.Connected)
{ {
// Invoke the display to update // Invoke the display to update
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
StatusTextBlock.Text = "Connected!"; StatusTextBlock.Text = "Connected!";
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255)); StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
}); });
// Run image downloading for the sprite // Run image downloading for the sprite
// This task is contained in the CommunicationHandler class // This task is contained in the CommunicationHandler class
Progress<CommunicationHandler.ProgressData> progress = new Progress<CommunicationHandler.ProgressData>(); Progress<CommunicationHandler.ProgressData> progress = new Progress<CommunicationHandler.ProgressData>();
Task t = App.Context.GameCommunicationHandler.InitDataLoader(client.GetStream(), progress); Task t = App.Context.GameCommunicationHandler.InitDataLoader(client.GetStream(), progress);
progress.ProgressChanged += Progress_ProgressChanged; 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 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 // We should, however, ensure that we don't make requests on client until progress is completed (which can be monitored via
// the Progress object)
} }
else else
{ {
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
StatusTextBlock.Text = "Connection Failed"; StatusTextBlock.Text = "Connection Failed";
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)); StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0));
}); });
}
} }
catch (Exception ex)
} {
catch (Exception ex) Dispatcher.Invoke(() =>
{ {
Dispatcher.Invoke(() => StatusTextBlock.Text = ex.Message[..(128 < ex.Message.Length ? 128 : ex.Message.Length)];
{ StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0));
StatusTextBlock.Text = ex.Message[..(128 < ex.Message.Length ? 128 : ex.Message.Length)]; });
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)); client?.Dispose();
}); }
client?.Dispose(); });
}
});
} }
/// <summary> /// <summary>
/// Callback that updates the UI with the new images, once downloaded /// Progress callback, that responds to changes in the state of the task
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
private void Progress_ProgressChanged(object sender, CommunicationHandler.ProgressData e) private void Progress_ProgressChanged(object sender, CommunicationHandler.ProgressData e)
{ {
// Load sprites as they arrive // Load iamges as they arrive
if (e.CurrentActivity == CommunicationHandler.ProgressData.Activity.ImageDownloaded) if (e.CurrentActivity == CommunicationHandler.ProgressData.Activity.ImageDownloaded)
{ {
// Show the user the total number of images downloaded
Dispatcher.Invoke(() => StatusTextBlock.Text = $"Downloaded {e.Progress} of {App.Context.GameCommunicationHandler.ImageList.Count} images."); Dispatcher.Invoke(() => StatusTextBlock.Text = $"Downloaded {e.Progress} of {App.Context.GameCommunicationHandler.ImageList.Count} images.");
App.Context.GameCommunicationHandler.ImageCollection.TryGetValue(e.Message, out CachedByteArray cachedByteArray); // Attempt to retrieve the image data
BitmapImage image = new(); if(App.Context.GameCommunicationHandler.ImageCollection.TryGetValue(e.Message, out CachedByteArray cachedByteArray))
image.BeginInit();
image.StreamSource = new MemoryStream(cachedByteArray, false);
image.EndInit();
Image spriteImage = new()
{ {
Source = image BitmapImage image = new();
}; image.BeginInit();
if (e.Message == App.Context.GameCommunicationHandler.BoardName) image.StreamSource = new MemoryStream(cachedByteArray, false);
{ image.EndInit();
// Image is the board image
Dispatcher.Invoke(() =>BoardPreviewImage.Source = image); if (e.Message == App.Context.GameCommunicationHandler.BoardName)
}
else
{
// Image is a sprite, load it
LoadedSpriteGrid loadedSprite = null;
foreach (LoadedSpriteGrid item in ClientLoadedSprites.Children)
{ {
if (item.Equals(e.Message)) // Set the board image to `image`
_ = Dispatcher.Invoke(() => BoardPreviewImage.Source = image);
}
else
{
// Create a new image object
Image spriteImage = new()
{ {
loadedSprite = item; Source = image
break; };
// Image is a sprite, load it
LoadedSpriteGrid loadedSprite = null;
foreach (LoadedSpriteGrid item in ClientLoadedSprites.Children)
{
// If the image already exists, replace the current image with the new one
if (item.Equals(e.Message))
{
loadedSprite = item;
// Set the image to the new loaded image
Dispatcher.Invoke(() => loadedSprite.FrameImage = spriteImage);
break;
}
}
if (loadedSprite == null)
{
loadedSprite = new LoadedSpriteGrid(spriteImage, e.Message);
// Listen to any selection event
loadedSprite.MouseDown += SpriteImage_Tapped;
loadedSprite.TouchDown += SpriteImage_Tapped;
loadedSprite.StylusDown += SpriteImage_Tapped;
// Add the loaded image into the view
Dispatcher.Invoke(() => ClientLoadedSprites.Children.Add(loadedSprite));
} }
} }
if (loadedSprite == null)
{
//spriteImage.MouseDown += SpriteImage_Tapped;
//spriteImage.TouchDown += SpriteImage_Tapped;
//spriteImage.StylusDown += SpriteImage_Tapped;
loadedSprite = new LoadedSpriteGrid(spriteImage, e.Message);
loadedSprite.MouseDown += SpriteImage_Tapped;
loadedSprite.TouchDown += SpriteImage_Tapped;
loadedSprite.StylusDown += SpriteImage_Tapped;
}
// Add the loaded image into the view
Dispatcher.Invoke(() => ClientLoadedSprites.Children.Add(loadedSprite));
} }
} }
} }
LoadedSpriteGrid currentlySelected = null; LoadedSpriteGrid currentlySelected = null;
@ -169,33 +187,67 @@ namespace RBG_Server_WPF
currentlySelected.frame.BorderThickness = new Thickness(0, 0, 0, 0); currentlySelected.frame.BorderThickness = new Thickness(0, 0, 0, 0);
currentlySelected = sender as LoadedSpriteGrid; currentlySelected = sender as LoadedSpriteGrid;
currentlySelected.frame.BorderThickness = new Thickness(3, 3, 3, 3); currentlySelected.frame.BorderThickness = new Thickness(3, 3, 3, 3);
// Finally, enable the button
CheckEnableVis();
} }
/// <summary>
/// Every check required to enable the 'Join Server' button
/// </summary>
private void CheckEnableVis()
{
if (currentlySelected != null && PlayerNameBox.Text != "" && client.Connected)
ClientStartGameButton.IsEnabled = true;
else
ClientStartGameButton.IsEnabled = false;
}
/// <summary>
/// Layout that comprises of a Border containing an Image
/// </summary>
internal class LoadedSpriteGrid : Grid internal class LoadedSpriteGrid : Grid
{ {
string imageName; string imageName;
public Border frame; public Border frame;
public Image FrameImage { get; set; }
public LoadedSpriteGrid(Image spriteImage, string imageName) public LoadedSpriteGrid(Image spriteImage, string imageName)
{ {
// Listen to events FrameImage = spriteImage;
frame = new Border(); frame = new();
frame.Child = spriteImage; frame.Child = FrameImage;
frame.BorderThickness = new Thickness(0, 0, 0, 0); frame.BorderThickness = new Thickness(0, 0, 0, 0);
frame.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 0, 100, 200)); frame.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 0, 100, 200));
Children.Add(frame); Children.Add(frame);
this.imageName = imageName; this.imageName = imageName;
} }
/// <summary>
/// Gets if the two grids are referencing the same image (regardless of the loaded mip level)
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public new bool Equals(object obj) public new bool Equals(object obj)
{ {
if (obj == null || GetType() != obj.GetType()) if (obj == null || GetType() != obj.GetType())
{ {
return false; return false;
} }
return imageName.Equals(((LoadedSpriteGrid)obj).imageName); string otherName = ((LoadedSpriteGrid)obj).imageName.Replace(App.MIP_LOW, "").Replace(App.MIP_MEDIUM, "").Replace(App.MIP_HIGH, "").Replace(App.MIP_RAW, "");
string tName = imageName.Replace(App.MIP_LOW, "").Replace(App.MIP_MEDIUM, "").Replace(App.MIP_HIGH, "").Replace(App.MIP_RAW, "");
return tName.Equals(otherName);
} }
} }
private void PlayerNameBox_LostFocus(object sender, RoutedEventArgs e)
{
CheckEnableVis();
}
#endregion
// ************************************************************
// *************** Server Connection Logic *******************
// ************************************************************
#region server connection logic
#endregion
} }
} }