Make fit for beta release (#51)

* removed

* edited a lot of stuff
This commit is contained in:
Valentin Heiserer
2024-04-26 01:41:50 +02:00
committed by GitHub
parent 2e5a42b6d3
commit 539e29dc56
94 changed files with 843 additions and 8636 deletions

View File

@@ -1,7 +1,9 @@
<script lang="ts" setup>
import MessageBoard from "./components/MessageBoard.vue";
</script>
<template>
<router-view/>
<MessageBoard></MessageBoard>
</template>
<style lang="scss">
@import "bootstrap-icons/font/bootstrap-icons.css";

View File

@@ -74,34 +74,104 @@ export enum GamePhase {
export enum MessageType {
PLAYER_CARD = "PLAYER_CARD",
START_DEDICATED_GAME = "START_DEDICATED_GAME",
JOIN_GAME = "JOIN_GAME",
JOIN_ONLINE_GAME = "JOIN_ONLINE_GAME",
LEAVE_ONLINE_GAME = "LEAVE_ONLINE_GAME",
REQUEST_SERVER_CONNECTION = "REQUEST_SERVER_CONNECTION",
CREATE_ONLINE_GAME = "CREATE_ONLINE_GAME",
LIST_ONLINE_GAMES = "LIST_ONLINE_GAMES",
UNKNOWN_ERROR = "UNKNOWN_ERROR",
INFO_MESSAGE = "INFO_MESSAGE",
GET_ONLINE_GAME = "GET_ONLINE_GAME",
SET_STATUS_READY = "SET_STATUS_READY",
GAME_STATE = "GAME_STATE",
ONLINE_PLAYER_HAND = "ONLINE_PLAYER_HAND",
SERVER_CONNECTION_SUCCESSFUL = "SERVER_CONNECTION_SUCCESSFUL",
SET_PLAYER_NAME = "SET_PLAYER_NAME",
GAME_START_READY = "GAME_START_READY",
}
// Define the interface for an array of cards
export interface CardArray {
cards: Card[];
export interface CardArrayMessage {
message_type: MessageType.ONLINE_PLAYER_HAND;
content: { cards: Card[] };
}
export interface CardObject {
card: Card;
export interface CardMessage {
message_type: MessageType.PLAYER_CARD;
content: { card: Card };
}
// Define the interface for the game state
export interface GameState {
gamePhase: GamePhase;
currentPlayer?: number;
currentPlayer?: string;
card?: Card;
color?: KartenFarbe;
trumpf?: boolean;
}
export interface GameSession {
serverName: string;
playerCount: number;
players: OnlinePlayer[];
}
export interface OnlinePlayer {
playerName: string;
isReady: boolean;
isBot?: boolean;
}
export interface GameStateMessage {
message_type: MessageType.GAME_STATE;
content: GameState;
}
export interface GameListMessage {
message_type: MessageType.LIST_ONLINE_GAMES;
content: { games: GameSession[] };
}
export interface GameInfoMessage {
message_type: MessageType.GET_ONLINE_GAME;
content: { game: GameSession };
}
export interface JoinGameMessage {
message_type: MessageType.JOIN_ONLINE_GAME;
content: { serverName: string };
}
export interface ErrorMessage {
message_type: MessageType.UNKNOWN_ERROR;
content: { error: string };
}
export interface InfoMessage {
message_type: MessageType.INFO_MESSAGE;
content: { message: string };
}
export interface EmptyMessage {
message_type: string;
content: GameState | CardArray | CardObject;
message_type: MessageType.SERVER_CONNECTION_SUCCESSFUL | MessageType.GAME_START_READY | MessageType.REQUEST_SERVER_CONNECTION;
}
export interface SetPlayerNameMessage {
message_type: MessageType.SET_PLAYER_NAME;
content: { playerName: string }
}
// Define a union type for all possible message types
export type BackendMessage = EmptyMessage
export type BackendMessage =
GameListMessage
| JoinGameMessage
| ErrorMessage
| InfoMessage
| GameInfoMessage | GameStateMessage | CardArrayMessage | CardMessage | EmptyMessage | SetPlayerNameMessage;
export enum MessageBoardType {
ERROR = "alert-error",
WARNING = "alert-warning",
INFO = "alert-info",
SUCCESS = "alert-success"
}

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import MessageComponent from "./MessageComponent.vue";
import {BackendMessage, MessageBoardType, MessageType} from "../BackendMessage.ts";
import {scg} from "ioc-service-container";
import {onMounted, ref} from "vue";
const backendConnection = scg("BackendConnection");
const socket = ref<WebSocket | null>();
const errorMessages = ref<{ message: string, type: MessageBoardType }[]>([]);
onMounted(() => {
socket.value = backendConnection.getWebSocket();
const messageListener = (message: string) => {
const message1: BackendMessage = JSON.parse(message);
if (message1.message_type === MessageType.UNKNOWN_ERROR && "error" in message1.content) {
errorMessages.value.push({message: message1.content.error, type: MessageBoardType.ERROR});
// Schedule removal for the newly added message
setTimeout(() => {
errorMessages.value.shift();
}, 3000); // Adjust 3000 to your desired delay in milliseconds
}
if (message1.message_type === MessageType.INFO_MESSAGE && "message" in message1.content) {
errorMessages.value.push({message: message1.content.message, type: MessageBoardType.INFO});
// Schedule removal for the newly added message
setTimeout(() => {
errorMessages.value.shift();
}, 3000); // Adjust 3000 to your desired delay in milliseconds
}
};
backendConnection.addMessageListener(messageListener);
});
</script>
<template>
<div class="fixed bottom-0 left-0 mx-auto px-8 py-2 w-screen flex flex-col gap-1">
<MessageComponent v-for="message in errorMessages" :message="message.message" :type="message.type">
message="Error! Task failed successfully." :type="MessageBoardType.WARNING">
</MessageComponent>
</div>
</template>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import {MessageBoardType} from "../BackendMessage.ts";
defineProps<{
message: string;
type: MessageBoardType;
}>();
</script>
<template>
<div role="alert" class="alert" :class="type">
<i class="bi bi-exclamation"></i>
<span>{{ message }}</span>
</div>
</template>
<style scoped lang="scss">
</style>

View File

@@ -7,6 +7,7 @@ import {setupService} from "./services/DependencyInjection.ts";
const routes = [
{path: '/', component: () => import('./pages/MainMenu.vue'),},
{path: '/online', component: () => import('./pages/OnlineGameList.vue'),},
{path: '/gamesession', component: () => import('./pages/GameSession.vue'),},
{path: '/localgame', component: () => import('./pages/LocalGame.vue'),},
{path: '/dedicatedgame', component: () => import('./pages/DedicatedGame.vue'),},
]
@@ -16,8 +17,7 @@ const router = createRouter({
routes,
})
const websocketIp = import.meta.env.VITE_APP_WEBSOCKET_IP;
setupService("ws://" + websocketIp + ":8080/schafkopf-events/");
setupService("ws://localhost:8080/schafkopf-events/");
const app = createApp(App)
app.use(router)

View File

@@ -3,43 +3,41 @@ import {onMounted, ref} from 'vue';
import {scg} from 'ioc-service-container';
import CardComp from '../components/CardComponent.vue';
import {BackendMessage, Card, GamePhase, GameState, MessageType} from "../BackendMessage";
import {BackendMessage, Card, GamePhase, GameSession, GameState, MessageType} from "../BackendMessage";
import {useRouter} from "vue-router";
const backendConnection = scg("BackendConnection");
const messageFromServer = ref<string[]>([]);
const gameStateText = ref<string>("Schafkopf");
const gameStateText = ref<string>("Spiel startet...");
const gameInfoText = ref<string>("");
const router = useRouter();
const socket = ref<WebSocket | null>();
const tableCards = ref<Card[]>([]);
const botCards = ref<Card[]>();
const trickCard = ref<Card>();
const gameState = ref<GameState>();
const showGameSelect = ref(true);
function startDedicated(): void {
backendConnection.sendMessage(MessageType.START_DEDICATED_GAME,);
}
function joinGame(): void {
backendConnection.sendMessage(MessageType.JOIN_GAME,);
}
const gameSession = ref<GameSession>({
serverName: "",
playerCount: 0,
players: []
});
function sendCard(cardInput: Card): void {
backendConnection.sendMessage(MessageType.PLAYER_CARD, {card: cardInput});
}
function showGameState(gamestate: GameState) {
async function showGameState(gamestate: GameState) {
switch (gamestate.gamePhase) {
case GamePhase.GAME_START:
gameStateText.value = "Spiel startet";
showGameSelect.value = false;
// botCards.value = 0;
break;
case GamePhase.TRICK_START:
gameStateText.value = "Runde startet";
@@ -48,13 +46,12 @@ function showGameState(gamestate: GameState) {
gameInfoText.value = "";
break;
case GamePhase.WAIT_FOR_CARD:
gameStateText.value = "Spieler " + gamestate.currentPlayer + " muss eine Karte legen.";
gameState.value = gamestate;
gameStateText.value = gamestate.currentPlayer + " muss eine Karte legen.";
break;
case GamePhase.PLAYER_CARD:
gameStateText.value = "Spieler " + gamestate.currentPlayer + " hat eine Karte gespielt.";
if (gamestate.currentPlayer === 0) {
// botCards.value.pop();
}
gameStateText.value = gamestate.currentPlayer + " hat eine Karte gespielt.";
if (gamestate.trumpf) {
gameInfoText.value = "TRUMPF";
} else {
@@ -65,11 +62,11 @@ function showGameState(gamestate: GameState) {
break;
case GamePhase.PLAYER_TRICK:
gameStateText.value = "Spieler " + gamestate.currentPlayer + " sticht.";
gameStateText.value = gamestate.currentPlayer + " sticht.";
trickCard.value = gamestate.card
break;
case GamePhase.GAME_STOP:
showGameSelect.value = true;
await router.push("/gamesession");
break;
default:
gameStateText.value = "Fehler";
@@ -83,32 +80,44 @@ onMounted(() => {
const messageListener = (message: string) => {
const message1: BackendMessage = JSON.parse(message);
console.log(message1)
if (message1.message_type === "GAME_STATE" && "gamePhase" in message1.content) {
if (message1.message_type === MessageType.GET_ONLINE_GAME) {
gameSession.value = message1.content.game;
console.log(message1.content)
}
if (message1.message_type === MessageType.GAME_STATE) {
console.log(message1.content)
showGameState(message1.content)
}
if (message1.message_type === "ONLINE_PLAYER_HAND" && "cards" in message1.content) {
if (message1.message_type === MessageType.ONLINE_PLAYER_HAND) {
botCards.value = message1.content.cards;
console.log(message1.content.cards)
}
};
backendConnection.addMessageListener(messageListener);
backendConnection.sendMessage(MessageType.GAME_START_READY);
backendConnection.sendMessage(MessageType.GET_ONLINE_GAME);
});
</script>
<template>
<div>
<div v-for="message in messageFromServer" :key="message">{{ message }}</div>
<div v-if="showGameSelect">
<div class="flex gap-2 place-content-center">
<button class="v-button" @click="startDedicated">Starten</button>
<button class="v-button" @click="joinGame">Join</button>
</div>
</div>
<div v-else>
<div>
<div class="flex gap-2 place-content-center">
<div class="text-sm breadcrumbs">
<ul>
<li v-for="player in gameSession.players">
<span
:class="{'text-primary': gameState!.currentPlayer === player.playerName}"
class="inline-flex gap-2 items-center">
<i v-if="!player.isBot" class="bi bi-person"></i>
<i v-else class="bi bi-robot"></i>
<p>{{ player.playerName }}</p>
</span>
</li>
</ul>
</div>
</div>
<h1 class=" top-52 text-white font-bold text-6xl absolute text-center w-full">{{ gameInfoText }}</h1>
<h1 class=" top-64 text-white font-bold text-6xl absolute text-center w-full">{{ gameStateText }}</h1>

View File

@@ -0,0 +1,112 @@
<script setup lang="ts">
import {scg} from "ioc-service-container";
import {BackendMessage, GameSession, MessageType} from "../BackendMessage.ts";
import {computed, onMounted, ref} from "vue";
import {useRouter} from "vue-router";
const backendConnection = scg("BackendConnection");
const socket = ref<WebSocket | null>();
const gameSession = ref<GameSession>({
serverName: "",
playerCount: 0,
players: []
});
const router = useRouter();
const allPlayersReady = computed(() => {
// Check if all players are ready by iterating through them
return gameSession.value.players.every(player => player.isReady);
});
onMounted(() => {
refreshGameInfo();
socket.value = backendConnection.getWebSocket();
const messageListener = async (message: string) => {
const message1: BackendMessage = JSON.parse(message);
console.log(message1)
if (message1.message_type === MessageType.GET_ONLINE_GAME && "game" in message1.content) {
gameSession.value = message1.content.game;
}
if (message1.message_type === MessageType.GAME_START_READY) {
// Resolve the Promise when the success message is received
await router.push("/dedicatedgame");
}
};
backendConnection.addMessageListener(messageListener);
});
function refreshGameInfo() {
backendConnection.sendMessage(MessageType.GET_ONLINE_GAME);
}
async function leaveGame() {
backendConnection.sendMessage(MessageType.LEAVE_ONLINE_GAME);
await router.push("/online");
}
function setStatusReady() {
backendConnection.sendMessage(MessageType.SET_STATUS_READY);
}
async function startDedicated() {
backendConnection.sendMessage(MessageType.START_DEDICATED_GAME);
const successMessageReceived = new Promise<void>((resolve) => {
const messageListener = (message: string) => {
const message1: BackendMessage = JSON.parse(message);
console.log(message)
if (message1.message_type === MessageType.GAME_START_READY) {
// Resolve the Promise when the success message is received
resolve();
}
};
backendConnection.addMessageListener(messageListener);
});
await successMessageReceived;
await router.push("/dedicatedgame");
}
</script>
<template>
<button class="btn btn-primary" @click="leaveGame()">Leave Game
</button>
<div class="flex flex-col gap-2 max-w-xl mx-auto">
<div class="flex flex-col gap-4 p-6 bg-base-200 rounded-box">
<h1 class="font-bold text-xl">{{ gameSession.serverName }}</h1>
<span>
Lorem ipsum dolor sit amet consectetur adipisicing elit In odit
</span>
<div class="flex justify-between items-center">
<span class="font-medium text-2xl">{{ gameSession.playerCount }}/4</span>
</div>
</div>
Spieler:
<div v-for="player in gameSession.players" class="flex flex-row gap-4 p-6 bg-base-200 rounded-box">
<p class="grow">{{ player.playerName }}</p>
<p v-if="player.isBot" class="text-warning"><i class="bi bi-robot"></i></p>
<p v-else-if="player.isReady" class="text-success">Bereit</p>
<p v-else class="text-error">Nicht bereit</p>
</div>
<button class="btn btn-primary" @click="setStatusReady()">Toggle Ready
</button>
<button :disabled="!allPlayersReady" class="btn btn-primary max-w-xl" @click="startDedicated()">Starten</button>
</div>
</template>
<style scoped lang="scss">
</style>

View File

@@ -6,12 +6,12 @@ import {BackendMessage, MessageType} from "../BackendMessage.ts";
const backendConnection = scg("BackendConnection");
const serverAddress = ref("10.6.9.57:8085")
const serverAddress = ref("dyn.heiserer.de:8085")
const isConnected = ref<boolean>(false);
const isPingInProgress = ref<boolean>(false);
const secondsRemaining = ref<number>(10);
const checkInterval: number = 10;
const checkInterval: number = 5;
const router = useRouter();
onBeforeMount(async () => {
@@ -58,8 +58,7 @@ async function openOnlineGameList() {
const successMessageReceived = new Promise<void>((resolve) => {
const messageListener = (message: string) => {
const message1: BackendMessage = JSON.parse(message);
console.log(message)
if (message1.message_type === "SERVER_CONNECTION_SUCCESSFUL") {
if (message1.message_type === MessageType.SERVER_CONNECTION_SUCCESSFUL) {
// Resolve the Promise when the success message is received
resolve();
}
@@ -105,7 +104,7 @@ async function openOnlineGameList() {
</div>
</div>
<a class="btn btn-primary">Spielen</a>
<button disabled class="btn btn-primary">Bald verfügbar</button>
</div>
<div class="flex flex-col gap-6 bg-base-200 rounded-box p-8">
@@ -175,7 +174,7 @@ async function openOnlineGameList() {
</div>
</div>
<a class="btn btn-primary">Spielen</a>
<button disabled class="btn btn-primary">Bald verfügbar</button>
</div>
</div>

View File

@@ -1,12 +1,92 @@
<script setup lang="ts">
import {scg} from "ioc-service-container";
import {BackendMessage, GameSession, MessageType} from "../BackendMessage.ts";
import {onMounted, ref} from "vue";
import {useRouter} from "vue-router";
const backendConnection = scg("BackendConnection");
const socket = ref<WebSocket | null>();
const gameList = ref<GameSession[]>([]);
const router = useRouter();
// Load playerName from localStorage or set default value if not present
const storedPlayerName = localStorage.getItem("playerName");
const playerName = ref<string>(storedPlayerName || "SchafkopfPlayer");
onMounted(() => {
backendConnection.sendMessage(MessageType.SET_PLAYER_NAME, {playerName: playerName.value});
refreshGameList();
socket.value = backendConnection.getWebSocket();
const messageListener = (message: string) => {
const message1: BackendMessage = JSON.parse(message);
if (message1.message_type === MessageType.LIST_ONLINE_GAMES && "games" in message1.content) {
console.log(message1)
gameList.value = message1.content.games;
}
};
backendConnection.addMessageListener(messageListener);
});
function refreshGameList() {
backendConnection.sendMessage(MessageType.LIST_ONLINE_GAMES);
}
async function createOnlineGame() {
const serverName = `Schafkopf_${new Date().getTime()}`; // Append timestamp to server name
backendConnection.sendMessage(MessageType.CREATE_ONLINE_GAME, {serverName: serverName});
await router.push("/gamesession");
}
async function joinGame(serverName: string) {
backendConnection.sendMessage(MessageType.JOIN_ONLINE_GAME, {serverName: serverName});
await router.push("/gamesession");
}
// function getServerByName(serverName: string): GameSession | undefined {
// return gameList.value.find(session => session.serverName === serverName);
// }
function sendPlayerName() {
backendConnection.sendMessage(MessageType.SET_PLAYER_NAME, {playerName: playerName.value});
localStorage.setItem("playerName", playerName.value);
}
</script>
<template>
<router-link to="/dedicatedgame">
<button class="btn btn-primary">Zum Spiel</button>
<router-link to="/">
<button class="btn btn-primary">zurück</button>
</router-link>
<button class="btn btn-primary" @click="refreshGameList()">Refresh Game
List
</button>
<input
v-model="playerName" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs"
@change="sendPlayerName()"/>
<div class="flex flex-col max-w-xl mx-auto gap-2">
<button class="btn btn-primary" @click="createOnlineGame()">Create Game</button>
<div v-for="game in gameList" :key="game.serverName" class="flex max-w-lg">
<div class="flex flex-col gap-4 p-6 bg-base-200 rounded-box">
<h1 class="font-bold text-xl">{{ game.serverName }}</h1>
<span>
Lorem ipsum dolor sit amet consectetur adipisicing elit In odit
</span>
<div class="flex justify-between items-center">
<span class="font-medium text-2xl">{{ game.playerCount }}/4</span>
<a class="btn btn-primary btn-sm" @click="joinGame(game.serverName)">Join</a>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">

View File

@@ -23,9 +23,9 @@ export class BackendConnection {
});
}
public sendMessage(messageType: MessageType, message?: any): void {
public sendMessage(messageType: MessageType, content?: any): void {
let jsonMessage;
if (message === undefined) {
if (content === undefined) {
jsonMessage = {
origin: "FRONTEND",
message: {
@@ -37,7 +37,7 @@ export class BackendConnection {
origin: "FRONTEND",
message: {
message_type: messageType,
content: message
content: content
}
};
}