Merge pull request 'developmaunt' (#5) from developmaunt into mauster
Reviewed-on: https://git.mau-mau.nl/MauMau/MauMau-Server/pulls/5
This commit was merged in pull request #5.
This commit is contained in:
@@ -1,4 +1,26 @@
|
|||||||
.idea/
|
**/.dockerignore
|
||||||
.git/
|
**/.env
|
||||||
.gitignore
|
**/.git
|
||||||
|
**/.gitea
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/.idea
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- name: Setup .NET Core
|
- name: Setup .NET Core
|
||||||
uses: actions/setup-dotnet@v3
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 8.0.x
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|||||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,8 +1,7 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
bin
|
|
||||||
obj
|
|
||||||
Properties
|
|
||||||
appsettings.Local.json
|
|
||||||
.git
|
|
||||||
*.DotSettings.user
|
|
||||||
*.sln
|
|
||||||
36
Dockerfile
36
Dockerfile
@@ -1,35 +1,23 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
USER $APP_UID
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80 443
|
EXPOSE 8080
|
||||||
|
EXPOSE 8081
|
||||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG BUILDPLATFORM
|
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY *.csproj .
|
COPY MauMau-Server.csproj .
|
||||||
RUN dotnet restore "MauMau-Server.csproj"
|
RUN dotnet restore "MauMau-Server.csproj"
|
||||||
COPY . .
|
COPY . .
|
||||||
WORKDIR "/src"
|
WORKDIR "/src"
|
||||||
RUN dotnet build "MauMau-Server.csproj" -c Release -o /app/build -a $TARGETARCH
|
RUN dotnet build "MauMau-Server.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
FROM build AS publish
|
FROM build AS publish
|
||||||
RUN dotnet publish "MauMau-Server.csproj" -c Release -o /app/publish \
|
ARG BUILD_CONFIGURATION=Release
|
||||||
--self-contained true \
|
RUN dotnet publish "MauMau-Server.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
/p:PublishTrimmed=true \
|
|
||||||
/p:PublishSingleFile=true \
|
|
||||||
-a $TARGETARCH
|
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM base AS final
|
FROM base AS final
|
||||||
ARG TARGETARCH
|
|
||||||
ARG BUILDPLATFORM
|
|
||||||
|
|
||||||
RUN adduser --disabled-password \
|
|
||||||
--home /app \
|
|
||||||
--gecos '' dotnetuser && chown -R dotnetuser /app
|
|
||||||
|
|
||||||
USER dotnetuser
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=publish /app/publish .
|
COPY --from=publish /app/publish .
|
||||||
ENTRYPOINT ["./MauMau-Server"]
|
ENTRYPOINT ["dotnet", "MauMau-Server.dll"]
|
||||||
|
|||||||
15
Mau/Card.cs
15
Mau/Card.cs
@@ -48,6 +48,21 @@ public static class CardExtensions
|
|||||||
|| playedCard.IsSameCardValue(currentCard)
|
|| playedCard.IsSameCardValue(currentCard)
|
||||||
|| playedCard.CardType == CardType.JOKER;
|
|| playedCard.CardType == CardType.JOKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsSpecialCard(this Card card)
|
||||||
|
{
|
||||||
|
return card.IsMauCard() || card.CardValue is
|
||||||
|
CardValue.SEVEN or
|
||||||
|
CardValue.EIGHT or
|
||||||
|
CardValue.JACK or
|
||||||
|
CardValue.KING or
|
||||||
|
CardValue.ACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsMauCard(this Card card)
|
||||||
|
{
|
||||||
|
return card.CardType == CardType.JOKER || card.CardValue is CardValue.TWO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CardType
|
public enum CardType
|
||||||
|
|||||||
107
Mau/Deck.cs
107
Mau/Deck.cs
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
public class Deck
|
public class Deck
|
||||||
{
|
{
|
||||||
private List<Card> _unusedDeck = new();
|
private readonly List<Card> _unusedDeck = new();
|
||||||
private List<Card> _usedDeck = new();
|
private readonly List<Card> _usedDeck = new();
|
||||||
public Card CurrentCard;
|
public Card CurrentCard { get; private set; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
@@ -13,25 +13,32 @@ public class Deck
|
|||||||
*/
|
*/
|
||||||
public Deck()
|
public Deck()
|
||||||
{
|
{
|
||||||
|
// Create a new set of cards
|
||||||
CreateSet();
|
CreateSet();
|
||||||
ShuffleDeck();
|
|
||||||
CurrentCard = DrawCard();
|
|
||||||
_usedDeck.Add(CurrentCard);
|
|
||||||
|
|
||||||
if (CurrentCard.CardType != CardType.JOKER) return;
|
// Shuffle the deck
|
||||||
CurrentCard = DrawCard();
|
ShuffleDeck();
|
||||||
_usedDeck.Add(CurrentCard);
|
|
||||||
|
// Draw the first card
|
||||||
|
var initialCard = DrawCard();
|
||||||
|
|
||||||
|
// Set the current card to the first card
|
||||||
|
CurrentCard = initialCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Adds the given card to the used cards deck.
|
* Adds the given card to the used cards deck and sets the current card to the given card.
|
||||||
* </summary>
|
* </summary>
|
||||||
* <param name="card">The card to add to the used cards deck.</param>
|
* <param name="card">The card to add to the used cards deck.</param>
|
||||||
*/
|
*/
|
||||||
public void AddCardToUsedDeck(Card card)
|
public void AddCardToUsedDeck(Card card)
|
||||||
{
|
{
|
||||||
|
// Add the card to the used deck
|
||||||
_usedDeck.Add(card);
|
_usedDeck.Add(card);
|
||||||
|
|
||||||
|
// Set the current card to the given card
|
||||||
|
CurrentCard = card;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,6 +52,41 @@ public class Deck
|
|||||||
_usedDeck.AddRange(cards);
|
_usedDeck.AddRange(cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <summary>
|
||||||
|
* Draws a card from the deck.
|
||||||
|
* If the deck is empty, the deck is reshuffled with <see cref="ReshuffleDeck"/>.
|
||||||
|
* </summary>
|
||||||
|
*/
|
||||||
|
public Card DrawCard()
|
||||||
|
{
|
||||||
|
// Check if the deck is empty, if so, reshuffle it
|
||||||
|
if (_unusedDeck.Count == 0) ReshuffleDeck();
|
||||||
|
|
||||||
|
// Grab the first card from the deck and remove it
|
||||||
|
var card = _unusedDeck[0];
|
||||||
|
_unusedDeck.RemoveAt(0);
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <summary>
|
||||||
|
* Take a given amount of cards from the deck. This method calls <see cref="DrawCard"/> for each card.
|
||||||
|
* </summary>
|
||||||
|
* <param name="amount">The amount of cards to draw from the deck.</param>
|
||||||
|
*/
|
||||||
|
public IEnumerable<Card> DrawCards(int amount)
|
||||||
|
{
|
||||||
|
// Create a list of cards and add the drawn cards to it
|
||||||
|
var cards = new List<Card>();
|
||||||
|
for (var i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
cards.Add(DrawCard());
|
||||||
|
}
|
||||||
|
return cards;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Creates a new deck of cards and adds them to the unused deck.
|
* Creates a new deck of cards and adds them to the unused deck.
|
||||||
@@ -68,36 +110,6 @@ public class Deck
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <summary>
|
|
||||||
* Draws a card from the deck.
|
|
||||||
* If the deck is empty, the deck is reshuffled with <see cref="ReshuffleDeck"/>.
|
|
||||||
* </summary>
|
|
||||||
*/
|
|
||||||
public Card DrawCard()
|
|
||||||
{
|
|
||||||
if (_unusedDeck.Count == 0) ReshuffleDeck();
|
|
||||||
var card = _unusedDeck[0];
|
|
||||||
_unusedDeck.RemoveAt(0);
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <summary>
|
|
||||||
* Take a given amount of cards from the deck. This method calls <see cref="DrawCard"/> for each card.
|
|
||||||
* </summary>
|
|
||||||
* <param name="amount">The amount of cards to draw from the deck.</param>
|
|
||||||
*/
|
|
||||||
public IEnumerable<Card> DrawCards(int amount)
|
|
||||||
{
|
|
||||||
var cards = new List<Card>();
|
|
||||||
for (var i = 0; i < amount; i++)
|
|
||||||
{
|
|
||||||
cards.Add(DrawCard());
|
|
||||||
}
|
|
||||||
return cards;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Moves all the used cards back to the unused deck and shuffles it.
|
* Moves all the used cards back to the unused deck and shuffles it.
|
||||||
@@ -106,14 +118,17 @@ public class Deck
|
|||||||
*/
|
*/
|
||||||
private void ReshuffleDeck()
|
private void ReshuffleDeck()
|
||||||
{
|
{
|
||||||
|
// Move all used cards back to the unused deck
|
||||||
_unusedDeck.AddRange(_usedDeck);
|
_unusedDeck.AddRange(_usedDeck);
|
||||||
_usedDeck.Clear();
|
_usedDeck.Clear();
|
||||||
|
|
||||||
if (_unusedDeck.Count == 0)
|
// If there are no cards left, create a new set and add it
|
||||||
|
if (!_unusedDeck.Any())
|
||||||
{
|
{
|
||||||
CreateSet();
|
CreateSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle the deck
|
||||||
ShuffleDeck();
|
ShuffleDeck();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +139,14 @@ public class Deck
|
|||||||
*/
|
*/
|
||||||
private void ShuffleDeck()
|
private void ShuffleDeck()
|
||||||
{
|
{
|
||||||
_unusedDeck = _unusedDeck.OrderBy(x => Guid.NewGuid()).ToList();
|
// Clear the unused ceck
|
||||||
|
var unusedDeckCopy = new List<Card>(_unusedDeck);
|
||||||
|
_unusedDeck.Clear();
|
||||||
|
|
||||||
|
// Shuffle the deck
|
||||||
|
unusedDeckCopy = unusedDeckCopy.OrderBy(x => Guid.NewGuid()).ToList();
|
||||||
|
|
||||||
|
// Add the shuffled deck back to the unused deck
|
||||||
|
_unusedDeck.AddRange(unusedDeckCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
132
Mau/Game.cs
132
Mau/Game.cs
@@ -1,27 +1,46 @@
|
|||||||
using MauMau_Server.Mau.GameMessages;
|
using System.Text.Json;
|
||||||
|
using MauMau_Server.Mau.GameMessages;
|
||||||
using MauMau_Server.Mau.Managers;
|
using MauMau_Server.Mau.Managers;
|
||||||
using MauMau_Server.Websockets;
|
using MauMau_Server.Websockets;
|
||||||
using MauMau_Server.Room;
|
using MauMau_Server.Room;
|
||||||
using MauMau_Server.Room.Messages;
|
using MauMau_Server.Room.Messages;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace MauMau_Server.Mau;
|
namespace MauMau_Server.Mau;
|
||||||
|
|
||||||
public class Game : RoomType
|
public class Game : RoomType
|
||||||
{
|
{
|
||||||
|
// Helpers
|
||||||
private readonly Deck _deck = new();
|
private readonly Deck _deck = new();
|
||||||
private readonly TurnManager _turnManager = new();
|
private readonly TurnManager _turnManager = new();
|
||||||
public readonly List<Card> MauCardBuffer = new();
|
|
||||||
public CardType? NextAllowedCardType { get; set; }
|
// Game state
|
||||||
|
private readonly List<Card> _mauCardBuffer = new();
|
||||||
|
private CardType? NextAllowedCardType { get; set; }
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
private const int NumberOfFaultcards = 5;
|
||||||
|
private const int NumberOfStartCards = 8;
|
||||||
|
|
||||||
public Game(Room.Room room, IEnumerable<ConnectionInstance> connections) : base(room)
|
public Game(Room.Room room, IEnumerable<ConnectionInstance> connections) : base(room)
|
||||||
{
|
{
|
||||||
|
// If the current card is a joker, set the next allowed card type to a random card type
|
||||||
|
if (_deck.CurrentCard.CardType == CardType.JOKER)
|
||||||
|
{
|
||||||
|
// In the case the random card type is a joker, try again until it is not
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var cardTypes = Enum.GetValues(typeof(CardType));
|
||||||
|
var randomIndex = new Random().Next(cardTypes.Length);
|
||||||
|
NextAllowedCardType = (CardType?)cardTypes.GetValue(randomIndex) ?? CardType.SPADES;
|
||||||
|
} while (NextAllowedCardType == CardType.JOKER);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert all the connections to players
|
// Convert all the connections to players
|
||||||
List<Player> players = new();
|
List<Player> players = new();
|
||||||
foreach (var player in connections.Select(connection => new Player(connection)))
|
foreach (var player in connections.Select(connection => new Player(connection)))
|
||||||
{
|
{
|
||||||
// Give the new player a hand of cards
|
// Give the new player a hand of cards
|
||||||
var initialHand = _deck.DrawCards(8);
|
var initialHand = _deck.DrawCards(NumberOfStartCards);
|
||||||
player.GiveCards(initialHand);
|
player.GiveCards(initialHand);
|
||||||
players.Add(player);
|
players.Add(player);
|
||||||
}
|
}
|
||||||
@@ -123,6 +142,8 @@ public class Game : RoomType
|
|||||||
*/
|
*/
|
||||||
private void Choose(Player player, string data)
|
private void Choose(Player player, string data)
|
||||||
{
|
{
|
||||||
|
// TODO: Validate if choosing a card is allowed
|
||||||
|
|
||||||
// Convert the data to a CardType, if it fails, ignore the message
|
// Convert the data to a CardType, if it fails, ignore the message
|
||||||
if (!Enum.TryParse(data, out CardType cardType))
|
if (!Enum.TryParse(data, out CardType cardType))
|
||||||
{
|
{
|
||||||
@@ -149,13 +170,12 @@ public class Game : RoomType
|
|||||||
* When there are multiple mau cards played, the player has to draw the combined amount of mau cards played.
|
* When there are multiple mau cards played, the player has to draw the combined amount of mau cards played.
|
||||||
* </summary>
|
* </summary>
|
||||||
* <param name="player">The player that drew a card</param>
|
* <param name="player">The player that drew a card</param>
|
||||||
* <param name="data">A string that can be serialized to a drawcard instance</param>
|
|
||||||
*/
|
*/
|
||||||
private void Draw(Player player)
|
private void Draw(Player player)
|
||||||
{
|
{
|
||||||
// If there are cards in the MauCardBuffer, this means there are multiple cards that need to be drawn
|
// If there are cards in the MauCardBuffer, this means there are multiple cards that need to be drawn
|
||||||
// Otherwise, just draw a single card
|
// Otherwise, just draw a single card
|
||||||
if (MauCardBuffer.Count > 0)
|
if (_mauCardBuffer.Count > 0)
|
||||||
{
|
{
|
||||||
// Count the amount of cards that need to be drawn
|
// Count the amount of cards that need to be drawn
|
||||||
var totalCards = CountMauCardBuffer();
|
var totalCards = CountMauCardBuffer();
|
||||||
@@ -178,7 +198,7 @@ public class Game : RoomType
|
|||||||
player.GiveCard(drawnCard);
|
player.GiveCard(drawnCard);
|
||||||
|
|
||||||
// Change the player if the drawn card cannot be played
|
// Change the player if the drawn card cannot be played
|
||||||
if (!drawnCard.CanBePlayedOn(_deck.CurrentCard))
|
if (!CardCanBePlayed(drawnCard))
|
||||||
{
|
{
|
||||||
_turnManager.ChangeTurnTo();
|
_turnManager.ChangeTurnTo();
|
||||||
}
|
}
|
||||||
@@ -209,7 +229,7 @@ public class Game : RoomType
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the data to a Card instance
|
// Convert the data to a Card instance
|
||||||
var cardData = JsonConvert.DeserializeObject<PlayCard>(data).ToCard();
|
var cardData = JsonSerializer.Deserialize<PlayCard>(data).ToCard();
|
||||||
|
|
||||||
// Check if the player indeed has the card they claim to have
|
// Check if the player indeed has the card they claim to have
|
||||||
var playerCard = player.TakeCardFromHand(cardData);
|
var playerCard = player.TakeCardFromHand(cardData);
|
||||||
@@ -218,42 +238,25 @@ public class Game : RoomType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is a specific card type that is allowed to be played
|
if (!CardCanBePlayed(playerCard)) return;
|
||||||
if (NextAllowedCardType != null)
|
|
||||||
{
|
|
||||||
// If the card is not the allowed card type, not the same value or a joker, ignore the message
|
|
||||||
if (playerCard.CardType != NextAllowedCardType && playerCard.CardType != CardType.JOKER && playerCard.CardValue != _deck.CurrentCard.CardValue)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Reset the allowed card type, so the next player has the normal same type and same value rules
|
|
||||||
NextAllowedCardType = null;
|
|
||||||
} else if (MauCardBuffer.Count > 0)
|
|
||||||
{
|
|
||||||
// If there are queued mau cards, the player can only another mau card (or draw)
|
|
||||||
if (playerCard.CardType != CardType.JOKER && playerCard.CardValue != CardValue.TWO)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check if the card can be played on the current card, if not, ignore the message
|
|
||||||
if (!playerCard.CanBePlayedOn(_deck.CurrentCard))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the card from the player's hand
|
// Remove the card from the player's hand
|
||||||
player.Hand.Remove(playerCard);
|
player.Hand.Remove(playerCard);
|
||||||
|
|
||||||
|
// If the player's last played card is a special card, give the player 5 fault cards
|
||||||
|
if (player.Hand.Count < 1 && playerCard.IsSpecialCard())
|
||||||
|
{
|
||||||
|
var faultCards = _deck.DrawCards(NumberOfFaultcards);
|
||||||
|
player.GiveCards(faultCards);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the card to the used deck
|
// Add the card to the used deck
|
||||||
_deck.AddCardToUsedDeck(playerCard);
|
_deck.AddCardToUsedDeck(playerCard);
|
||||||
|
|
||||||
// Set the new current card
|
// Reset the allowed card type, so the next player has the normal same type and same value rules
|
||||||
_deck.CurrentCard = playerCard;
|
NextAllowedCardType = null;
|
||||||
|
|
||||||
|
// If the player has no cards left, end the game with player as winner
|
||||||
if (player.Hand.Count == 0)
|
if (player.Hand.Count == 0)
|
||||||
{
|
{
|
||||||
EndGame(player);
|
EndGame(player);
|
||||||
@@ -280,13 +283,13 @@ public class Game : RoomType
|
|||||||
case CardValue.RED:
|
case CardValue.RED:
|
||||||
case CardValue.BLACK:
|
case CardValue.BLACK:
|
||||||
{
|
{
|
||||||
MauCardBuffer.Add(card);
|
_mauCardBuffer.Add(card);
|
||||||
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CardValue.TWO:
|
case CardValue.TWO:
|
||||||
{
|
{
|
||||||
MauCardBuffer.Add(card);
|
_mauCardBuffer.Add(card);
|
||||||
_turnManager.ChangeTurnTo();
|
_turnManager.ChangeTurnTo();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -302,6 +305,7 @@ public class Game : RoomType
|
|||||||
_turnManager.ChangeDirection();
|
_turnManager.ChangeDirection();
|
||||||
_turnManager.ChangeTurnTo();
|
_turnManager.ChangeTurnTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CardValue.JACK:
|
case CardValue.JACK:
|
||||||
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
||||||
@@ -319,6 +323,38 @@ public class Game : RoomType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <summary>
|
||||||
|
* Check if the card can be played with the current game state.
|
||||||
|
* <list type="bullet">
|
||||||
|
* <item>The player can only play a mau card if there are pending mau cards (or draw)</item>
|
||||||
|
* <item>If there is a next allowed card type, the player can only play that card type, a joker or a card with the same value as the current card</item>
|
||||||
|
* <item>Otherwise, the player can play a card that has the same type, same value or is a joker</item>
|
||||||
|
* </list>
|
||||||
|
* </summary>
|
||||||
|
* <returns>True if the given card could be played</returns>
|
||||||
|
*/
|
||||||
|
private bool CardCanBePlayed(Card card)
|
||||||
|
{
|
||||||
|
// Check if there are pending mau cards played
|
||||||
|
if (_mauCardBuffer.Count > 0)
|
||||||
|
{
|
||||||
|
// If so, the card must be a mau card
|
||||||
|
return card.IsMauCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is a next allowed card type
|
||||||
|
if (NextAllowedCardType != null)
|
||||||
|
{
|
||||||
|
// If so, the card must be the allowed card type, a joker or the same value as the current card
|
||||||
|
return card.CardType == NextAllowedCardType || card.CardType == CardType.JOKER ||
|
||||||
|
card.CardValue == _deck.CurrentCard.CardValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, use the normal rules
|
||||||
|
return card.CanBePlayedOn(_deck.CurrentCard);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Count the amount of cards that need to be drawn from the MauCardBuffer. This method also clears the buffer.
|
* Count the amount of cards that need to be drawn from the MauCardBuffer. This method also clears the buffer.
|
||||||
@@ -328,21 +364,19 @@ public class Game : RoomType
|
|||||||
private int CountMauCardBuffer()
|
private int CountMauCardBuffer()
|
||||||
{
|
{
|
||||||
var totalCards = 0;
|
var totalCards = 0;
|
||||||
foreach (var card in MauCardBuffer)
|
foreach (var card in _mauCardBuffer)
|
||||||
{
|
{
|
||||||
if (card.CardType == CardType.JOKER)
|
if (card.CardType == CardType.JOKER)
|
||||||
{
|
{
|
||||||
totalCards += 5;
|
totalCards += 5;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else if (card.CardValue == CardValue.TWO)
|
||||||
if (card.CardValue == CardValue.TWO)
|
|
||||||
{
|
{
|
||||||
totalCards += 2;
|
totalCards += 2;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MauCardBuffer.Clear();
|
|
||||||
|
_mauCardBuffer.Clear();
|
||||||
return totalCards;
|
return totalCards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,8 +390,10 @@ public class Game : RoomType
|
|||||||
{
|
{
|
||||||
foreach (var player in _turnManager.Players)
|
foreach (var player in _turnManager.Players)
|
||||||
{
|
{
|
||||||
var gameState = new GameState(player, _deck.CurrentCard, NextAllowedCardType, _turnManager.CurrentPlayer, _turnManager.Players);
|
var gameState = new GameState(player, _deck.CurrentCard, NextAllowedCardType, _turnManager.CurrentPlayer,
|
||||||
player.Connection.SendMessageAsync(JsonConvert.SerializeObject(new RoomMessage<GameState>("GAME", gameState)));
|
_turnManager.Players);
|
||||||
|
player.Connection.SendMessageAsync(
|
||||||
|
JsonSerializer.Serialize(new RoomMessage<GameState>("GAME", gameState)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +405,7 @@ public class Game : RoomType
|
|||||||
*/
|
*/
|
||||||
private void EndGame(Player winner)
|
private void EndGame(Player winner)
|
||||||
{
|
{
|
||||||
var winMessage = new EndMessage(winner.Connection.Id, winner.Connection.Name);
|
var winMessage = new EndMessage(winner.Connection);
|
||||||
_room.BroadCast(new RoomMessage<EndMessage>("END", winMessage));
|
_room.BroadCast(new RoomMessage<EndMessage>("END", winMessage));
|
||||||
_room.RoomType = new Lobby(_room);
|
_room.RoomType = new Lobby(_room);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<RootNamespace>MauMau_Server2</RootNamespace>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Hangfire.Core" Version="1.8.12" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6"/>
|
||||||
<PackageReference Include="Hangfire.MemoryStorage" Version="1.8.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
||||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.3" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.3" />
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
16
MauMau-Server.sln
Normal file
16
MauMau-Server.sln
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MauMau-Server", "MauMau-Server.csproj", "{44311559-F848-4D9B-9DB6-372042C8E6DA}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{44311559-F848-4D9B-9DB6-372042C8E6DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{44311559-F848-4D9B-9DB6-372042C8E6DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{44311559-F848-4D9B-9DB6-372042C8E6DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{44311559-F848-4D9B-9DB6-372042C8E6DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
27
Program.cs
27
Program.cs
@@ -1,30 +1,16 @@
|
|||||||
using Hangfire;
|
|
||||||
using Hangfire.MemoryStorage;
|
|
||||||
using MauMau_Server.Room;
|
using MauMau_Server.Room;
|
||||||
using MauMau_Server.Websockets;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
var services = builder.Services;
|
builder.Services.AddControllers();
|
||||||
services.AddControllers();
|
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
services.AddScoped<IRoomManager, RoomManager>();
|
builder.Services.AddScoped<IRoomManager, RoomManager>();
|
||||||
// var roomManager = services.BuildServiceProvider().GetRequiredService<IRoomManager>();
|
|
||||||
//
|
|
||||||
// services.AddHangfire((sp, config) =>
|
|
||||||
// {
|
|
||||||
// config.UseRecommendedSerializerSettings();
|
|
||||||
// config.UseMemoryStorage();
|
|
||||||
// });
|
|
||||||
// services.AddHangfireServer();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.UsePathBase("/api");
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
@@ -39,9 +25,6 @@ var webSocketOptions = new WebSocketOptions()
|
|||||||
|
|
||||||
app.UseWebSockets(webSocketOptions);
|
app.UseWebSockets(webSocketOptions);
|
||||||
|
|
||||||
// var recurringJobManager = app.Services.GetRequiredService<IRecurringJobManagerV2>();
|
|
||||||
// recurringJobManager.AddOrUpdate("1", () => roomManager.ClearGhostRooms(), Cron.Hourly);
|
|
||||||
|
|
||||||
app.UseCors(policyBuilder =>
|
app.UseCors(policyBuilder =>
|
||||||
{
|
{
|
||||||
policyBuilder.AllowAnyOrigin();
|
policyBuilder.AllowAnyOrigin();
|
||||||
@@ -50,7 +33,5 @@ app.UseCors(policyBuilder =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseRouting();
|
|
||||||
app.UseAuthorization();
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
app.Run();
|
app.Run();
|
||||||
41
Properties/launchSettings.json
Normal file
41
Properties/launchSettings.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:65148",
|
||||||
|
"sslPort": 44331
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "http://localhost:5039",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "https://localhost:7037;http://localhost:5039",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": false,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
public class ChatMessage
|
public class ChatMessage
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
public string Sender { get; set; }
|
public string Sender { get; set; }
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace MauMau_Server.Room.Messages;
|
using MauMau_Server.Websockets;
|
||||||
|
|
||||||
|
namespace MauMau_Server.Room.Messages;
|
||||||
|
|
||||||
public class EndMessage
|
public class EndMessage
|
||||||
{
|
{
|
||||||
public Guid WinnerId { get; set; }
|
public ConnectionInstance Winner { get; set; }
|
||||||
public string WinnerName { get; set; }
|
|
||||||
|
|
||||||
public EndMessage(Guid winnerId, string winnerName)
|
public EndMessage(ConnectionInstance winner)
|
||||||
{
|
{
|
||||||
WinnerId = winnerId;
|
Winner = winner;
|
||||||
WinnerName = winnerName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@ using System.Text.Json;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using MauMau_Server.Room.Messages;
|
using MauMau_Server.Room.Messages;
|
||||||
using MauMau_Server.Websockets;
|
using MauMau_Server.Websockets;
|
||||||
using Microsoft.AspNet.SignalR.Messaging;
|
|
||||||
|
|
||||||
namespace MauMau_Server.Room;
|
namespace MauMau_Server.Room;
|
||||||
|
|
||||||
@@ -11,7 +10,7 @@ public class Room
|
|||||||
{
|
{
|
||||||
private readonly IRoomManager _roomManager;
|
private readonly IRoomManager _roomManager;
|
||||||
private readonly string _roomId;
|
private readonly string _roomId;
|
||||||
public readonly List<ConnectionInstance> Connections = new();
|
public readonly List<ConnectionInstance> Connections = [];
|
||||||
public ConnectionInstance? Host;
|
public ConnectionInstance? Host;
|
||||||
public RoomType RoomType;
|
public RoomType RoomType;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Newtonsoft.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace MauMau_Server.Room;
|
namespace MauMau_Server.Room;
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ public class RoomMessage<T>
|
|||||||
public RoomMessage(string type, T data)
|
public RoomMessage(string type, T data)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Data = JsonConvert.SerializeObject(data);
|
Data = JsonSerializer.Serialize(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoomMessage()
|
public RoomMessage()
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Newtonsoft.Json;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace MauMau_Server.Websockets;
|
namespace MauMau_Server.Websockets;
|
||||||
|
|
||||||
public class ConnectionInstance
|
public class ConnectionInstance(string name, Guid id, WebSocket socket)
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; } = id;
|
||||||
public string Name { get; set; }
|
public string Name { get; set; } = name;
|
||||||
[JsonIgnore]
|
|
||||||
public WebSocket Socket { get; set; }
|
|
||||||
|
|
||||||
public ConnectionInstance(string name, Guid id, WebSocket socket)
|
[JsonIgnore]
|
||||||
{
|
public WebSocket Socket { get; set; } = socket;
|
||||||
Name = name;
|
|
||||||
Id = id;
|
|
||||||
Socket = socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
version: '3.9'
|
|
||||||
services:
|
|
||||||
server:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: 'MauMau-Server'
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "5000:5000"
|
|
||||||
networks:
|
|
||||||
- MauMau
|
|
||||||
networks:
|
|
||||||
MauMau:
|
|
||||||
driver: bridge
|
|
||||||
Reference in New Issue
Block a user