Refactored and added base projects & code
This commit is contained in:
parent
8dfbba79ee
commit
9b5f08e86f
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# IDE0011: Add braces
|
||||
csharp_prefer_braces = when_multiline
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -373,3 +373,6 @@ FodyWeavers.xsd
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Ignore testing board
|
||||
TestingBoard/
|
||||
|
||||
|
6
PDGServer_WPF/App.xaml
Normal file
6
PDGServer_WPF/App.xaml
Normal file
@ -0,0 +1,6 @@
|
||||
<Application x:Class="RBG_Server.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:RBG_Server"
|
||||
StartupUri="MainWindow.xaml">
|
||||
</Application>
|
17
PDGServer_WPF/App.xaml.cs
Normal file
17
PDGServer_WPF/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace RBG_Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
10
PDGServer_WPF/AssemblyInfo.cs
Normal file
10
PDGServer_WPF/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
56
PDGServer_WPF/MainWindow.xaml
Normal file
56
PDGServer_WPF/MainWindow.xaml
Normal file
@ -0,0 +1,56 @@
|
||||
<Window x:Class="RBG_Server.WPF.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
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">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<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>
|
||||
</StackPanel>
|
||||
<Border Grid.Column="1" BorderThickness="1,1,1,1" Background="#54D3D3D3" BorderBrush="DarkGray">
|
||||
<ListView x:Name="PlayersList">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" VerticalAlignment="Center">
|
||||
<Image x:Name="PreviewImage" MinHeight="150" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||
<Grid x:Name="PreviewImageOverlay"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
290
PDGServer_WPF/MainWindow.xaml.cs
Normal file
290
PDGServer_WPF/MainWindow.xaml.cs
Normal file
@ -0,0 +1,290 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Effects;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace RBG_Server.WPF
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
GameServer gameServer;
|
||||
MemoryStream gameBoard;
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
//gameServer = new GameServer(8, 0, 9, 9, 3, 3, 3, 3, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse for file button
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void BrowseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OpenFileDialog ofd = new();
|
||||
ofd.Filter = "Image Files (.png; .jpg)|*.png;*.jpg";
|
||||
if (ofd.ShowDialog() == true)
|
||||
{
|
||||
ImageSourceTextBox.Text = ofd.FileName;
|
||||
UpdateImage();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the image when the text box looses focus
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ImageSourceTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateImage();
|
||||
}
|
||||
|
||||
private void UpdateImage()
|
||||
{
|
||||
try
|
||||
{
|
||||
using FileStream fs = File.OpenRead(ImageSourceTextBox.Text);
|
||||
gameBoard = new();
|
||||
fs.CopyTo(gameBoard); // Load into memory, so the server can also utilise the stream
|
||||
|
||||
BitmapImage gameBoardImage = new();
|
||||
gameBoardImage.BeginInit();
|
||||
gameBoardImage.StreamSource = gameBoard;
|
||||
//gameBoardImage.CacheOption = BitmapCacheOption.OnLoad; // Must preload the image into memory, before it is unloaded
|
||||
gameBoardImage.EndInit();
|
||||
PreviewImage.Source = gameBoardImage;
|
||||
RedrawGrid();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates and starts the game server
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
|
||||
private void NumberOfRows_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
StartingRow.Maximum = NumberOfRows.Value;
|
||||
ZoomBoxStartRow.Maximum = NumberOfRows.Value;
|
||||
ZoomBoxSpan.Maximum = Math.Min(NumberOfRows.Value - ZoomBoxStartRow.Value, NumberOfColumns.Value - ZoomBoxStartColumn.Value);
|
||||
RedrawGrid();
|
||||
}
|
||||
}
|
||||
|
||||
private void NumberOfColumns_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
StartingColumn.Maximum = NumberOfColumns.Value;
|
||||
ZoomBoxStartColumn.Maximum = NumberOfColumns.Value;
|
||||
ZoomBoxSpan.Maximum = Math.Min(NumberOfRows.Value - ZoomBoxStartRow.Value, NumberOfColumns.Value - ZoomBoxStartColumn.Value);
|
||||
RedrawGrid();
|
||||
}
|
||||
}
|
||||
|
||||
private void RedrawGrid()
|
||||
{
|
||||
SolidColorBrush borderBrush = new(Color.FromRgb(255, 0, 0));
|
||||
PreviewImageOverlay.RowDefinitions.Clear();
|
||||
PreviewImageOverlay.ColumnDefinitions.Clear();
|
||||
PreviewImageOverlay.Children.Clear();
|
||||
for (int i = 0; i < NumberOfColumns.Value; i++)
|
||||
{
|
||||
PreviewImageOverlay.ColumnDefinitions.Add(new ColumnDefinition());
|
||||
}
|
||||
for (int i = 0; i < NumberOfRows.Value; i++)
|
||||
{
|
||||
PreviewImageOverlay.RowDefinitions.Add(new RowDefinition());
|
||||
}
|
||||
// Draw the overlay
|
||||
Rectangle overlay = new();
|
||||
overlay.Fill = new SolidColorBrush(Color.FromArgb(128, 0, 128, 255));
|
||||
_ = PreviewImageOverlay.Children.Add(overlay);
|
||||
Grid.SetRow(overlay, (int)ZoomBoxStartRow.Value);
|
||||
Grid.SetColumn(overlay, (int)ZoomBoxStartColumn.Value);
|
||||
Grid.SetRowSpan(overlay, (int)ZoomBoxSpan.Value);
|
||||
Grid.SetColumnSpan(overlay, (int)ZoomBoxSpan.Value);
|
||||
// Draw the starting position
|
||||
overlay = new();
|
||||
overlay.Fill = new SolidColorBrush(Color.FromArgb(64, 0, 255, 128));
|
||||
_ = PreviewImageOverlay.Children.Add(overlay);
|
||||
Grid.SetRow(overlay, (int)StartingRow.Value);
|
||||
Grid.SetColumn(overlay, (int)StartingColumn.Value);
|
||||
// Draw grids onto the preview image
|
||||
for (int v = 0; v < PreviewImageOverlay.RowDefinitions.Count; v++)
|
||||
{
|
||||
for (int u = 0; u < PreviewImageOverlay.ColumnDefinitions.Count; u++)
|
||||
{
|
||||
Border border = new();
|
||||
border.BorderBrush = borderBrush;
|
||||
border.BorderThickness = new Thickness(2);
|
||||
_ = PreviewImageOverlay.Children.Add(border);
|
||||
Grid.SetRow(border, v);
|
||||
Grid.SetColumn(border, u);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates elements to go inside the game grid from the provided list of players
|
||||
/// The grid should be appropriately sized before using this
|
||||
/// </summary>
|
||||
private void GenerateGameBoard(List<Player> players)
|
||||
{
|
||||
SolidColorBrush buttonBrush = new(Color.FromArgb(1, 255, 255, 255));
|
||||
Grid[] cells = new Grid[PreviewImageOverlay.RowDefinitions.Count * PreviewImageOverlay.ColumnDefinitions.Count];
|
||||
List<Player> unaddedPlayers = players;
|
||||
for (int i = 0; i < cells.Length; i++)
|
||||
{
|
||||
cells[i] = new Grid();
|
||||
// Each cell has several components:
|
||||
// Stackpanel, which has each sprite in the cell
|
||||
UniformGrid cellStack = new();
|
||||
cellStack.Columns = 4;
|
||||
//cellStack.ItemWidth = cellStack.Width / 4;
|
||||
Queue<Player> removedPlayers = new();
|
||||
foreach (Player item in unaddedPlayers)
|
||||
{
|
||||
if ((item.Row * PreviewImageOverlay.ColumnDefinitions.Count) + item.Column == i)
|
||||
{
|
||||
removedPlayers.Enqueue(item);
|
||||
}
|
||||
}
|
||||
while (removedPlayers.Count > 0)
|
||||
{
|
||||
Player removed = removedPlayers.Dequeue();
|
||||
_ = unaddedPlayers.Remove(removed);
|
||||
_ = cellStack.Children.Add(removed);
|
||||
}
|
||||
_ = cells[i].Children.Add(cellStack);
|
||||
// Button, whose content is empty
|
||||
Button cellButton = new()
|
||||
{
|
||||
Content = ""
|
||||
};
|
||||
cellButton.Background = buttonBrush;
|
||||
cellButton.Tag = new Tuple<int, int>(i / PreviewImageOverlay.ColumnDefinitions.Count, i % PreviewImageOverlay.ColumnDefinitions.Count); // Tag is a Tuple<row, column>
|
||||
cellButton.Click += CellButton_Click;
|
||||
_ = cells[i].Children.Add(cellButton);
|
||||
_ = PreviewImageOverlay.Children.Add(cells[i]);
|
||||
Grid.SetColumn(cells[i], i % PreviewImageOverlay.ColumnDefinitions.Count);
|
||||
Grid.SetRow(cells[i], i / PreviewImageOverlay.ColumnDefinitions.Count);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents a cell on the board
|
||||
/// </summary>
|
||||
class BoardCell
|
||||
{
|
||||
// brush the button should have
|
||||
static SolidColorBrush buttonBrush = new(Color.FromArgb(1, 255, 255, 255));
|
||||
|
||||
// Each cell has a uniform grid that
|
||||
UniformGrid cellStack = new()
|
||||
{
|
||||
Columns = 4,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
Button cellButton = new()
|
||||
{
|
||||
Content = ""
|
||||
};
|
||||
Queue<Player> removedPlayers = new();
|
||||
Grid parentGrid;
|
||||
|
||||
public BoardCell(Grid parentGrid)
|
||||
{
|
||||
this.parentGrid = parentGrid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void GenerateNewGameBoard(List<Player> players)
|
||||
{
|
||||
SolidColorBrush buttonBrush = new(Color.FromArgb(1, 255, 255, 255));
|
||||
Grid[] cells = new Grid[PreviewImageOverlay.RowDefinitions.Count * PreviewImageOverlay.ColumnDefinitions.Count];
|
||||
List<Player> unaddedPlayers = players;
|
||||
for (int i = 0; i < cells.Length; i++)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void CellButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Button cellButton = sender as Button;
|
||||
Console.WriteLine("Button at {0}, {1} was clicked", ((Tuple<int, int>)cellButton.Tag).Item2, ((Tuple<int, int>)cellButton.Tag).Item1);
|
||||
}
|
||||
|
||||
private void Sliders_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
RedrawGrid();
|
||||
}
|
||||
}
|
||||
|
||||
private void GridVisibilityToggleButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PreviewImageOverlay.Visibility = PreviewImageOverlay.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private static readonly string[] sprites = new string[]
|
||||
{
|
||||
"01.png",
|
||||
"02.png",
|
||||
"03.png",
|
||||
"04.png",
|
||||
};
|
||||
private void DrawRandomizedPlayers_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
List<Player> randPlayers = new();
|
||||
Random rand = new();
|
||||
int count = rand.Next(1, 10);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Create a new player at a random location
|
||||
Player p = new("Player " + i, rand.Next(0, PreviewImageOverlay.RowDefinitions.Count), rand.Next(PreviewImageOverlay.ColumnDefinitions.Count));
|
||||
// Load the sprite
|
||||
BitmapSource pSprite = new BitmapImage(new Uri("pack://application:,,,/Sprites/" + sprites[rand.Next(0, sprites.Length)]));
|
||||
// Recolour:
|
||||
if (rand.Next(1, 4) == 1)
|
||||
{
|
||||
pSprite = RBG.Helpers.ImageProcessing.UpdatePixelColours(pSprite, 0.0, 0.0, 1.0);
|
||||
}
|
||||
p.Source = pSprite;
|
||||
randPlayers.Add(p);
|
||||
}
|
||||
|
||||
GenerateGameBoard(randPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
PDGServer_WPF/RBG Server WPF.csproj
Normal file
22
PDGServer_WPF/RBG Server WPF.csproj
Normal file
@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RBG.Helpers\RBG.Helpers.csproj" />
|
||||
<ProjectReference Include="..\RBG_Server.Core\RBG_Server.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
4
Pokemon Drinking Game/.editorconfig
Normal file
4
Pokemon Drinking Game/.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# IDE0011: Add braces
|
||||
csharp_prefer_braces = when_multiline
|
9
Pokemon Drinking Game/App.xaml
Normal file
9
Pokemon Drinking Game/App.xaml
Normal file
@ -0,0 +1,9 @@
|
||||
<Application x:Class="Pokemon_Drinking_Game.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Pokemon_Drinking_Game"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<BitmapImage x:Key="GameBoardImage" UriSource="../pokemon_v3.png" />
|
||||
</Application.Resources>
|
||||
</Application>
|
17
Pokemon Drinking Game/App.xaml.cs
Normal file
17
Pokemon Drinking Game/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Pokemon_Drinking_Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
10
Pokemon Drinking Game/AssemblyInfo.cs
Normal file
10
Pokemon Drinking Game/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
147
Pokemon Drinking Game/MainWindow.xaml
Normal file
147
Pokemon Drinking Game/MainWindow.xaml
Normal file
@ -0,0 +1,147 @@
|
||||
<Window x:Class="Pokemon_Drinking_Game.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Pokemon_Drinking_Game"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="450" Width="800" Background="Black">
|
||||
<Grid>
|
||||
<Grid x:Name="GameGrid" Background="Black" Visibility="Visible">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image x:Name="gameBoard" Source="/pokemon_v3.png" />
|
||||
<Grid x:Name="boardLayout" Margin="1,1,1,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- First moves -->
|
||||
<Button x:Name="palletTownButton" Content="" Grid.Row="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="rattataButton" Content="" Grid.Row="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="pidgeyButton" Content="" Grid.Row="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="caterpieButton" Content="" Grid.Row="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="pikachuButton" Content="" Grid.Row="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="beedrilButton" Content="" Grid.Row="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="pewterButton" Content="" Grid.Row="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="nidoranButton" Content="" Grid.Row="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="zubatButton" Content="" Grid.Row="0" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- Second Moves -->
|
||||
<Button x:Name="clefairyButton" Content="" Grid.Row="0" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="jigglypuffButton" Content="" Grid.Row="0" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="abraButton" Content="" Grid.Row="0" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="garyButton" Content="" Grid.Row="0" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="ceruleanButton" Content="" Grid.Row="0" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="slowpokeButton" Content="" Grid.Row="0" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="bellsproutButton" Content="" Grid.Row="0" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="meowthButton" Content="" Grid.Row="0" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- Third Moves -->
|
||||
<Button x:Name="diglettButton" Content="" Grid.Row="1" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="ssanneButton" Content="" Grid.Row="2" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="vermillionButton" Content="" Grid.Row="3" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="bicycleButton" Content="" Grid.Row="4" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="magikarpButton" Content="" Grid.Row="5" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="sandshrewButton" Content="" Grid.Row="6" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="pokemontowerButton" Content="" Grid.Row="7" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="channelerButton" Content="" Grid.Row="8" Grid.Column="8" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- fourth Moves -->
|
||||
<Button x:Name="haunterButton" Content="" Grid.Row="8" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="cuboneButton" Content="" Grid.Row="8" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="ghostButton" Content="" Grid.Row="8" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="abra2Button" Content="" Grid.Row="8" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="snorlaxButton" Content="" Grid.Row="8" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="gary2Button" Content="" Grid.Row="8" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="eeveeButton" Content="" Grid.Row="8" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- fifth Moves -->
|
||||
<Button x:Name="celadonButton" Content="" Grid.Row="7" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="psyduckButton" Content="" Grid.Row="6" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="evolutionButton" Content="" Grid.Row="5" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="porygonButton" Content="" Grid.Row="4" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="silphButton" Content="" Grid.Row="3" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="scientistButton" Content="" Grid.Row="2" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="laprasButton" Content="" Grid.Row="1" Grid.Column="1" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- sixth Moves -->
|
||||
<Button x:Name="rocketButton" Content="" Grid.Row="1" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="giovanniButton" Content="" Grid.Row="1" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="rarecandyButton" Content="" Grid.Row="1" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="gary3Button" Content="" Grid.Row="1" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="saffronButton" Content="" Grid.Row="1" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="hitmonsButton" Content="" Grid.Row="1" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- seventh Moves -->
|
||||
<Button x:Name="krabbyButton" Content="" Grid.Row="2" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="dittoButton" Content="" Grid.Row="3" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="doduoButton" Content="" Grid.Row="4" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="safariButton" Content="" Grid.Row="5" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="dratiniButton" Content="" Grid.Row="6" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="taurosButton" Content="" Grid.Row="7" Grid.Column="7" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- eigth Moves -->
|
||||
<Button x:Name="chanseyButton" Content="" Grid.Row="7" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="fuchsiaButton" Content="" Grid.Row="7" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="electrodeButton" Content="" Grid.Row="7" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="electabuzzButton" Content="" Grid.Row="7" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="poliwagButton" Content="" Grid.Row="7" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- ninth Moves -->
|
||||
<Button x:Name="seakingButton" Content="" Grid.Row="6" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="missingnoButton" Content="" Grid.Row="5" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="cinnabarButton" Content="" Grid.Row="4" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="koffingButton" Content="" Grid.Row="3" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="fossilButton" Content="" Grid.Row="2" Grid.Column="2" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- tenth Moves -->
|
||||
<Button x:Name="pokeballButton" Content="" Grid.Row="2" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="persianButton" Content="" Grid.Row="2" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="viridianButton" Content="" Grid.Row="2" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="fearowButton" Content="" Grid.Row="2" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- tenth Moves -->
|
||||
<Button x:Name="gravellerButton" Content="" Grid.Row="3" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="gyradosButton" Content="" Grid.Row="4" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="dragoniteButton" Content="" Grid.Row="5" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="legendbirdButton" Content="" Grid.Row="6" Grid.Column="6" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<!-- 11th Moves -->
|
||||
<Button x:Name="elitefourButton" Content="" Grid.Row="6" Grid.Column="5" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="championButton" Content="" Grid.Row="6" Grid.Column="4" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Button x:Name="masterButton" Content="" Grid.Row="6" Grid.Column="3" Background="#01000000" MouseEnter="buttons_MouseEnter" MouseLeave="buttons_MouseLeave" BorderBrush="{x:Null}"/>
|
||||
<Image x:Name="zoomPieceImage" Grid.ColumnSpan="3" Grid.Column="3" Grid.RowSpan="3" Grid.Row="3" Source="/pokemon_v3.png" />
|
||||
|
||||
<!-- Holders -->
|
||||
<StackPanel Grid.Row="8"/>
|
||||
|
||||
|
||||
</Grid>
|
||||
<StackPanel x:Name="PlayerList" Grid.Column="1"/>
|
||||
|
||||
</Grid>
|
||||
<Grid x:Name="ConnectionGrid" Background="Black" Visibility="Visible" d:IsHidden="True">
|
||||
<StackPanel Margin="0,20,0,10" HorizontalAlignment="Center">
|
||||
<TextBlock Text="Connection:" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center" Margin="0,0,0,10" FontSize="22"/>
|
||||
<TextBlock Text="Server Address:" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center"/>
|
||||
<TextBox x:Name="AddressTextBox" Text="pdgserver.kauripeak.co.nz" TextWrapping="Wrap" MinWidth="250" Margin="0,5,0,0"/>
|
||||
<TextBlock Text="Server Port:" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,0"/>
|
||||
<TextBox x:Name="PortTextBox" Text="13000" TextWrapping="Wrap" MinWidth="50" HorizontalAlignment="Center" Margin="0,5,0,0"/>
|
||||
<TextBlock Text="Player Name:" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center" Margin="0,10,0,0"/>
|
||||
<TextBox x:Name="PlayerNameTextBox" Text="Player" TextWrapping="Wrap" MinWidth="250" HorizontalAlignment="Center" Margin="0,5,0,0"/>
|
||||
<Button x:Name="ConnectButton" Content="Connect" HorizontalAlignment="Center" Margin="0,20,0,0" Click="ConnectButton_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
338
Pokemon Drinking Game/MainWindow.xaml.cs
Normal file
338
Pokemon Drinking Game/MainWindow.xaml.cs
Normal file
@ -0,0 +1,338 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
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 Pokemon_Drinking_Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
BitmapImage subImage;
|
||||
List<Player> players;
|
||||
int ourPlayerIndex;
|
||||
int currentTurn;
|
||||
Timer updateTimer;
|
||||
TcpClient client;
|
||||
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
// Load the sub image just once
|
||||
loadImage();
|
||||
players = new List<Player>();
|
||||
//TcpClient client = new TcpClient("pdgserver.kauripeak.co.nz", 13000);
|
||||
|
||||
}
|
||||
|
||||
void loadImage()
|
||||
{
|
||||
subImage = new(new Uri("pack://application:,,,/pokemon_v3.png"));
|
||||
int i = 0;
|
||||
}
|
||||
|
||||
private void buttons_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Replace center image
|
||||
|
||||
zoomPieceImage.Source = retrieveSubImage(subImage, (Button)sender);
|
||||
zoomPieceImage.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void buttons_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Hide center image
|
||||
//zoomPieceImage.Source = new BitmapImage();
|
||||
zoomPieceImage.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
CroppedBitmap retrieveSubImage(BitmapImage source, Button button)
|
||||
{
|
||||
// Get various element heights & widths
|
||||
int imageWidth = source.PixelWidth;
|
||||
int imageHight = source.PixelHeight;
|
||||
|
||||
int pixPerTile = imageWidth / 9 -1;
|
||||
|
||||
double parentHeight = ((Grid)button.Parent).ActualHeight;
|
||||
double parentWidth = ((Grid)button.Parent).ActualWidth;
|
||||
|
||||
|
||||
int row = -1;
|
||||
int col = -1;
|
||||
|
||||
// Hard coding cause its a bitch
|
||||
|
||||
if (button == palletTownButton)
|
||||
{
|
||||
col = 0;
|
||||
row = 8;
|
||||
}
|
||||
else if (button == rattataButton) { col = 0; row = 7; }
|
||||
else if (button == pidgeyButton) { col = 0; row = 6; }
|
||||
else if (button == caterpieButton) { col = 0; row = 5; }
|
||||
else if (button == pikachuButton) { col = 0; row = 4; }
|
||||
else if (button == beedrilButton) { col = 0; row = 3; }
|
||||
else if (button == pewterButton) { col = 0; row = 2; }
|
||||
else if (button == nidoranButton) { col = 0; row = 1; }
|
||||
else if (button == zubatButton) { col = 0; row = 0; }
|
||||
//
|
||||
else if (button == clefairyButton) { col = 1; row = 0; }
|
||||
else if (button == jigglypuffButton) { col = 2; row = 0; }
|
||||
else if (button == abraButton) { col = 3; row = 0; }
|
||||
else if (button == garyButton) { col = 4; row = 0; }
|
||||
else if (button == ceruleanButton) { col = 5; row = 0; }
|
||||
else if (button == slowpokeButton) { col = 6; row = 0; }
|
||||
else if (button == bellsproutButton) { col = 7; row = 0; }
|
||||
else if (button == meowthButton) { col = 8; row = 0; }
|
||||
//
|
||||
else if (button == diglettButton) { col = 8; row = 1; }
|
||||
else if (button == ssanneButton) { col = 8; row = 2; }
|
||||
else if (button == vermillionButton) { col = 8; row = 3; }
|
||||
else if (button == bicycleButton) { col = 8; row = 4; }
|
||||
else if (button == magikarpButton) { col = 8; row = 5; }
|
||||
else if (button == sandshrewButton) { col = 8; row = 6; }
|
||||
else if (button == pokemontowerButton) { col = 8; row = 7; }
|
||||
else if (button == channelerButton) { col = 8; row = 8; }
|
||||
//
|
||||
else if (button == haunterButton) { col = 7; row = 8; }
|
||||
else if (button == cuboneButton) { col = 6; row = 8; }
|
||||
else if (button == ghostButton) { col = 5; row = 8; }
|
||||
else if (button == abra2Button) { col = 4; row = 8; }
|
||||
else if (button == snorlaxButton) { col = 3; row = 8; }
|
||||
else if (button == gary2Button) { col = 2; row = 8; }
|
||||
else if (button == eeveeButton) { col = 1; row = 8; }
|
||||
//
|
||||
else if (button == celadonButton) { col = 1; row = 7; }
|
||||
else if (button == psyduckButton) { col = 1; row = 6; }
|
||||
else if (button == evolutionButton) { col = 1; row = 5; }
|
||||
else if (button == porygonButton) { col = 1; row = 4; }
|
||||
else if (button == silphButton) { col = 1; row = 3; }
|
||||
else if (button == scientistButton) { col = 1; row = 2; }
|
||||
else if (button == laprasButton) { col = 1; row = 1; }
|
||||
//
|
||||
else if (button == rocketButton) { col = 2; row = 1; }
|
||||
else if (button == giovanniButton) { col = 3; row = 1; }
|
||||
else if (button == rarecandyButton) { col = 4; row = 1; }
|
||||
else if (button == gary3Button) { col = 5; row = 1; }
|
||||
else if (button == saffronButton) { col = 6; row = 1; }
|
||||
else if (button == hitmonsButton) { col = 7; row = 1; }
|
||||
//
|
||||
else if (button == krabbyButton) { col = 7; row = 2; }
|
||||
else if (button == dittoButton) { col = 7; row = 3; }
|
||||
else if (button == doduoButton) { col = 7; row = 4; }
|
||||
else if (button == safariButton) { col = 7; row = 5; }
|
||||
else if (button == dratiniButton) { col = 7; row = 6; }
|
||||
else if (button == taurosButton) { col = 7; row = 7; }
|
||||
//
|
||||
else if (button == chanseyButton) { col = 6; row = 7; }
|
||||
else if (button == fuchsiaButton) { col = 5; row = 7; }
|
||||
else if (button == electrodeButton) { col = 4; row = 7; }
|
||||
else if (button == electabuzzButton) { col = 3; row = 7; }
|
||||
else if (button == poliwagButton) { col = 2; row = 7; }
|
||||
//
|
||||
else if (button == seakingButton) { col = 2; row = 6; }
|
||||
else if (button == missingnoButton) { col = 2; row = 5; }
|
||||
else if (button == cinnabarButton) { col = 2; row = 4; }
|
||||
else if (button == koffingButton) { col = 2; row = 3; }
|
||||
else if (button == fossilButton) { col = 2; row = 2; }
|
||||
//
|
||||
else if (button == pokeballButton) { col = 3; row = 2; }
|
||||
else if (button == persianButton) { col = 4; row = 2; }
|
||||
else if (button == viridianButton) { col = 5; row = 2; }
|
||||
else if (button == fearowButton) { col = 6; row = 2; }
|
||||
//
|
||||
else if (button == gravellerButton) { col = 6; row = 3; }
|
||||
else if (button == gyradosButton) { col = 6; row = 4; }
|
||||
else if (button == dragoniteButton) { col = 6; row = 5; }
|
||||
else if (button == legendbirdButton) { col = 6; row = 6; }
|
||||
//
|
||||
else if (button == elitefourButton) { col = 5; row = 6; }
|
||||
else if (button == championButton) { col = 4; row = 6; }
|
||||
else if (button == masterButton) { col = 3; row = 6; }
|
||||
|
||||
|
||||
|
||||
Int32Rect pixelRect = new Int32Rect(pixPerTile * col, pixPerTile * row , pixPerTile, pixPerTile);
|
||||
CroppedBitmap cb = new CroppedBitmap(source, pixelRect);
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
byte[] overflowBuffer;
|
||||
/// <summary>
|
||||
/// Server logic
|
||||
/// Called periodically (e.g. 1/10 of a second), retrieves new data from the buffer, and
|
||||
/// sends out any updates that have occured.
|
||||
///
|
||||
/// Data packets are 0xFF terminated (new command is the proceeding byte)
|
||||
/// Data terminations are 0xFE (next data type is the proceeding byte; does not apply to deterministic primative sizes)
|
||||
/// strings are expected to be sent in UTF-8 format
|
||||
///
|
||||
/// As this is all in TCP, data is guaranteed to be in the correct order
|
||||
/// </summary>
|
||||
void ClientUpdate()
|
||||
{
|
||||
// ***************************
|
||||
// **** Ensure connected ***
|
||||
// ***************************
|
||||
if (!client.Connected)
|
||||
{
|
||||
|
||||
}
|
||||
// ***************************
|
||||
// ****** Recieve Data *****
|
||||
// ***************************
|
||||
if (client.Available > 0)
|
||||
{
|
||||
int available = client.Available;
|
||||
// Internal byte array to store all awaiting bytes
|
||||
byte[] buffer = new byte[available];
|
||||
// Get the underlying networkstream, to read and write
|
||||
NetworkStream connectionStream = client.GetStream();
|
||||
connectionStream.Read(buffer, 0, available);
|
||||
|
||||
int pos = 0;
|
||||
|
||||
while (pos < available)
|
||||
{
|
||||
int command = buffer[pos] >> 4; // Get the four command bits
|
||||
ourPlayerIndex = buffer[pos++] & 0xF; // Ensure we are the correct indexed player
|
||||
|
||||
switch (command) // post-increment past the command byte
|
||||
{
|
||||
case 0: // Server queries a heartbeat response
|
||||
connectionStream.Write(new byte[] { (byte)ourPlayerIndex, 1, 0xFF });
|
||||
break;
|
||||
case 1: // Server has a board (game) update
|
||||
while (buffer[pos] != 0xFF)
|
||||
{
|
||||
// First four bits, after the command is the number of players
|
||||
int playerCount = buffer[pos] >> 4;
|
||||
// Next four are the number of players
|
||||
currentTurn = buffer[pos++] | 0xF;
|
||||
// Next
|
||||
|
||||
|
||||
// If there is a different number of players, create a new list of players
|
||||
if (players.Count != playerCount)
|
||||
{
|
||||
players = new List<Player>(playerCount);
|
||||
}
|
||||
// Next bit is a flag, denoting if the current player is a
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
UpdateUI();
|
||||
}
|
||||
// ***************************
|
||||
// ******* Send Data *******
|
||||
// ***************************
|
||||
|
||||
}
|
||||
|
||||
void UpdateUI()
|
||||
{
|
||||
Brush labelBrush = new SolidColorBrush(Color.FromRgb(255, 255, 255));
|
||||
|
||||
Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
|
||||
{
|
||||
PlayerList.Children.Clear();
|
||||
// do UI updates here
|
||||
foreach (var item in players)
|
||||
{
|
||||
Label playerLabel = new Label()
|
||||
{
|
||||
Content = item.name,
|
||||
Foreground = labelBrush
|
||||
};
|
||||
PlayerList.Children.Add(playerLabel);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void ConnectButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Do connection using props
|
||||
if (client != null)
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
client = new TcpClient(AddressTextBox.Text, Convert.ToInt32(PortTextBox.Text));
|
||||
success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
ConnectionGrid.Visibility = Visibility.Collapsed;
|
||||
GameGrid.Visibility = Visibility.Visible;
|
||||
|
||||
ourPlayerIndex = 0;
|
||||
currentTurn = 0;
|
||||
|
||||
List<byte> sendBytes = new();
|
||||
sendBytes.Add(1 << 4);
|
||||
sendBytes.AddRange(Encoding.UTF8.GetBytes(PlayerNameTextBox.Text));
|
||||
sendBytes.Add(0xFF);
|
||||
// Send through the player name
|
||||
client.GetStream().Write(sendBytes.ToArray());
|
||||
// Add listener for data
|
||||
updateTimer = new Timer((t) =>
|
||||
{
|
||||
ClientUpdate();
|
||||
});
|
||||
updateTimer.Change(100, 33);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Player
|
||||
{
|
||||
public string name;
|
||||
public int row;
|
||||
public int column;
|
||||
public long lastTime;
|
||||
|
||||
public Player(string name, int row, int column)
|
||||
{
|
||||
this.name = name;
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
this.lastTime = DateTime.Now.Ticks;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name + " (" + column + ", " + row + ")";
|
||||
}
|
||||
}
|
||||
}
|
20
Pokemon Drinking Game/Pokemon Drinking Game.csproj
Normal file
20
Pokemon Drinking Game/Pokemon Drinking Game.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<RootNamespace>Pokemon_Drinking_Game</RootNamespace>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="pokemon_v3.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="pokemon_v3.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
42
Pokemon Drinking Game/Pokemon Drinking Game.sln
Normal file
42
Pokemon Drinking Game/Pokemon Drinking Game.sln
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31515.178
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pokemon Drinking Game", "Pokemon Drinking Game.csproj", "{3BF04BFD-307C-4878-B420-47DFFAD97BE0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PDGServer", "..\PDGServer\PDGServer.csproj", "{FD6A1623-2695-4353-8B4E-7115BDCB34FD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PDGServer_WPF", "..\PDGServer_WPF\PDGServer_WPF.csproj", "{78CE20FA-E26B-4C12-9498-6EFB058586E5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F4C5002D-A70D-4B97-8BDD-F02008F4B79B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3BF04BFD-307C-4878-B420-47DFFAD97BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3BF04BFD-307C-4878-B420-47DFFAD97BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3BF04BFD-307C-4878-B420-47DFFAD97BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3BF04BFD-307C-4878-B420-47DFFAD97BE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD6A1623-2695-4353-8B4E-7115BDCB34FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD6A1623-2695-4353-8B4E-7115BDCB34FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD6A1623-2695-4353-8B4E-7115BDCB34FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD6A1623-2695-4353-8B4E-7115BDCB34FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{78CE20FA-E26B-4C12-9498-6EFB058586E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78CE20FA-E26B-4C12-9498-6EFB058586E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78CE20FA-E26B-4C12-9498-6EFB058586E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78CE20FA-E26B-4C12-9498-6EFB058586E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {35DA9C3E-6A70-4E39-85A6-1843C79A07D4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
86
RBG.Helpers/ImageProcessing.cs
Normal file
86
RBG.Helpers/ImageProcessing.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace RBG.Helpers
|
||||
{
|
||||
public class ImageProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a copy of the original bitmap with a specified per-channel colour multiplier
|
||||
/// Each channel expects a rate 0-1 (will handle other values, with unexpected results)
|
||||
/// Defaults to 1.0 for each channel (no modification)
|
||||
/// </summary>
|
||||
/// <param name="sourceBitmap">The source bitmap</param>
|
||||
/// <param name="redRate">The red-channel multiplier</param>
|
||||
/// <param name="greenRate">The green-channel multiplier</param>
|
||||
/// <param name="blueRate">The blue-channel multiplier</param>
|
||||
/// <param name="alphaRate">The alpha-channel multiplier</param>
|
||||
/// <returns></returns>
|
||||
public static BitmapSource UpdatePixelColours(BitmapSource sourceBitmap, double redRate = 1.0, double greenRate = 1.0, double blueRate = 1.0, double alphaRate = 1.0)
|
||||
{
|
||||
// Create a writeable bitmap from the source bitmap
|
||||
WriteableBitmap wbmp = new(sourceBitmap);
|
||||
// Ensure 32 bpp
|
||||
if (wbmp.Format.BitsPerPixel != 32) return null;
|
||||
// Lock the bitmap so the buffer cannot change
|
||||
wbmp.Lock();
|
||||
// Enter unsafe code (used over marshalled pointer access so that it is more performant, but has a
|
||||
// higher security risk as this is raw [but still bounded] memory access ( => data may be changed by a third party)
|
||||
// As the buffer is of a known size, and not terminated by a specific symbol, modified data in the buffer is
|
||||
// unlikely to cause a novel vulnerability in the software ( => vulnerability exists in BitmapSource, can be
|
||||
// exploited with any bitmap image being loaded)
|
||||
unsafe
|
||||
{
|
||||
// Retrieve the buffer pointer
|
||||
int* arrayptr = (int*)wbmp.BackBuffer;
|
||||
// Iterate through each pixel
|
||||
for (int i = 0; i < wbmp.PixelWidth * wbmp.PixelHeight; i++)
|
||||
{
|
||||
// Dereference the exact pixel value
|
||||
int pixel = *(arrayptr + i);
|
||||
// decompose the colour channels
|
||||
int a = (pixel >> 24) & 0xFF;
|
||||
int r = (pixel >> 16) & 0xFF;
|
||||
int g = (pixel >> 8) & 0xFF;
|
||||
int b = pixel & 0xFF;
|
||||
// Calc new values & clamp to a max of 0xFF (8 bits per channel)
|
||||
int newB = (int)Math.Min((uint)(b * blueRate), 255);
|
||||
int newG = (int)Math.Min((uint)(g * greenRate), 255);
|
||||
int newR = (int)Math.Min((uint)(r * redRate), 255);
|
||||
int newA = (int)Math.Min((uint)(a * alphaRate), 255);
|
||||
// Set the pixel to the new value
|
||||
*(arrayptr + i) = (newA << 24) | (newR << 16) | (newG << 8) | newB;
|
||||
}
|
||||
}
|
||||
// Invalidate the full current image, so that the new buffer data is fully applied
|
||||
wbmp.AddDirtyRect(new Int32Rect(0, 0, wbmp.PixelWidth, wbmp.PixelHeight));
|
||||
// Unlock the image, as everything has finished changing
|
||||
wbmp.Unlock();
|
||||
return wbmp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a cropped area of the provided bitmap
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="row"></param>
|
||||
/// <param name="col"></param>
|
||||
/// <param name="rowSize"></param>
|
||||
/// <param name="colSize"></param>
|
||||
/// <param name="colsIncluded"></param>
|
||||
/// <param name="rowsIncluded"></param>
|
||||
/// <returns></returns>
|
||||
public static BitmapSource RetrieveSubImage(BitmapSource source, int row, int col, int rowSize, int colSize, int colsIncluded = 1, int rowsIncluded = 1)
|
||||
{
|
||||
// Get number of pixels per segment
|
||||
int rowPixelsPerTile = (source.PixelWidth / rowSize) - 1;
|
||||
int colPixelsPerTile = (source.PixelHeight / colSize) - 1;
|
||||
// Create a cropping bound
|
||||
Int32Rect pixelRect = new(colPixelsPerTile * col, rowPixelsPerTile * row, colPixelsPerTile * colsIncluded, rowPixelsPerTile * rowsIncluded);
|
||||
return new CroppedBitmap(source, pixelRect);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
18
RBG.Helpers/RBG.Helpers.csproj
Normal file
18
RBG.Helpers/RBG.Helpers.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF" />
|
||||
</ItemGroup>
|
||||
</Project>
|
428
RBG_Server.Core/GameServer.cs
Normal file
428
RBG_Server.Core/GameServer.cs
Normal file
@ -0,0 +1,428 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace RBG_Server
|
||||
{
|
||||
public class GameServer
|
||||
{
|
||||
private readonly byte startRow, startColumn, rowSize, columnSize, zoomRow, zoomCol, zoomRowSpan, zoomColSpan;
|
||||
private readonly Dictionary<int, byte[]> boardImages;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new server, with the provided starting row & column
|
||||
///
|
||||
/// </summary>
|
||||
/// <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)
|
||||
{
|
||||
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;
|
||||
BitmapImage gameBoardImage = new();
|
||||
gameBoardImage.StreamSource = boardImage;
|
||||
// Hold images
|
||||
Dictionary<int, byte[]> sourceImages = new();
|
||||
// Create a JPEG encoder
|
||||
JpegBitmapEncoder encoder = new()
|
||||
{
|
||||
QualityLevel = 100,
|
||||
};
|
||||
// Add the base frame to the encoder and retrieve its byte array
|
||||
encoder.Frames.Add(BitmapFrame.Create(gameBoardImage));
|
||||
using (MemoryStream stream = new())
|
||||
{
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(-1, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
|
||||
// Add a resized version for each "common" scale
|
||||
if (gameBoardImage.PixelHeight > 2160)
|
||||
{
|
||||
double rate = 2160 / gameBoardImage.PixelHeight;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * rate, gameBoardImage.PixelHeight * rate));
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
using MemoryStream stream = new();
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(2160, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
if (gameBoardImage.PixelHeight > 1440)
|
||||
{
|
||||
double rate = 1440 / gameBoardImage.PixelHeight;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * rate, gameBoardImage.PixelHeight * rate));
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
using MemoryStream stream = new();
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(1440, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
if (gameBoardImage.PixelHeight > 1080)
|
||||
{
|
||||
double rate = 1080 / gameBoardImage.PixelHeight;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * rate, gameBoardImage.PixelHeight * rate));
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
using MemoryStream stream = new();
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(1080, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
if (gameBoardImage.PixelHeight > 720)
|
||||
{
|
||||
double rate = 720 / gameBoardImage.PixelHeight;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * rate, gameBoardImage.PixelHeight * rate));
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
using MemoryStream stream = new();
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(720, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
// Send a 240p thumbnail
|
||||
{
|
||||
double rate = 240 / gameBoardImage.PixelHeight;
|
||||
TransformedBitmap modified = new(gameBoardImage, new ScaleTransform(gameBoardImage.PixelWidth * rate, gameBoardImage.PixelHeight * rate));
|
||||
encoder.Frames.Add(BitmapFrame.Create(modified));
|
||||
using MemoryStream stream = new();
|
||||
encoder.Save(stream);
|
||||
byte[] frameData = stream.ToArray();
|
||||
sourceImages.Add(240, frameData);
|
||||
encoder.Frames.Clear();
|
||||
}
|
||||
|
||||
// add the board images to the
|
||||
boardImages = sourceImages;
|
||||
}
|
||||
|
||||
public List<Player> Players { get; } = new();
|
||||
// Map players to connections/clients
|
||||
Dictionary<TcpClient, Player> clients = new();
|
||||
// Clients that have connected, but are not yet added to the list
|
||||
ConcurrentQueue<TcpClient> awaitingAdds = new();
|
||||
|
||||
void Init(IPAddress localAddr, int port)
|
||||
{
|
||||
TcpListener listener = new(localAddr, port);
|
||||
listener.Start();
|
||||
while (true)
|
||||
{
|
||||
TcpClient client = listener.AcceptTcpClient();
|
||||
// Delegate to another thread
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
AcceptConnections(client);
|
||||
});
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Accept the client, and do the preprocessing
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
void AcceptConnections(TcpClient client)
|
||||
{
|
||||
// Ensure we send data immediately
|
||||
client.NoDelay = true;
|
||||
// In the case the client
|
||||
NetworkStream stream = client.GetStream();
|
||||
// Await the mode switch data from the client
|
||||
int command;
|
||||
do
|
||||
{
|
||||
command = stream.ReadByte();
|
||||
break;
|
||||
}
|
||||
while (stream.DataAvailable);
|
||||
if (command == 0xFD)
|
||||
{
|
||||
// Connect to game; send request
|
||||
}
|
||||
else if (command == 0xFC)
|
||||
{
|
||||
// Next byte contains the screen size
|
||||
int screenSize = stream.ReadByte() << 8 | stream.ReadByte();
|
||||
// Send three images, the low res, and the screen res, and the full res (in that order, so the client may display something
|
||||
SendImage(240, stream);
|
||||
// Send the customized screen res image
|
||||
if (screenSize <= 720)
|
||||
{
|
||||
SendImage(720, stream);
|
||||
}
|
||||
else if (screenSize <= 1080)
|
||||
{
|
||||
SendImage(1080, stream);
|
||||
}
|
||||
else if (screenSize <= 1440)
|
||||
{
|
||||
SendImage(1440, stream);
|
||||
}
|
||||
else if (screenSize <= 2160)
|
||||
{
|
||||
SendImage(2160, stream);
|
||||
}
|
||||
// Finally, send the full-screen image
|
||||
SendImage(-1, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void SendImage(int index, NetworkStream stream)
|
||||
{
|
||||
byte[] dataSize = new byte[] { (byte)(boardImages[index].Length >> 24), (byte)(boardImages[index].Length >> 16), (byte)(boardImages[index].Length >> 8), (byte)(boardImages[index].Length & 0xFF) };
|
||||
stream.Write(dataSize);
|
||||
stream.Write(boardImages[index]);
|
||||
}
|
||||
|
||||
static int currentTurn = 0;
|
||||
|
||||
void ServerUpdate()
|
||||
{
|
||||
// ***************************
|
||||
// ** Accept new connections**
|
||||
// ***************************
|
||||
while (!awaitingAdds.IsEmpty)
|
||||
{
|
||||
// try to dequeue a client
|
||||
if (awaitingAdds.TryDequeue(out TcpClient poppedClient))
|
||||
{
|
||||
// TODO:
|
||||
// Check that the player isn't reconnecting
|
||||
Player newPlayer = new("<loading>", startRow, startColumn);
|
||||
Players.Add(newPlayer);
|
||||
clients.Add(poppedClient, newPlayer);
|
||||
Console.WriteLine("New player added.");
|
||||
}
|
||||
}
|
||||
// Create a list of clients that are no longer connected, so they may be closed at the end of this
|
||||
// loop
|
||||
ConcurrentQueue<TcpClient> closedClients = new();
|
||||
|
||||
bool turnCompleted = false;
|
||||
|
||||
// ***************************
|
||||
// ***** 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);
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
currentTurn++;
|
||||
currentTurn %= Players.Count;
|
||||
}
|
||||
// ***************************
|
||||
// ** Remove old connections**
|
||||
// ***************************
|
||||
foreach (var item in closedClients)
|
||||
{
|
||||
_ = Players.Remove(clients[item]);
|
||||
_ = clients.Remove(item);
|
||||
}
|
||||
// ***************************
|
||||
// ******* Send Data *******
|
||||
// ***************************
|
||||
IReadOnlyCollection<byte> dataPacket;
|
||||
{
|
||||
List<byte> allData = new();
|
||||
allData.Add(1); // command bits; gets modulated when sent
|
||||
byte playersTurn = (byte)(Players.Count << 4 | currentTurn); // Player count & turn
|
||||
allData.Add(playersTurn);
|
||||
// Data about each player
|
||||
for (int i = 0; i < Players.Count; i++)
|
||||
{
|
||||
// Data begins with the UTF-8 formatted player-name string (and termination char)
|
||||
allData.AddRange(Encoding.UTF8.GetBytes(Players[i].PlayerName));
|
||||
allData.Add(0xFE); // EoString
|
||||
// Next data byte is the row & column the player is in
|
||||
byte pos = (byte)(Players[i].Row << 4 | Players[i].Column);
|
||||
allData.Add(pos);
|
||||
// End of player is implicit
|
||||
}
|
||||
// Finally, terminate the command
|
||||
allData.Add(0xFF);
|
||||
dataPacket = allData.AsReadOnly();
|
||||
}
|
||||
// Create a personalised data packet for each client (tells the client its order in the game)
|
||||
// Sent in parallel, to prevent a misbehaving connection from delaying everyone
|
||||
_ = Parallel.ForEach(clients, (x) =>
|
||||
{
|
||||
Player item = x.Value;
|
||||
// Alert any further ops that there is a pending data send
|
||||
if (item.ObtainLock() == 0)
|
||||
{
|
||||
List<byte> clientPacket = new(dataPacket);
|
||||
clientPacket[0] = (byte)(clientPacket[0] << 4 | Players.IndexOf(item));
|
||||
long attemptStart = DateTime.Now.Ticks;
|
||||
int attemptCount = 0;
|
||||
while (attemptCount < 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
x.Key.GetStream().Write(clientPacket.ToArray(), 0, clientPacket.Count);
|
||||
break;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
_ = Task.Delay(100);
|
||||
attemptCount++;
|
||||
}
|
||||
}
|
||||
// Reset the lock;
|
||||
item.ReleaseLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
// client hasn't recieved old data; avoid sending new state updates
|
||||
Console.WriteLine("Client is still recieving old data");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
61
RBG_Server.Core/Player.cs
Normal file
61
RBG_Server.Core/Player.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace RBG_Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Data class containing information about a player. Drawn directly to the screen, hence the inheritance
|
||||
/// of Image, which allows this entire object to be
|
||||
/// </summary>
|
||||
public class Player : Image
|
||||
{
|
||||
// C# uses implicit field definitions; i.e. declaring a property creates an implicit private field
|
||||
// Note that it is also possible to assign values, and specify access modifiers for the get & set independantly
|
||||
public string PlayerName { get; set; }
|
||||
public int Row { get; set; }
|
||||
public int Column { get; set; }
|
||||
public long LastTime { get; set; } = DateTime.Now.Ticks;
|
||||
public bool Connected { get; private set; }
|
||||
public byte[] UnhandledBuffer { get; set; }
|
||||
private int processing;
|
||||
|
||||
public int ObtainLock()
|
||||
{
|
||||
return System.Threading.Interlocked.CompareExchange(ref processing, 1, 0);
|
||||
}
|
||||
|
||||
public void ReleaseLock()
|
||||
{
|
||||
_ = System.Threading.Interlocked.Exchange(ref processing, 0);
|
||||
}
|
||||
|
||||
// public Image sprite; // Sprite is now set as the implementation of this class
|
||||
|
||||
public Player(string name, int row, int column) : base() // Call the base constructor at the same time
|
||||
{
|
||||
PlayerName = name;
|
||||
Row = row;
|
||||
Column = column;
|
||||
LastTime = DateTime.Now.Ticks;
|
||||
Connected = true;
|
||||
UnhandledBuffer = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public new bool Equals(object obj)
|
||||
{
|
||||
return (obj as Player).GetHashCode() == GetHashCode();
|
||||
|
||||
}
|
||||
|
||||
public new int GetHashCode()
|
||||
{
|
||||
int res = (base.GetHashCode() + PlayerName.GetHashCode()) >> 8; // Right-shift the original hashcode by one byte & use our row & column
|
||||
int rcByte = ((Row & 0xF) << 4) | (Column & 0xF);
|
||||
return (rcByte << 24) | res;
|
||||
}
|
||||
}
|
||||
}
|
11
RBG_Server.Core/RBG_Server.csproj
Normal file
11
RBG_Server.Core/RBG_Server.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
48
Remote Board Game.sln
Normal file
48
Remote Board Game.sln
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31515.178
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RBG Server WPF", "PDGServer_WPF\RBG Server WPF.csproj", "{E6B5F89A-2D77-46CE-8DC2-C2F99AF9B74E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pokemon Drinking Game", "Pokemon Drinking Game\Pokemon Drinking Game.csproj", "{AE1C89D8-A6F6-425A-B4C1-AEBECE850198}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RBG_Server", "RBG_Server.Core\RBG_Server.csproj", "{0C203CD4-5139-4CB2-A55D-83405B72DAEF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4B56FDC3-E973-462F-BEEC-BB33A0E3F290}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RBG.Helpers", "RBG.Helpers\RBG.Helpers.csproj", "{B3366717-065E-4025-ABCD-5B8104FE2E0E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E6B5F89A-2D77-46CE-8DC2-C2F99AF9B74E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E6B5F89A-2D77-46CE-8DC2-C2F99AF9B74E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E6B5F89A-2D77-46CE-8DC2-C2F99AF9B74E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6B5F89A-2D77-46CE-8DC2-C2F99AF9B74E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AE1C89D8-A6F6-425A-B4C1-AEBECE850198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE1C89D8-A6F6-425A-B4C1-AEBECE850198}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE1C89D8-A6F6-425A-B4C1-AEBECE850198}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AE1C89D8-A6F6-425A-B4C1-AEBECE850198}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C203CD4-5139-4CB2-A55D-83405B72DAEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C203CD4-5139-4CB2-A55D-83405B72DAEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C203CD4-5139-4CB2-A55D-83405B72DAEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C203CD4-5139-4CB2-A55D-83405B72DAEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B3366717-065E-4025-ABCD-5B8104FE2E0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B3366717-065E-4025-ABCD-5B8104FE2E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B3366717-065E-4025-ABCD-5B8104FE2E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B3366717-065E-4025-ABCD-5B8104FE2E0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {07E43435-7C22-47A1-B830-5ECFAC6F6CD9}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
x
Reference in New Issue
Block a user