Cleaned some code; added dynamic loading of sprites
This commit is contained in:
parent
9b5f08e86f
commit
453dcd52bd
@ -4,7 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="PDG Server" Height="600" Width="800">
|
||||
Title="PDG Server" Height="768" Width="1024" Background="#FF4B4B4B">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
@ -16,30 +16,33 @@
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel>
|
||||
<TextBox x:Name="ImageSourceTextBox" Text="Source" TextWrapping="Wrap" LostFocus="ImageSourceTextBox_LostFocus"/>
|
||||
<Button x:Name="BrowseButton" Content="Browse" Height="20" Width="40" Click="BrowseButton_Click"/>
|
||||
<TextBlock Text="Number of Rows" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="NumberOfRows" IsSnapToTickEnabled="True" Minimum="1" TickPlacement="BottomRight" AutoToolTipPlacement="BottomRight" ValueChanged="NumberOfRows_ValueChanged" Value="9"/>
|
||||
<TextBlock Text="Number of Columns:" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="NumberOfColumns" IsSnapToTickEnabled="True" Minimum="1" TickPlacement="BottomRight" AutoToolTipPlacement="BottomRight" ValueChanged="NumberOfColumns_ValueChanged" Value="9"/>
|
||||
<TextBlock Text="Starting Row" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="StartingRow" IsSnapToTickEnabled="True" Value="8" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" ValueChanged="Sliders_ValueChanged" Maximum="9"/>
|
||||
<TextBlock Text="Starting Column" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="StartingColumn" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" ValueChanged="Sliders_ValueChanged" Maximum="9"/>
|
||||
<TextBlock Text="Zoom Box Starting Row" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="ZoomBoxStartRow" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Maximum="9"/>
|
||||
<TextBlock Text="Zoom Box Starting Column" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="ZoomBoxStartColumn" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Maximum="9"/>
|
||||
<TextBlock Text="Zoom Box Span" TextWrapping="Wrap" Padding="0,10,0,0"/>
|
||||
<Slider x:Name="ZoomBoxSpan" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Minimum="1" Maximum="6"/>
|
||||
<Button x:Name="GridVisibilityToggleButton" Content="Show/Hide Grid" Click="GridVisibilityToggleButton_Click"/>
|
||||
<Button x:Name="StartServerButton" Content="Start Server" HorizontalAlignment="Center" Margin="0,25,0,0" Click="StartServerButton_Click"/>
|
||||
<Button x:Name="DrawRandomizedPlayers" Content="Draw Random Players" Margin="0,25,0,0" Click="DrawRandomizedPlayers_Click"/>
|
||||
<WrapPanel Height="100">
|
||||
</WrapPanel>
|
||||
<TextBlock Text="Game Board File Path" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,5,2,0"/>
|
||||
<TextBox x:Name="ImageSourceTextBox" TextWrapping="Wrap" LostFocus="ImageSourceTextBox_LostFocus" Margin="2,5,2,0"/>
|
||||
<Button x:Name="BrowseButton" Content="Browse" Click="BrowseButton_Click" Margin="10,5,10,0"/>
|
||||
<TextBlock Text="Game Sprites Files" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<TextBox x:Name="ImageSourceTextBox_Copy" TextWrapping="Wrap" LostFocus="ImageSourceTextBox_LostFocus" Margin="2,5,2,0"/>
|
||||
<Button x:Name="GameSpritesBrowser" Content="Browse" Click="GameSpritesBrowser_Click" Margin="10,5,10,0"/>
|
||||
<TextBlock Text="Number of Rows" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="NumberOfRows" IsSnapToTickEnabled="True" Minimum="1" TickPlacement="BottomRight" AutoToolTipPlacement="BottomRight" ValueChanged="NumberOfRows_ValueChanged" Value="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Number of Columns:" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="NumberOfColumns" IsSnapToTickEnabled="True" Minimum="1" TickPlacement="BottomRight" AutoToolTipPlacement="BottomRight" ValueChanged="NumberOfColumns_ValueChanged" Value="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Starting Row" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="StartingRow" IsSnapToTickEnabled="True" Value="8" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" ValueChanged="Sliders_ValueChanged" Maximum="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Starting Column" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="StartingColumn" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" ValueChanged="Sliders_ValueChanged" Maximum="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Zoom Box Starting Row" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="ZoomBoxStartRow" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Maximum="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Zoom Box Starting Column" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="ZoomBoxStartColumn" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Maximum="9" Margin="2,0,2,0"/>
|
||||
<TextBlock Text="Zoom Box Span" TextWrapping="Wrap" Padding="0,10,0,0" Foreground="White" Margin="2,0,2,0"/>
|
||||
<Slider x:Name="ZoomBoxSpan" IsSnapToTickEnabled="True" AutoToolTipPlacement="BottomRight" TickPlacement="BottomRight" Value="3" ValueChanged="Sliders_ValueChanged" Minimum="1" Maximum="6" Margin="2,0,2,0"/>
|
||||
<Button x:Name="GridVisibilityToggleButton" Content="Show/Hide Grid" Click="GridVisibilityToggleButton_Click" Margin="10,10,10,0"/>
|
||||
<Button x:Name="StartServerButton" Content="Start Server" HorizontalAlignment="Stretch" Margin="10,25,10,0" Click="StartServerButton_Click" Background="#955FF17A" Foreground="White"/>
|
||||
<Button x:Name="DrawRandomizedPlayers" Content="Draw Random Players" Margin="10,25,10,0" Click="DrawRandomizedPlayers_Click"/>
|
||||
<UniformGrid x:Name="LoadedSprites" Columns="6" Margin="2,0,2,0" Rows="6" MinHeight="120" />
|
||||
</StackPanel>
|
||||
<Border Grid.Column="1" BorderThickness="1,1,1,1" Background="#54D3D3D3" BorderBrush="DarkGray">
|
||||
<ListView x:Name="PlayersList">
|
||||
<Border Grid.Column="1" BorderThickness="1,1,1,1" BorderBrush="DarkGray" Background="#19000000">
|
||||
<ListView x:Name="PlayersList" Background="{x:Null}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn/>
|
||||
|
@ -1,7 +1,10 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
@ -22,7 +25,6 @@ namespace RBG_Server.WPF
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
//gameServer = new GameServer(8, 0, 9, 9, 3, 3, 3, 3, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -33,7 +35,7 @@ namespace RBG_Server.WPF
|
||||
private void BrowseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog ofd = new();
|
||||
ofd.Filter = "Image Files (.png; .jpg)|*.png;*.jpg";
|
||||
ofd.Filter = "Image Files|*.png;*.jpg";
|
||||
if (ofd.ShowDialog() == true)
|
||||
{
|
||||
ImageSourceTextBox.Text = ofd.FileName;
|
||||
@ -81,7 +83,7 @@ namespace RBG_Server.WPF
|
||||
/// <param name="e"></param>
|
||||
private void StartServerButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
gameServer = new((int)StartingRow.Value, (int)StartingColumn.Value, (int)NumberOfRows.Value, (int)NumberOfColumns.Value, (int)ZoomBoxStartRow.Value, (int)ZoomBoxStartColumn.Value, (int)ZoomBoxSpan.Value, (int)ZoomBoxSpan.Value, gameBoard);
|
||||
gameServer = new((byte)StartingRow.Value, (byte)StartingColumn.Value, (byte)NumberOfRows.Value, (byte)NumberOfColumns.Value, (byte)ZoomBoxStartRow.Value, (byte)ZoomBoxStartColumn.Value, (byte)ZoomBoxSpan.Value, (byte)ZoomBoxSpan.Value, gameBoard);
|
||||
}
|
||||
|
||||
|
||||
@ -285,6 +287,68 @@ namespace RBG_Server.WPF
|
||||
|
||||
GenerateGameBoard(randPlayers);
|
||||
}
|
||||
|
||||
ConcurrentDictionary<string, MemoryStream> loadedSprites = new();
|
||||
Task loadingFiles;
|
||||
|
||||
private void GameSpritesBrowser_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog ofd = new();
|
||||
ofd.Filter = "Image Files|*.png;*.jpg";
|
||||
ofd.Multiselect = true;
|
||||
if (ofd.ShowDialog() == true)
|
||||
{
|
||||
string[] resultFiles = ofd.FileNames;
|
||||
loadedSprites.Clear();
|
||||
// Run the following work in a separate thread
|
||||
loadingFiles = Task.Run(() =>
|
||||
{
|
||||
// Continue in parallel
|
||||
_ = Parallel.ForEach(resultFiles, (file) =>
|
||||
{
|
||||
MemoryStream ms = new();
|
||||
using FileStream fs = File.OpenRead(file);
|
||||
|
||||
if (new FileInfo(file).Length > 512e6) // greater than 512 kB; resize the sprite to something more reasonable
|
||||
{
|
||||
BitmapImage gameBoardImage = new();
|
||||
gameBoardImage.BeginInit();
|
||||
gameBoardImage.StreamSource = fs;
|
||||
gameBoardImage.CacheOption = BitmapCacheOption.Default;
|
||||
gameBoardImage.EndInit();
|
||||
double vRate = 128 / (double)gameBoardImage.PixelHeight; // Resize so the largest dimension is 128 px
|
||||
double hRate = 128 / (double)gameBoardImage.PixelWidth;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * Math.Min(vRate, hRate), gameBoardImage.PixelHeight * Math.Min(vRate, hRate)));
|
||||
PngBitmapEncoder encoder = new();
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
encoder.Save(ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.CopyTo(ms);
|
||||
}
|
||||
_ = loadedSprites.TryAdd(file, ms);
|
||||
});
|
||||
// Invoke the dispatcher to add all of the sprites to the loaded sprites list
|
||||
_ = Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
|
||||
{
|
||||
LoadedSprites.Children.Clear();
|
||||
foreach (KeyValuePair<string, MemoryStream> item in loadedSprites)
|
||||
{
|
||||
BitmapImage image = new();
|
||||
image.BeginInit();
|
||||
image.StreamSource = item.Value;
|
||||
image.EndInit();
|
||||
Image spriteImage = new()
|
||||
{
|
||||
Source = image
|
||||
};
|
||||
_ = LoadedSprites.Children.Add(spriteImage);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,16 +27,16 @@ namespace RBG_Server
|
||||
/// <param name="startRow">The starting row of the board</param>
|
||||
/// <param name="startColumn">The starting column of the board</param>
|
||||
/// <param name="boardImage">The full-scale board image</param>
|
||||
public GameServer(int startRow, int startColumn, int rowSize, int columnSize, int zoomRow, int zoomCol, int zoomRowSpan, int zoomColSpan, Stream boardImage)
|
||||
public GameServer(byte startRow, byte startColumn, byte rowSize, byte columnSize, byte zoomRow, byte zoomCol, byte zoomRowSpan, byte zoomColSpan, Stream boardImage)
|
||||
{
|
||||
this.startRow = (byte)startRow;
|
||||
this.startColumn = (byte)startColumn;
|
||||
this.rowSize = (byte)rowSize;
|
||||
this.columnSize = (byte)columnSize;
|
||||
this.zoomRow = (byte)zoomRow;
|
||||
this.zoomCol = (byte)zoomCol;
|
||||
this.zoomRowSpan = (byte)zoomRowSpan;
|
||||
this.zoomColSpan = (byte)zoomColSpan;
|
||||
this.startRow = startRow;
|
||||
this.startColumn = startColumn;
|
||||
this.rowSize = rowSize;
|
||||
this.columnSize = columnSize;
|
||||
this.zoomRow = zoomRow;
|
||||
this.zoomCol = zoomCol;
|
||||
this.zoomRowSpan = zoomRowSpan;
|
||||
this.zoomColSpan = zoomColSpan;
|
||||
BitmapImage gameBoardImage = new();
|
||||
gameBoardImage.StreamSource = boardImage;
|
||||
// Hold images
|
||||
@ -194,7 +194,7 @@ namespace RBG_Server
|
||||
stream.Write(boardImages[index]);
|
||||
}
|
||||
|
||||
static int currentTurn = 0;
|
||||
static int currentTurn;
|
||||
|
||||
void ServerUpdate()
|
||||
{
|
||||
@ -224,132 +224,132 @@ namespace RBG_Server
|
||||
// ***** Recieve Data *****
|
||||
// ***************************
|
||||
// Data are recieved in parallel, so that it may be processed quickly
|
||||
Parallel.ForEach(clients, (item) =>
|
||||
{
|
||||
Player player = item.Value;
|
||||
if (!item.Key.Connected)
|
||||
{
|
||||
// Client no longer connected, add to the removed list
|
||||
closedClients.Enqueue(item.Key);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Game logic
|
||||
// If there are available bytes to be read, we can process them
|
||||
if (item.Key.Available > 0)
|
||||
{
|
||||
// Get number of bytes
|
||||
int availableBytes = item.Key.Available;
|
||||
// Store read bytes in an array
|
||||
byte[] receivedBytes = new byte[player.UnhandledBuffer.Length + availableBytes];
|
||||
// Grab the stream to read from/write to
|
||||
NetworkStream clientStream = item.Key.GetStream();
|
||||
// read the buffer to the end
|
||||
clientStream.Read(receivedBytes, player.UnhandledBuffer.Length, availableBytes);
|
||||
_ = Parallel.ForEach(clients, (item) =>
|
||||
{
|
||||
Player player = item.Value;
|
||||
if (!item.Key.Connected)
|
||||
{
|
||||
// Client no longer connected, add to the removed list
|
||||
closedClients.Enqueue(item.Key);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Game logic
|
||||
// If there are available bytes to be read, we can process them
|
||||
if (item.Key.Available > 0)
|
||||
{
|
||||
// Get number of bytes
|
||||
int availableBytes = item.Key.Available;
|
||||
// Store read bytes in an array
|
||||
byte[] receivedBytes = new byte[player.UnhandledBuffer.Length + availableBytes];
|
||||
// Grab the stream to read from/write to
|
||||
NetworkStream clientStream = item.Key.GetStream();
|
||||
// read the buffer to the end
|
||||
_ = clientStream.Read(receivedBytes, player.UnhandledBuffer.Length, availableBytes);
|
||||
|
||||
// Copy the unhandled buffer to the recieved bytes
|
||||
player.UnhandledBuffer.CopyTo(receivedBytes, 0);
|
||||
// Reset the unhandled array
|
||||
player.UnhandledBuffer = Array.Empty<byte>();
|
||||
// Copy the unhandled buffer to the recieved bytes
|
||||
player.UnhandledBuffer.CopyTo(receivedBytes, 0);
|
||||
// Reset the unhandled array
|
||||
player.UnhandledBuffer = Array.Empty<byte>();
|
||||
|
||||
int pos = 0;
|
||||
// While we still haven't reached the end of the buffer, read bytes
|
||||
while (pos < receivedBytes.Length)
|
||||
{
|
||||
if (pos == receivedBytes.Length - 1)
|
||||
{
|
||||
player.UnhandledBuffer = new byte[] { receivedBytes[^1] };
|
||||
break;
|
||||
}
|
||||
int command = receivedBytes[pos] >> 4; // Get the four command bits
|
||||
if ((receivedBytes[pos++] & 0xF) != Players.IndexOf(item.Value))
|
||||
{
|
||||
Console.WriteLine("Unexpected client ID: {0}", (receivedBytes[pos++] & 0xF));
|
||||
}
|
||||
int pos = 0;
|
||||
// While we still haven't reached the end of the buffer, read bytes
|
||||
while (pos < receivedBytes.Length)
|
||||
{
|
||||
if (pos == receivedBytes.Length - 1)
|
||||
{
|
||||
player.UnhandledBuffer = new byte[] { receivedBytes[^1] };
|
||||
break;
|
||||
}
|
||||
int command = receivedBytes[pos] >> 4; // Get the four command bits
|
||||
if ((receivedBytes[pos++] & 0xF) != Players.IndexOf(item.Value))
|
||||
{
|
||||
Console.WriteLine("Unexpected client ID: {0}", (receivedBytes[pos++] & 0xF));
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case 0: // Heartbeat from client {0x0, 0x1, 0xFF}
|
||||
// In case of buffer overflow, take the last command and paste it into
|
||||
// the unhandled buffer
|
||||
if (pos + 2 > receivedBytes.Length)
|
||||
{
|
||||
player.UnhandledBuffer = new byte[receivedBytes.Length - pos + 1];
|
||||
for (int i = 0; i < receivedBytes.Length - pos + 1; i++)
|
||||
{
|
||||
player.UnhandledBuffer[i] = receivedBytes[(pos - 1) + i];
|
||||
}
|
||||
// Finally, set the pos to the end of the buffer
|
||||
pos = receivedBytes.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer won't overflow, process normally
|
||||
player.LastTime = DateTime.Now.Ticks;
|
||||
pos += 2; // Move two bytes
|
||||
}
|
||||
break;
|
||||
case 1: // Player sets name
|
||||
List<byte> strBytes = new();
|
||||
bool endReached = false;
|
||||
while (pos < receivedBytes.Length && receivedBytes[pos] != 0xFF)
|
||||
{
|
||||
byte nextByte = receivedBytes[pos++];
|
||||
if (pos != receivedBytes.Length - 1 && receivedBytes[pos + 1] == 0xFF)
|
||||
{
|
||||
endReached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
strBytes.Add(nextByte);
|
||||
}
|
||||
}
|
||||
if (endReached)
|
||||
{
|
||||
// Buffer contained full string, move to the next command
|
||||
player.PlayerName = Encoding.UTF8.GetString(strBytes.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
player.UnhandledBuffer = new byte[receivedBytes.Length - strBytes.Count + 1];
|
||||
for (int i = 0; i < receivedBytes.Length - strBytes.Count + 1; i++)
|
||||
{
|
||||
player.UnhandledBuffer[i] = receivedBytes[(strBytes.Count - 1) + i];
|
||||
}
|
||||
// Pos is implicitely
|
||||
}
|
||||
break;
|
||||
case 2: // update player position
|
||||
if (Players[currentTurn].Equals(player))
|
||||
{
|
||||
// It is our turn, move
|
||||
byte nextByte = receivedBytes[pos++];
|
||||
int row = nextByte >> 4;
|
||||
int column = nextByte & 0xF;
|
||||
player.Column = column;
|
||||
player.Row = row;
|
||||
// Can't update turn until we are synchronised, else we would
|
||||
// inadvertently accept turns from the next player
|
||||
turnCompleted = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Unknown client command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we haven't recieved data from this client for some time, send a packet that requests
|
||||
// a response
|
||||
else if (TimeSpan.FromTicks(DateTime.Now.Ticks - item.Value.LastTime) > TimeSpan.FromSeconds(5))
|
||||
{
|
||||
item.Key.GetStream().Write(new byte[] { (byte)(Players.IndexOf(item.Value)), 0xFF }); // Heartbeat is 0x0, 0x1
|
||||
Player curr = item.Value;
|
||||
curr.LastTime = DateTime.Now.Ticks;
|
||||
}
|
||||
}
|
||||
});
|
||||
switch (command)
|
||||
{
|
||||
case 0: // Heartbeat from client {0x0, 0x1, 0xFF}
|
||||
// In case of buffer overflow, take the last command and paste it into
|
||||
// the unhandled buffer
|
||||
if (pos + 2 > receivedBytes.Length)
|
||||
{
|
||||
player.UnhandledBuffer = new byte[receivedBytes.Length - pos + 1];
|
||||
for (int i = 0; i < receivedBytes.Length - pos + 1; i++)
|
||||
{
|
||||
player.UnhandledBuffer[i] = receivedBytes[(pos - 1) + i];
|
||||
}
|
||||
// Finally, set the pos to the end of the buffer
|
||||
pos = receivedBytes.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer won't overflow, process normally
|
||||
player.LastTime = DateTime.Now.Ticks;
|
||||
pos += 2; // Move two bytes
|
||||
}
|
||||
break;
|
||||
case 1: // Player sets name
|
||||
List<byte> strBytes = new();
|
||||
bool endReached = false;
|
||||
while (pos < receivedBytes.Length && receivedBytes[pos] != 0xFF)
|
||||
{
|
||||
byte nextByte = receivedBytes[pos++];
|
||||
if (pos != receivedBytes.Length - 1 && receivedBytes[pos + 1] == 0xFF)
|
||||
{
|
||||
endReached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
strBytes.Add(nextByte);
|
||||
}
|
||||
}
|
||||
if (endReached)
|
||||
{
|
||||
// Buffer contained full string, move to the next command
|
||||
player.PlayerName = Encoding.UTF8.GetString(strBytes.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
player.UnhandledBuffer = new byte[receivedBytes.Length - strBytes.Count + 1];
|
||||
for (int i = 0; i < receivedBytes.Length - strBytes.Count + 1; i++)
|
||||
{
|
||||
player.UnhandledBuffer[i] = receivedBytes[(strBytes.Count - 1) + i];
|
||||
}
|
||||
// Pos is implicitely
|
||||
}
|
||||
break;
|
||||
case 2: // update player position
|
||||
if (Players[currentTurn].Equals(player))
|
||||
{
|
||||
// It is our turn, move
|
||||
byte nextByte = receivedBytes[pos++];
|
||||
int row = nextByte >> 4;
|
||||
int column = nextByte & 0xF;
|
||||
player.Column = column;
|
||||
player.Row = row;
|
||||
// Can't update turn until we are synchronised, else we would
|
||||
// inadvertently accept turns from the next player
|
||||
turnCompleted = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Unknown client command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we haven't recieved data from this client for some time, send a packet that requests
|
||||
// a response
|
||||
else if (TimeSpan.FromTicks(DateTime.Now.Ticks - item.Value.LastTime) > TimeSpan.FromSeconds(5))
|
||||
{
|
||||
item.Key.GetStream().Write(new byte[] { (byte)Players.IndexOf(item.Value), 0xFF }); // Heartbeat is 0x0, 0x1
|
||||
Player curr = item.Value;
|
||||
curr.LastTime = DateTime.Now.Ticks;
|
||||
}
|
||||
}
|
||||
});
|
||||
// Synchronised, update player turn
|
||||
if (turnCompleted)
|
||||
{
|
||||
@ -359,7 +359,7 @@ namespace RBG_Server
|
||||
// ***************************
|
||||
// ** Remove old connections**
|
||||
// ***************************
|
||||
foreach (var item in closedClients)
|
||||
foreach (TcpClient item in closedClients)
|
||||
{
|
||||
_ = Players.Remove(clients[item]);
|
||||
_ = clients.Remove(item);
|
||||
|
Loading…
x
Reference in New Issue
Block a user