Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SH-70 Implement survival prediction for not kicked players #50

Merged
merged 10 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
libs/common/src/database/prisma/migrations
libs/common/src/database/prisma/generated

test.ts

# Database
data/

Expand Down
4 changes: 2 additions & 2 deletions apps/shelter-client/src/libs/loader.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import '../styles/Loader.scss';
import { Triangle } from 'react-loader-spinner';

const Loader = () => {
const Loader = (props: { color?: string }) => {
return (
<div className="loader-container">
<Triangle
visible={true}
height="80"
width="80"
color="#fac978"
color={props.color || '#fac978'}
ariaLabel="triangle-loading"
wrapperStyle={{}}
wrapperClass=""
Expand Down
67 changes: 61 additions & 6 deletions apps/shelter-client/src/pages/Room.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { updateLobby } from '../redux/reducers/lobbySlice';
import shelterIcon from '../assets/images/shelter-icon.png';
import catastropheIcon from '../assets/images/catastrophe-icon.png';
import Timer from '../components/Timer';
import Loader from '../libs/loader';

interface IState {
isCameraOn: boolean;
Expand All @@ -42,6 +43,7 @@ interface IState {
maxClients: number;
kickedPlayers: any[];
isDescriptionOpened: boolean;
isPredictionOpened: boolean;
modalProps: any;
isOponentsListFocused: boolean;
focusData: any; // sets on isOponentsListFocused
Expand Down Expand Up @@ -115,6 +117,7 @@ const RoomPage = () => {
kickedPlayers: [],
maxClients: 4,
isDescriptionOpened: false,
isPredictionOpened: false,
isOponentsListFocused: false,
modalProps: {
type: '',
Expand Down Expand Up @@ -150,6 +153,7 @@ const RoomPage = () => {
revealPlayerId: data.revealPlayerId,
timer: data.timer,
timerEndTime: data.timerEndTime,
finalPrediction: data.finalPrediction,
}),
);

Expand Down Expand Up @@ -198,6 +202,17 @@ const RoomPage = () => {
// on finish game
if (data.hasFinished) {
tipStr = 'Game over!';
dispatch(
updateLobby({
hasFinished: data.hasFinished,
}),
);
}

if (data.finalPrediction) {
updateState({
isPredictionOpened: true,
});
}

updateState({
Expand Down Expand Up @@ -316,6 +331,11 @@ const RoomPage = () => {
updateState({ isOponentsListFocused: false, focusData: {} });
}
};
const handleOpenPreditionModal = (isOpened: boolean) => {
updateState({
isPredictionOpened: isOpened,
});
};

// COMPONENTS
const OponentsList = () => {
Expand Down Expand Up @@ -439,7 +459,6 @@ const RoomPage = () => {
const handleEndTurn = () => {
if (state.uRemainedChars !== 0) {
for (let i = 0; i < state.uRemainedChars; i++) {
console.log('handleCharRevial in handleEndTurn, i:', i);
const notRevealedChars = lobby.characteristics[user.userId!].filter(
(_: { isRevealed: boolean }) => _.isRevealed !== true,
);
Expand Down Expand Up @@ -485,20 +504,33 @@ const RoomPage = () => {
</div>
</div>
)}
{(!lobby.hasStarted || lobby.hasFinished) && (
{!lobby.hasStarted && (
<div>
<div className="divider"></div>
<div>
{state.isOrganizator ? (
<button className="start-game-btn" onClick={handleGameStart}>
{lobby.hasFinished ? 'RESTART' : 'START GAME'}
{'START GAME'}
</button>
) : (
<div>Waiting for organizator</div>
)}
</div>
</div>
)}
{lobby.hasFinished && (
<div>
<div className="divider"></div>
<div>
<button
className="start-game-btn"
onClick={() => updateState({ isPredictionOpened: true })}
>
SHOW PREDICTION
</button>
</div>
</div>
)}
</div>
);
};
Expand All @@ -511,7 +543,28 @@ const RoomPage = () => {
updateState({ isOponentsListFocused: false });
}}
></div>
{state.isDescriptionOpened ? (
{state.isPredictionOpened && (
<ModalWindow handleOpenModal={handleOpenPreditionModal}>
<div className="modal-info-wrapper">
<div className="info-title">
<h3>Final prediction</h3>
</div>
<div className={`modal-info`}>
<div className="description">
{lobby.finalPrediction ? (
<p>{lobby.finalPrediction}</p>
) : (
<div className="prediction-loader">
<Loader color="#000" />
Already in process
</div>
)}
</div>
</div>
</div>
</ModalWindow>
)}
{state.isDescriptionOpened && (
<ModalWindow handleOpenModal={handleOpenModal}>
<div className="modal-info-wrapper">
<div className="info-title">
Expand All @@ -526,7 +579,7 @@ const RoomPage = () => {
</div>
</div>
</ModalWindow>
) : null}
)}
<OponentsList />
<div className="camera-list-wrapper">
<div className="siwc-wrapper">
Expand Down Expand Up @@ -742,7 +795,9 @@ const RoomPage = () => {
text={
char.type === 'health'
? char.isRevealed
? `${char.text}(${char.stage})`
? char.text !== 'Абсолютно здоровий'
? `${char.text}(${char.stage})`
: char.text
: char.text
: char.text
}
Expand Down
2 changes: 2 additions & 0 deletions apps/shelter-client/src/redux/reducers/lobbySlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface LobbyState {
revealPlayerId?: string;
timer?: number;
timerEndTime?: number | null;
finalPrediction?: string | null;
}

const initialState: LobbyState = {
Expand All @@ -32,6 +33,7 @@ const initialState: LobbyState = {
revealPlayerId: '',
timer: 0,
timerEndTime: null,
finalPrediction: '',
};

const lobbySlice = createSlice({
Expand Down
2 changes: 1 addition & 1 deletion apps/shelter-client/src/styles/ActivityLogs.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.activity-logs-wraper {
overflow-y: scroll;
height: 30vh;
height: 38vh;
}

.activity-logs-block {
Expand Down
11 changes: 11 additions & 0 deletions apps/shelter-client/src/styles/Room.scss
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ $sunset-color: invert(69%) sepia(91%) saturate(296%) hue-rotate(342deg) brightne

.modal-info-wrapper {
padding: 10px 30px 30px 30px;
overflow-y: scroll;
height: 38vh;

h3 {
font-size: 26px;
Expand Down Expand Up @@ -535,4 +537,13 @@ $sunset-color: invert(69%) sepia(91%) saturate(296%) hue-rotate(342deg) brightne

.char-list-container::-webkit-scrollbar-button {
display: none;
}

.prediction-loader {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
text-align: center;
font-family: 'Roboto Condensed';
}
1 change: 1 addition & 0 deletions apps/shelter-client/src/websocket/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type ServerPayloads = {
kickedPlayers: string[];
timer: number;
timerEndTime: number | null;
finalPrediction: string;
};

[ServerEvents.GameMessage]: {
Expand Down
4 changes: 3 additions & 1 deletion apps/shelter-gateway/src/game/game.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { SocketExceptions } from './utils/SocketExceptions';
import { LobbyCreateDto } from './dto/LobbyCreate';
import { LobbyJoinDto } from './dto/LobbyJoin';
import { ChatMessage } from './dto/ChatMessage';
import { DatabaseService } from '@app/common';
import { DatabaseService, AIService } from '@app/common';
import { ActivityLogsService } from '../activityLogs/activity-logs.service';

@UsePipes(new WsValidationPipe())
Expand All @@ -32,6 +32,7 @@ export class GameGateway
constructor(
private readonly lobbyManager: LobbyManager,
private readonly databaseService: DatabaseService,
private readonly AIService: AIService,
private readonly activityLogsService: ActivityLogsService,
) {}

Expand Down Expand Up @@ -74,6 +75,7 @@ export class GameGateway
const lobby = this.lobbyManager.createLobby(
data.maxClients,
this.databaseService,
this.AIService,
this.activityLogsService,
);

Expand Down
28 changes: 26 additions & 2 deletions apps/shelter-gateway/src/game/instance/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class Instance {
public revealPlayerId: string;
public voteKickList: any = [];
public kickedPlayers: string[] = [];
public finalPrediction: string = '';

private charsRevealedCount: number = 0;
private readonly charOpenLimit: number = 2; // per 1 player on every stage
Expand Down Expand Up @@ -102,18 +103,41 @@ export class Instance {
);
}

public triggerFinish(): void {
public async triggerFinish(): Promise<void> {
if (this.hasFinished || !this.hasStarted) {
return;
}

// generate prediction in background and set finalPrediction on finish
this.lobby.AIService.generatePrediction({
conditions: this.conditions,
characteristics: this.characteristics,
players: this.players,
}).then((predictionStr) => {
this.finalPrediction = predictionStr
this.lobby.dispatchLobbyState();
})

// reveal all remained characteristics
const revealAllCharacteristics = (): void => {
// Iterate over each key in the map
Object.keys(this.characteristics).forEach(key => {
// Use forEach to update each characteristic in place
this.characteristics[key].forEach(characteristic => {
characteristic.isRevealed = true; // Directly modify the characteristic object
});
});
}
revealAllCharacteristics()

this.hasFinished = true;

this.lobby.dispatchLobbyState();
this.lobby.dispatchToLobby<ServerPayloads[ServerEvents.GameMessage]>(
ServerEvents.GameMessage,
{
color: 'blue',
message: 'Game finished !',
message: 'Game finished! All characteristics revealed..',
},
);
}
Expand Down
2 changes: 2 additions & 0 deletions apps/shelter-gateway/src/game/lobby/lobby.manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ export class LobbyManager {
public createLobby(
maxClients: number,
databaseService,
AIService,
activityLogsService,
): Lobby {
const lobby = new Lobby(
this.server,
maxClients,
databaseService,
AIService,
activityLogsService,
);
this.lobbies.set(lobby.id, lobby);
Expand Down
5 changes: 4 additions & 1 deletion apps/shelter-gateway/src/game/lobby/lobby.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Instance } from '../instance/instance';
import { ServerEvents } from '../utils/ServerEvents';
import { ServerPayloads } from '../utils/ServerPayloads';
import { generateSixSymbolHash } from 'helpers';
import { DatabaseService } from '@app/common';
import { AIService, DatabaseService } from '@app/common';
import { ActivityLogsService } from '../../activityLogs/activity-logs.service';

export class Lobby {
Expand All @@ -18,12 +18,14 @@ export class Lobby {
public isPrivate: boolean = true;
public timer: number = 0;
public readonly databaseService = this._databaseService;
public readonly AIService = this._AIService;
public readonly activityLogsService = this._activityLogsService;

constructor(
private readonly server: Server,
public maxClients: number,
private readonly _databaseService: DatabaseService,
private readonly _AIService: AIService,
private readonly _activityLogsService: ActivityLogsService,
) {}

Expand Down Expand Up @@ -91,6 +93,7 @@ export class Lobby {
voteKickList: this.instance.voteKickList,
kickedPlayers: this.instance.kickedPlayers,
timerEndTime: this.instance.timerEndTime,
finalPrediction: this.instance.finalPrediction,
};

this.dispatchToLobby(ServerEvents.LobbyState, payload);
Expand Down
1 change: 1 addition & 0 deletions apps/shelter-gateway/src/game/utils/ServerPayloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type ServerPayloads = {
voteKickList: any[];
kickedPlayers: string[];
timerEndTime: number;
finalPrediction: string;
};

[ServerEvents.GameMessage]: {
Expand Down
3 changes: 2 additions & 1 deletion apps/shelter-gateway/src/gateway.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule, FirebaseModule } from '@app/common';
import { DatabaseModule, FirebaseModule, AIModule } from '@app/common';
import { StatusModule } from './status/status.module';
import { UploadsModule } from './uploads/uploads.module';
import { GameGateway } from './game/game.gateway';
Expand All @@ -22,6 +22,7 @@ import { ActivityLogsService } from './activityLogs/activity-logs.service';

DatabaseModule,
FirebaseModule,
AIModule,

ScheduleModule.forRoot(),
ConfigModule.forRoot({
Expand Down
4 changes: 4 additions & 0 deletions characteristics.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@
{
"name": "Астероїдний удар",
"description": "Величезний астероїд зіткнувся з Землею, викликавши глобальні пожежі, цунамі та ядерну зиму, що значно знизило сонячне світло, яке досягає поверхні планети. Виживання цивілізації залежить від вміння адаптуватися до радикально змінених умов існування."
},
{
"name": "Зомбівірус",
"description": "Цей невідомий вірус починається як загадкове захворювання, яке швидко перетворює людей на безжалісних та агресивних зомбі. Інфіковані втрачають свідомість і контроль над своїми діями, перетворюючись на безумних хижаків, які атакують навіть своїх власних співвітчизників. Вірус поширюється швидко через контакт з інфікованими кров'ю або тілом. Медичні установи намагаються виявити джерело вірусу та розробити вакцину, але намагаються боротися з великими труднощами через швидкість поширення захворювання та хаос, який воно викликає. Групи виживших формуються для захисту від нападів зомбі та пошуку безпечних місць для проживання. Суспільство знаходиться на межі руйнації, а виживання людства залежить від зусиль боротьби з цією жахливою загрозою."
}
],
"shelter": [
Expand Down
Loading
Loading