diff --git a/srcs/docker-compose.yml b/srcs/docker-compose.yml index 0c965928..62dc9479 100644 --- a/srcs/docker-compose.yml +++ b/srcs/docker-compose.yml @@ -24,6 +24,8 @@ services: volumes: - ./requirements/svelte/api_front/src:/usr/app/src/ - ./requirements/svelte/api_front/public:/usr/app/public/ + ports: + - "35729:35729" env_file: - .env environment: diff --git a/srcs/requirements/nestjs/api_back/package-lock.json b/srcs/requirements/nestjs/api_back/package-lock.json index 3c68b140..9678a46f 100644 --- a/srcs/requirements/nestjs/api_back/package-lock.json +++ b/srcs/requirements/nestjs/api_back/package-lock.json @@ -3886,9 +3886,9 @@ } }, "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, "dependencies": { "asap": "^2.0.0", @@ -4823,25 +4823,28 @@ } }, "node_modules/formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", "dev": true, "dependencies": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" }, "funding": { "url": "https://ko-fi.com/tunnckoCore/commissions" } }, "node_modules/formidable/node_modules/qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -12651,9 +12654,9 @@ "dev": true }, "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, "requires": { "asap": "^2.0.0", @@ -13380,22 +13383,25 @@ } }, "formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", "dev": true, "requires": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" }, "dependencies": { "qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "dev": true + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } } } }, diff --git a/srcs/requirements/nestjs/api_back/src/app.module.ts b/srcs/requirements/nestjs/api_back/src/app.module.ts index ba0f94a2..837f8baf 100644 --- a/srcs/requirements/nestjs/api_back/src/app.module.ts +++ b/srcs/requirements/nestjs/api_back/src/app.module.ts @@ -7,6 +7,7 @@ import { ConfigModule } from '@nestjs/config'; import { FriendshipsModule } from './friendship/friendships.module'; import { AuthenticationModule } from './auth/42/authentication.module'; import { PassportModule } from '@nestjs/passport'; +// import { GameModule } from './game/game/game.module'; @Module({ imports: [UsersModule, @@ -26,6 +27,7 @@ import { PassportModule } from '@nestjs/passport'; //avec une classe pour le module synchronize: true, }), + // GameModule, ], controllers: [AppController], providers: [AppService], diff --git a/srcs/requirements/nestjs/api_back/src/auth/42/authentication.controller.ts b/srcs/requirements/nestjs/api_back/src/auth/42/authentication.controller.ts index a032478b..6746e911 100644 --- a/srcs/requirements/nestjs/api_back/src/auth/42/authentication.controller.ts +++ b/srcs/requirements/nestjs/api_back/src/auth/42/authentication.controller.ts @@ -4,6 +4,7 @@ import { AuthenticationService } from './authentication.service'; import { Response } from 'express'; import { TwoFaDto } from './dto/2fa.dto'; import { UsersService } from 'src/users/users.service'; +import { User } from 'src/users/entities/user.entity'; @Controller('auth') export class AuthenticationController { @@ -33,13 +34,17 @@ export class AuthenticationController { async redirect(@Res() response : Response, @Req() request) { console.log('ON EST DANS REDIRECT AUTH CONTROLLER'); console.log('On redirige'); - if (request.user.isEnabledTwoFactorAuth === false) - return response.status(200).redirect('http://transcendance:8080'); + const user : User = request.user + if (user.isEnabledTwoFactorAuth === false || user.isTwoFactorAuthenticated === true){ + console.log('ON VA VERS PROFILE'); + return response.status(200).redirect('http://transcendance:8080/#/profile'); + } + console.log('ON VA VERS 2FA') return response.status(200).redirect('http://transcendance:8080/#/2fa'); } /** - * GET /api/v2/auth/logout + * POST /api/v2/auth/logout * Route pour déconnecter l'utilisateur */ @Post('logout') @@ -58,22 +63,26 @@ export class AuthenticationController { @Post('2fa/generate') @UseGuards(AuthenticateGuard) async register(@Req() request, @Res() response){ - console.log('ON EST DANS REGISTER POUR 2FA AUTH CONTROLLER') - const { otpauth } = await this.authService.generate2FaSecret(request.user); - return this.authService.pipeQrCodeStream(response, otpauth); + const user : User = request.user; + if (user.isEnabledTwoFactorAuth === true) + { + console.log('ON EST DANS REGISTER POUR 2FA AUTH CONTROLLER') + const { otpauth } = await this.authService.generate2FaSecret(request.user); + return this.authService.pipeQrCodeStream(response, otpauth); + } } - @Post('2fa/turn-on') + + @Post('2fa/check') @UseGuards(AuthenticateGuard) async verify(@Req() request, @Body() {twoFaCode} : TwoFaDto, @Res() response){ + const user : User = request.user; console.log('ON EST DANS VERIFY POUR 2FA AUTH CONTROLLER') const isCodeIsValid = await this.authService.verify2FaCode(request.user, twoFaCode); if (isCodeIsValid === false) - { throw new UnauthorizedException('Wrong Code.'); - } - await this.userService.enableTwoFactorAuth(request.user.id); + await this.userService.authenticateUserWith2FA(request.user.id); console.log('ON REDIRIGE'); - return response.status(200); + return response.status(200).redirect('http://transcendance:8080/#/profile'); } } diff --git a/srcs/requirements/nestjs/api_back/src/auth/42/authentication.service.ts b/srcs/requirements/nestjs/api_back/src/auth/42/authentication.service.ts index 0bea323d..b338ce7b 100644 --- a/srcs/requirements/nestjs/api_back/src/auth/42/authentication.service.ts +++ b/srcs/requirements/nestjs/api_back/src/auth/42/authentication.service.ts @@ -37,11 +37,15 @@ export class AuthenticationService { } async verify2FaCode(user : User, code : string) { + console.log("User : " + user.username); return authenticator.verify({ token: code, secret: user.secretTwoFactorAuth }); } async generate2FaSecret(user : User) { - const secret = authenticator.generateSecret(); + let secret : string; + secret = user.secretTwoFactorAuth; + if (!user.secretTwoFactorAuth) + secret = authenticator.generateSecret(); const otpauth = authenticator.keyuri(user.email, process.env.TWO_FACTOR_AUTHENTICATION_APP_NAME, secret); await this.userService.setAuthenticatorSecret(user.id, secret); return { secret, otpauth }; diff --git a/srcs/requirements/nestjs/api_back/src/friendship/dto/create-friendship.dto.ts b/srcs/requirements/nestjs/api_back/src/friendship/dto/create-friendship.dto.ts index 4285b556..57b67493 100644 --- a/srcs/requirements/nestjs/api_back/src/friendship/dto/create-friendship.dto.ts +++ b/srcs/requirements/nestjs/api_back/src/friendship/dto/create-friendship.dto.ts @@ -1,11 +1,10 @@ -import { IsEnum, IsString } from 'class-validator'; +import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; import { FriendshipStatus } from '../entities/friendship.entity'; export class CreateFriendshipDto { @IsString() - readonly requesterId: string; - @IsString() - readonly addresseeId: string; + @IsNotEmpty() + readonly receiverUsername: string; @IsEnum(FriendshipStatus) readonly status: FriendshipStatus; } diff --git a/srcs/requirements/nestjs/api_back/src/friendship/entities/friendship.entity.ts b/srcs/requirements/nestjs/api_back/src/friendship/entities/friendship.entity.ts index 0b8f08bd..28459b11 100644 --- a/srcs/requirements/nestjs/api_back/src/friendship/entities/friendship.entity.ts +++ b/srcs/requirements/nestjs/api_back/src/friendship/entities/friendship.entity.ts @@ -17,13 +17,17 @@ export class Friendship { @CreateDateColumn() date : Date; - @Column() - @ManyToOne(type => User, user => user.requesterId) - requesterId: string; + @ManyToOne(type => User, user => user.username) + sender: User; + + @ManyToOne(type => User, user => user.username) + receiver: User; @Column() - @ManyToOne(type => User, user => user.addresseeId) - addresseeId: string; + senderUsername : string; + + @Column() + receiverUsername : string; @Column({ type: 'enum', enum: FriendshipStatus, default: FriendshipStatus.REQUESTED}) status: FriendshipStatus; diff --git a/srcs/requirements/nestjs/api_back/src/friendship/friendship.controller.ts b/srcs/requirements/nestjs/api_back/src/friendship/friendship.controller.ts index 75b10f93..297be6f8 100644 --- a/srcs/requirements/nestjs/api_back/src/friendship/friendship.controller.ts +++ b/srcs/requirements/nestjs/api_back/src/friendship/friendship.controller.ts @@ -18,12 +18,29 @@ export class FriendshipController { } // GET http://transcendance:8080/api/v2/network/myfriends/relationshipId - @Get('myfriends/:relationshipId') + @Get('myfriend/:relationshipId') @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) findOneFriend(@Param('relationshipId') relationshipId: string, @Req() req) { const user = req.user; - return this.friendshipService.findOneFriend(relationshipId, user.id); + return this.friendshipService.findOneFriend(relationshipId, user.username); + } + + // GET http://transcendance:8080/api/v2/network/blocked + @Get('blocked') + @UseGuards(AuthenticateGuard) + @UseGuards(TwoFactorGuard) + findAllBlocked(@Req() req) { + const user = req.user; + return this.friendshipService.findAllBlockedFriends(user.username); + } + + @Get('blocked/:relationshipId') + @UseGuards(AuthenticateGuard) + @UseGuards(TwoFactorGuard) + findOneBlocked(@Param('relationshipId') relationshipId: string, @Req() req) { + const user = req.user; + return this.friendshipService.findOneBlocked(relationshipId, user.username); } // POST http://transcendance:8080/api/v2/network/myfriends @@ -33,38 +50,46 @@ export class FriendshipController { @UseGuards(TwoFactorGuard) create(@Body() createFriendshipDto: CreateFriendshipDto, @Req() req) { const user = req.user; - console.log(`User id: ${user.id}\nFriend id: ${createFriendshipDto.requesterId}\nStatus: ${createFriendshipDto.status}`); - if (user.id === +createFriendshipDto.requesterId) + if (user.username !== createFriendshipDto.receiverUsername) return this.friendshipService.create(createFriendshipDto, user); - return new HttpException('You can\'t request a frienship for another user', HttpStatus.FORBIDDEN); + return new HttpException('You can\'t request a frienship to yourself', HttpStatus.BAD_REQUEST); } - // PATCH http://transcendance:8080/api/v2/network/myfriends/relationshipId?status=A - @Patch('myfriends/:relationshipId') + // PATCH http://transcendance:8080/api/v2/network/myfriends/relationshipId/accept + @Patch('myfriends/:relationshipId/accept') @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) - update(@Param('relationshipId') relationshipId: string, @Query('status') status : string, @Req() req) + updateAccept(@Param('relationshipId') relationshipId: string, @Req() req) { const user : User = req.user; - return this.friendshipService.updateFriendship(relationshipId, user, status); + return this.friendshipService.acceptFriendship(relationshipId, user); + } + + @Patch('myfriends/:relationshipId/decline') + @UseGuards(AuthenticateGuard) + @UseGuards(TwoFactorGuard) + updateDecline(@Param('relationshipId') relationshipId: string, @Req() req) + { + const user : User = req.user; + return this.friendshipService.declineFriendship(relationshipId, user); + } + + @Patch('myfriends/:relationshipId/block') + @UseGuards(AuthenticateGuard) + @UseGuards(TwoFactorGuard) + updateBlock(@Param('relationshipId') relationshipId: string, @Req() req) + { + const user : User = req.user; + return this.friendshipService.blockFriendship(relationshipId, user); } // DELETE http://transcendance:8080/api/v2/network/myfriends/relationshipId - @Delete('myfriends/:relationshipId') + @Delete(':relationshipId') @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) - remove(@Param('relationshipId') relationshipId: string) { - return this.friendshipService.removeFriendship(relationshipId); - } - - - // GET http://transcendance:8080/api/v2/network/blocked - @Get('blocked') - @UseGuards(AuthenticateGuard) - @UseGuards(TwoFactorGuard) - findAllBlocked(@Req() req) { - const user = req.user; - return this.friendshipService.findAllBlockedFriends(user.id); + remove(@Param('relationshipId') relationshipId: string, @Req() req) { + const user : User = req.user; + return this.friendshipService.removeFriendship(relationshipId, user); } // GET http://transcendance:8080/api/v2/network/pending @@ -73,7 +98,7 @@ export class FriendshipController { @UseGuards(TwoFactorGuard) findAllPendantFriendshipRequested(@Req() req) { const user = req.user; - return this.friendshipService.findAllPendantRequestsForFriendship(user.id); + return this.friendshipService.findAllPendantRequestsForFriendship(user.username); } // GET http://transcendance:8080/api/v2/network/received @@ -82,6 +107,6 @@ export class FriendshipController { @UseGuards(TwoFactorGuard) findAllPendantFriendshipReceived(@Req() req) { const user = req.user; - return this.friendshipService.findAllReceivedRequestsForFriendship(user.id); + return this.friendshipService.findAllReceivedRequestsForFriendship(user.username); } } diff --git a/srcs/requirements/nestjs/api_back/src/friendship/friendship.service.ts b/srcs/requirements/nestjs/api_back/src/friendship/friendship.service.ts index 6066a881..cee750cd 100644 --- a/srcs/requirements/nestjs/api_back/src/friendship/friendship.service.ts +++ b/srcs/requirements/nestjs/api_back/src/friendship/friendship.service.ts @@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm'; import { User } from 'src/users/entities/user.entity'; import { Repository } from 'typeorm'; import { CreateFriendshipDto } from './dto/create-friendship.dto'; -import { UpdateFriendshipDto } from './dto/update-friendship.dto'; import { Friendship, FriendshipStatus } from './entities/friendship.entity'; @Injectable() @@ -17,26 +16,26 @@ export class FriendshipService { ) { } - async findOneFriend(friendshipId: string, userId: string) { - const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, requesterId: userId, status: FriendshipStatus.ACCEPTED } }); + async findOneFriend(friendshipId: string, username: string) { + const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, senderUsername: username, status: FriendshipStatus.ACCEPTED } }); if (!friendship) throw new HttpException(`The requested friend not found.`, HttpStatus.NOT_FOUND); return friendship; } - async findOneBlocked(friendshipId: string) { - const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, status: FriendshipStatus.BLOCKED } }); + async findOneBlocked(friendshipId: string, username: string) { + const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, senderUsername: username, status: FriendshipStatus.BLOCKED } }); if (!friendship) - throw new HttpException(`The requested user not found.`, HttpStatus.NOT_FOUND); + throw new HttpException(`The requested blocked not found.`, HttpStatus.NOT_FOUND); return friendship; } - async findAllFriends(userId: string) { + async findAllFriends(username: string) { const friendship = await this.friendshipRepository .createQueryBuilder('friendship') .where('friendship.status = :status', { status: FriendshipStatus.ACCEPTED }) - .andWhere('friendship.addresseeId = :addressee', { addressee: userId }) - .orWhere('friendship.requesterId = :requester', { requester: userId }) + .andWhere('friendship.receiverUsername = :addressee', { addressee: username }) + .orWhere('friendship.senderUsername = :requester', { requester: username }) .andWhere('friendship.status = :status', { status: FriendshipStatus.ACCEPTED }) .getMany(); for (const friend of friendship) @@ -44,40 +43,56 @@ export class FriendshipService { return friendship; } - async findAllBlockedFriends(userId: string) { - return await this.friendshipRepository + async findAllBlockedFriends(username: string) { + const friendships : Friendship[] = await this.friendshipRepository .createQueryBuilder('friendship') - .where('friendship.requesterId = :requestee', { requestee: userId }) - .orWhere('friendship.addresseeId = :addressee', { addressee: userId }) + .where('friendship.senderUsername = :requestee', { requestee: username }) .andWhere('friendship.status = :status', { status: FriendshipStatus.BLOCKED }) .getMany(); + let partialFriendship : Partial[] = []; + for (const friendship of friendships) { + partialFriendship.push({id: friendship.id, date: friendship.date, senderUsername: friendship.senderUsername, receiverUsername: friendship.receiverUsername, status: friendship.status}); + } + return partialFriendship; } - async findAllPendantRequestsForFriendship(userId: string) { - return await this.friendshipRepository + async findAllPendantRequestsForFriendship(username: string) { + const friendship = await this.friendshipRepository .createQueryBuilder('friendship') - .where('friendship.requesterId = :requestee', { requestee: userId }) + .where('friendship.senderUsername = :requestee', { requestee: username }) .andWhere('friendship.status = :status', { status: FriendshipStatus.REQUESTED }) .getMany(); + let partialFriendship : Partial[] = []; + for (const friend of friendship) { + console.log("FRIENDSHIP : " + friend); + partialFriendship.push({id: friend.id, senderUsername: friend.senderUsername, receiverUsername: friend.receiverUsername, status: friend.status}); + } + console.log("Pendant requests : " + partialFriendship); + return partialFriendship; } - async findAllReceivedRequestsForFriendship(userId: string) { - return await this.friendshipRepository + async findAllReceivedRequestsForFriendship(username: string) { + const friendship = await this.friendshipRepository .createQueryBuilder('friendship') - .where('friendship.addresseeId = :addressee', { addressee: userId }) + .where('friendship.receiverUsername = :addressee', { addressee: username }) .andWhere('friendship.status = :status', { status: FriendshipStatus.REQUESTED }) .getMany(); + let partialFriendship : Partial[] = []; + for (const friend of friendship) { + partialFriendship.push({id: friend.id, senderUsername: friend.senderUsername, receiverUsername: friend.receiverUsername, status: friend.status}); + } + return partialFriendship; } - //GROS CHANTIER - async create(createFriendshipDto: CreateFriendshipDto, creator : User) { - const addressee = await this.userRepository.findOneBy({ id: +createFriendshipDto.addresseeId }); - if (!addressee) + + async create(createFriendshipDto: CreateFriendshipDto, creator : User) : Promise > { + console.log("DTO : \n") + console.log({...createFriendshipDto}) + const receiver = await this.userRepository.findOneBy({username: createFriendshipDto.receiverUsername}); + if (!receiver) throw new HttpException(`The addressee does not exist.`, HttpStatus.NOT_FOUND); - if (creator.id === addressee.id) - throw new HttpException(`You can't add yourself.`, HttpStatus.FORBIDDEN); if (createFriendshipDto.status !== FriendshipStatus.REQUESTED && createFriendshipDto.status !== FriendshipStatus.BLOCKED) throw new HttpException(`The status is not valid.`, HttpStatus.NOT_FOUND); - const friendship = await this.friendshipRepository.findOneBy({ requesterId: createFriendshipDto.requesterId, addresseeId: createFriendshipDto.addresseeId }); + const friendship = await this.friendshipRepository.findOneBy({ sender: creator, receiver: receiver }); if (friendship) { if (friendship.status && friendship.status === FriendshipStatus.ACCEPTED) throw new HttpException(`The friendship request has already been accepted.`, HttpStatus.OK); @@ -88,46 +103,99 @@ export class FriendshipService { else if (friendship.status && friendship.status === FriendshipStatus.DECLINED) throw new HttpException(`The request has been declined.`, HttpStatus.OK); } - const newFriendship = this.friendshipRepository.create(createFriendshipDto); - return this.friendshipRepository.save(newFriendship); + const newFriendship = new Friendship(); + newFriendship.sender = creator; + newFriendship.senderUsername = creator.username; + newFriendship.receiver = receiver; + newFriendship.receiverUsername = receiver.username; + newFriendship.status = createFriendshipDto.status; + const savedFriendship = this.friendshipRepository.save(newFriendship); + const partialFriendship : Partial = { + id : (await savedFriendship).id, + date : (await savedFriendship).date, + receiverUsername: (await savedFriendship).receiverUsername, + status : (await savedFriendship).status + } + console.log({...partialFriendship}) + return partialFriendship; } - async updateFriendship(relationshipId: string, user: User, status: string) { + async acceptFriendship(relationshipId: string, user: User) { const relation = await this.friendshipRepository.findOneBy({ id: +relationshipId }); if (!relation) throw new HttpException(`The requested relationship not found.`, HttpStatus.NOT_FOUND); - if (+relation.requesterId === user.id) { + if (relation.sender.id === user.id) { throw new HttpException(`You can't accept your own request.`, HttpStatus.NOT_FOUND); } - if (status === FriendshipStatus.ACCEPTED) - relation.status = FriendshipStatus.ACCEPTED; - else if (status === FriendshipStatus.DECLINED) - relation.status = FriendshipStatus.DECLINED; - else if (status === FriendshipStatus.BLOCKED) - relation.status = FriendshipStatus.BLOCKED; - else - throw new HttpException(`The status is not valid.`, HttpStatus.NOT_FOUND); - if (relation.status !== status) - throw new HttpException(`We could not update the status.`, HttpStatus.OK); - return this.friendshipRepository.save(relation); + relation.status = FriendshipStatus.ACCEPTED; + const savedFriendship = this.friendshipRepository.save(relation); + const partialFriendship : Partial = { + id : (await savedFriendship).id, + date : (await savedFriendship).date, + receiverUsername: (await savedFriendship).receiverUsername, + status : (await savedFriendship).status + } + return partialFriendship; } - async removeFriendship(relationshipId: string) { + async declineFriendship(relationshipId: string, user: User) { + const relation = await this.friendshipRepository.findOneBy({ id: +relationshipId }); + if (!relation) + throw new HttpException(`The requested relationship not found.`, HttpStatus.NOT_FOUND); + if (relation.sender.id === user.id) { + throw new HttpException(`You can't accept your own request.`, HttpStatus.NOT_FOUND); + } + relation.status = FriendshipStatus.DECLINED; + const savedFriendship = this.friendshipRepository.save(relation); + const partialFriendship : Partial = { + id : (await savedFriendship).id, + date : (await savedFriendship).date, + receiverUsername: (await savedFriendship).receiverUsername, + status : (await savedFriendship).status + } + return partialFriendship + } + + async blockFriendship(relationshipId: string, user: User) { + const relation = await this.friendshipRepository.findOneBy({ id: +relationshipId }); + if (!relation) + throw new HttpException(`The requested relationship not found.`, HttpStatus.NOT_FOUND); + if (relation.sender.id === user.id) { + throw new HttpException(`You can't accept your own request.`, HttpStatus.NOT_FOUND); + } + relation.status = FriendshipStatus.BLOCKED; + const savedFriendship = this.friendshipRepository.save(relation); + const partialFriendship : Partial = { + id : (await savedFriendship).id, + date : (await savedFriendship).date, + receiverUsername: (await savedFriendship).receiverUsername, + status : (await savedFriendship).status + } + return partialFriendship + } + + async removeFriendship(relationshipId: string, user : User) { const friendship = await this.friendshipRepository.findOneBy({ id: +relationshipId }); if (!friendship) throw new HttpException(`Your friend could not be deleted.`, HttpStatus.NOT_FOUND); + if (friendship.sender.id !== user.id || friendship.receiver.id !== user.id) { + throw new HttpException(`You can't do that.`, HttpStatus.FORBIDDEN); + } return this.friendshipRepository.remove(friendship); } - async findIfUserIsBlockedOrHasBlocked(userConnectedId: string, userToCheckId: string) { + async findIfUserIsBlockedOrHasBlocked(userConnectedId: string, userToFindId: string) { + console.log("finding if user is blocked") const friendship = await this.friendshipRepository .createQueryBuilder('friendship') - .where('friendship.requesterId = :requestee', { requestee: userConnectedId }) - .orWhere('friendship.requesterId = :requesteeBis', { requesteeBis: userToCheckId }) + .where('friendship.senderUsername = :requestee', { requestee: userConnectedId }) + .orWhere('friendship.senderUsername = :requesteeBis', { requesteeBis: userToFindId }) .andWhere('friendship.status = :status', { status: FriendshipStatus.BLOCKED }) .getOne(); - if (friendship) + if (friendship) { + console.log('we are blocked in friendship.service') return true; + } return false; } } diff --git a/srcs/requirements/nestjs/api_back/src/game/dto/create-party.dto.ts b/srcs/requirements/nestjs/api_back/src/game/dto/create-party.dto.ts new file mode 100644 index 00000000..14d2e14c --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/dto/create-party.dto.ts @@ -0,0 +1,16 @@ +import { IsBoolean, IsEmail, IsNotEmpty, IsString } from 'class-validator'; + +export class CreateUsersDto { + @IsString() + @IsNotEmpty() + readonly username: string; + readonly fortyTwoId: string; + @IsEmail() + readonly email: string; + @IsString() + readonly image_url: string; + @IsString() + readonly status: string; + @IsBoolean() + readonly isEnabledTwoFactorAuth: boolean; +} diff --git a/srcs/requirements/nestjs/api_back/src/game/entity/user.entity.ts b/srcs/requirements/nestjs/api_back/src/game/entity/user.entity.ts new file mode 100644 index 00000000..6c45d3a5 --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/entity/user.entity.ts @@ -0,0 +1,22 @@ +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; + + + +@Entity('gameParty') +export class gameParty { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + playerOne: string + + @Column() + playerTwo: string + + @Column() + resultOfTheMatch: string + + @Column() + gameServerIdOfTheMatch: string +} diff --git a/srcs/requirements/nestjs/api_back/src/game/game.controller.spec.ts b/srcs/requirements/nestjs/api_back/src/game/game.controller.spec.ts new file mode 100644 index 00000000..f70c47c2 --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/game.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { GameController } from './game.controller'; + +describe('GameController', () => { + let controller: GameController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [GameController], + }).compile(); + + controller = module.get(GameController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/srcs/requirements/nestjs/api_back/src/game/game.controller.ts b/srcs/requirements/nestjs/api_back/src/game/game.controller.ts new file mode 100644 index 00000000..d86df072 --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/game.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('game') +export class GameController {} diff --git a/srcs/requirements/nestjs/api_back/src/game/game.module.ts b/srcs/requirements/nestjs/api_back/src/game/game.module.ts new file mode 100644 index 00000000..17a50c06 --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/game.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { GameController } from './game.controller'; +import { GameService } from './game.service'; + +@Module({ + controllers: [GameController], + providers: [GameService] +}) +export class GameModule {} diff --git a/srcs/requirements/nestjs/api_back/src/game/game.service.spec.ts b/srcs/requirements/nestjs/api_back/src/game/game.service.spec.ts new file mode 100644 index 00000000..f4a1db7e --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/game.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { GameService } from './game.service'; + +describe('GameService', () => { + let service: GameService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [GameService], + }).compile(); + + service = module.get(GameService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/srcs/requirements/nestjs/api_back/src/game/game.service.ts b/srcs/requirements/nestjs/api_back/src/game/game.service.ts new file mode 100644 index 00000000..18ca270d --- /dev/null +++ b/srcs/requirements/nestjs/api_back/src/game/game.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class GameService {} diff --git a/srcs/requirements/nestjs/api_back/src/users/dto/create-users.dto.ts b/srcs/requirements/nestjs/api_back/src/users/dto/create-users.dto.ts index a2d453e8..3c0e6472 100644 --- a/srcs/requirements/nestjs/api_back/src/users/dto/create-users.dto.ts +++ b/srcs/requirements/nestjs/api_back/src/users/dto/create-users.dto.ts @@ -1,9 +1,10 @@ -import { IsBoolean, IsEmail, IsOptional, IsString } from 'class-validator'; +import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { isSet } from 'util/types'; export class CreateUsersDto { @IsString() + @IsNotEmpty() readonly username: string; - @IsString() readonly fortyTwoId: string; @IsEmail() readonly email: string; diff --git a/srcs/requirements/nestjs/api_back/src/users/entities/user.entity.ts b/srcs/requirements/nestjs/api_back/src/users/entities/user.entity.ts index fa0fce5b..c00427b3 100644 --- a/srcs/requirements/nestjs/api_back/src/users/entities/user.entity.ts +++ b/srcs/requirements/nestjs/api_back/src/users/entities/user.entity.ts @@ -43,13 +43,11 @@ export class User { @Column({ nullable: true }) secretTwoFactorAuth: string; - @JoinTable() - @OneToMany(type => Friendship , (friendship) => friendship.requesterId) - requesterId: Friendship[]; + @OneToMany(type => Friendship , (friendship) => friendship.sender) + sentFriendRequest: Friendship[]; - @JoinTable() - @OneToMany(type => Friendship , (friendship) => friendship.addresseeId) - addresseeId: Friendship[]; + @OneToMany(type => Friendship , (friendship) => friendship.receiver) + receivedFriendRequest: Friendship[]; @JoinColumn() @OneToOne(() => UserStats, { cascade: true }) diff --git a/srcs/requirements/nestjs/api_back/src/users/users.controller.ts b/srcs/requirements/nestjs/api_back/src/users/users.controller.ts index 55d9dc61..181b9ac5 100644 --- a/srcs/requirements/nestjs/api_back/src/users/users.controller.ts +++ b/srcs/requirements/nestjs/api_back/src/users/users.controller.ts @@ -1,7 +1,8 @@ import { - Body, Controller, Delete, Get, NotFoundException, Param, Patch, Post, Query, Req, Res, UploadedFile, UseGuards, UseInterceptors + Body, Controller, Delete, Get, NotFoundException, Param, Patch, Post, Query, Redirect, Req, Res, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; +import { Response } from 'express'; import { AuthenticateGuard, TwoFactorGuard } from 'src/auth/42/guards/42guards'; import { PaginationQueryDto } from 'src/common/dto/pagination-query.dto'; import { ValidationPipe } from 'src/common/validation/validation.pipe'; @@ -10,6 +11,7 @@ import { UsersService } from './users.service'; import { User } from './entities/user.entity'; import { of } from 'rxjs'; import { storageForAvatar } from 'src/common/constants/constants'; +import { use } from 'passport'; @Controller('user') @@ -34,11 +36,26 @@ export class UsersController { * car un utilisateur est crée à la première connexion avec l'Oauth de 42. */ + // @UseGuards(AuthenticateGuard) + // @UseGuards(TwoFactorGuard) + // @Get() + // findOne(@Req() req) { + // console.log("Backend Getting current user"); + // return this.usersService.findOne(req.user.id); + // } + @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) @Get() - findOne(@Req() req) { - return this.usersService.findOne(req.user.id); + findOne(@Query('username') username: string, @Req() req) { + if (username === undefined) { + console.log("Backend Getting current user"); + return this.usersService.findOne(req.user.id); + } else { + const user : User = req.user; + console.log('we have a query: ' + username) + return this.usersService.findOneByUsername(user.id.toString(),username); + } } // GET http://transcendance:8080/user?username=NomDuUser @@ -47,9 +64,11 @@ export class UsersController { @Get('search') findOneByUsername(@Query('username') username: string, @Req() req) { const user : User = req.user; + console.log('searching for user' + user.username); return this.usersService.findOneByUsername(user.id.toString(),username); } + @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) @Get('stats') @@ -61,9 +80,19 @@ export class UsersController { @UseGuards(AuthenticateGuard) @UseGuards(TwoFactorGuard) @Patch() - update(@Req() req, @Body(new ValidationPipe()) usersUpdateDto: UpdateUsersDto) { + async update(@Req() req, @Body(new ValidationPipe()) usersUpdateDto: UpdateUsersDto, @Res() response : Response) { console.log("DANS PATCH USERS"); - return this.usersService.update(req.user.id, usersUpdateDto); + const user = await this.usersService.update(req.user.id, usersUpdateDto); + // const user : User = req.user; + if (user.isEnabledTwoFactorAuth === false && user.isTwoFactorAuthenticated === true) + this.usersService.setIsTwoFactorAuthenticatedWhenLogout(user.id); + console.log ("Enbale 2FA " + user.isEnabledTwoFactorAuth + " Is authenticated " + user.isTwoFactorAuthenticated); + if (user.isEnabledTwoFactorAuth === true && user.isTwoFactorAuthenticated === false) + { + response.status(201).send('2FA redirect') + } + console.log("ON RETOURNE 200\n") + response.status(200).send("OK") } @UseGuards(AuthenticateGuard) diff --git a/srcs/requirements/nestjs/api_back/src/users/users.service.ts b/srcs/requirements/nestjs/api_back/src/users/users.service.ts index 30e5594f..929d93d9 100644 --- a/srcs/requirements/nestjs/api_back/src/users/users.service.ts +++ b/srcs/requirements/nestjs/api_back/src/users/users.service.ts @@ -34,13 +34,13 @@ export class UsersService { async findOne(id: string) { console.log(`FIND ONE USER SERVICE Find user ${id}`); - const user = await this.userRepository.createQueryBuilder('user') + const user = await this.userRepository.createQueryBuilder('user') .leftJoinAndSelect('user.stats', 'stats') .where('user.id = :id', { id: +id }) .getOne(); if (!user) throw new NotFoundException(`The requested user not found.`); - console.log(`FIND ONE USER SERVICE The requested user found.` + console.log(`FIND ONE USER SERVICE The requested user found.` + user.username + user.stats.id + user.stats.winGame + user.stats.loseGame + user.stats.drawGame + user.stats.totalGame); const partialUser : Partial = { username: user.username, @@ -49,6 +49,7 @@ export class UsersService { status: user.status, stats: user.stats, }; + console.log(`Returned Partial User.` + partialUser.username + user.username); return partialUser; } @@ -59,21 +60,26 @@ export class UsersService { return true; } - async findOneByUsername(userConnectedId : string, username: string) { - const user : User = await this.userRepository.createQueryBuilder('user') + async findOneByUsername(userConnectedId : string, usernameToFind: string) { + const userToFind : User = await this.userRepository.createQueryBuilder('user') .leftJoinAndSelect('user.stats', 'stats') - .where('user.username = :username', { username: username }) + .where('user.username = :username', { username: usernameToFind }) .getOne(); - console.log('USERNAME OF FOUND USER : ' + user.username); - if (!user) - throw new HttpException(`The user could not be found.`,HttpStatus.NOT_FOUND); - if (this.friendshipService.findIfUserIsBlockedOrHasBlocked(userConnectedId, user.id.toString())) - throw new HttpException(`The user could not be found.`,HttpStatus.NOT_FOUND); + console.log('USERNAME OF FOUND USER : ' + userToFind.username); + // console.log({...user}) + // you can't do that, you need to do user === undefined + // if (user === undefined) + if (!userToFind) + throw new HttpException(`The user could not be found 1.`,HttpStatus.NOT_FOUND); + if (await this.friendshipService.findIfUserIsBlockedOrHasBlocked(userConnectedId, userToFind.id.toString())) { + console.log('we are blocked in user.service') + throw new HttpException(`The user could not be found 2.`,HttpStatus.NOT_FOUND); + } const partialUser : Partial = { - username: user.username, - image_url: user.image_url, - status: user.status, - stats: user.stats, + username: userToFind.username, + image_url: userToFind.image_url, + status: userToFind.status, + stats: userToFind.stats, }; return partialUser; } @@ -115,7 +121,11 @@ export class UsersService { } async enableTwoFactorAuth(id: string) { - return this.userRepository.update(id, {isEnabledTwoFactorAuth: true, isTwoFactorAuthenticated: true}); + return this.userRepository.update(id, {isEnabledTwoFactorAuth: true}); + } + + async authenticateUserWith2FA(id: string) { + return this.userRepository.update(id, { isTwoFactorAuthenticated: true}) } async setIsTwoFactorAuthenticatedWhenLogout(id: number) { diff --git a/srcs/requirements/svelte/api_front/src/old_unused/App_old.svelte b/srcs/requirements/svelte/api_front/old_unused/App_old.svelte similarity index 97% rename from srcs/requirements/svelte/api_front/src/old_unused/App_old.svelte rename to srcs/requirements/svelte/api_front/old_unused/App_old.svelte index e69b4dcc..4052bae1 100644 --- a/srcs/requirements/svelte/api_front/src/old_unused/App_old.svelte +++ b/srcs/requirements/svelte/api_front/old_unused/App_old.svelte @@ -6,7 +6,7 @@ import LoginPage from "./LoginPage.svelte"; import UserPage from "../UserPage.svelte"; - import NotFound from "../NotFound.svelte"; + import NotFound from "../pages/NotFound.svelte"; // Ideally fuck all this shit in the long run let pages = ['login', 'user', 'account']; diff --git a/srcs/requirements/svelte/api_front/src/old_unused/Canvas_1st_attempt.svelte b/srcs/requirements/svelte/api_front/old_unused/Canvas_1st_attempt.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/Canvas_1st_attempt.svelte rename to srcs/requirements/svelte/api_front/old_unused/Canvas_1st_attempt.svelte diff --git a/srcs/requirements/svelte/api_front/src/old_unused/Canvas_weird_circles.svelte b/srcs/requirements/svelte/api_front/old_unused/Canvas_weird_circles.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/Canvas_weird_circles.svelte rename to srcs/requirements/svelte/api_front/old_unused/Canvas_weird_circles.svelte diff --git a/srcs/requirements/svelte/api_front/old_unused/DisplayAUser_backup_copy.svelte b/srcs/requirements/svelte/api_front/old_unused/DisplayAUser_backup_copy.svelte new file mode 100644 index 00000000..85d8fe4e --- /dev/null +++ b/srcs/requirements/svelte/api_front/old_unused/DisplayAUser_backup_copy.svelte @@ -0,0 +1,112 @@ + + +{#if user !== undefined} + +{:else} +

Sorry

+
Failed to load user {aUsername}
+{/if} + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/old_unused/FlyingPotato.svelte b/srcs/requirements/svelte/api_front/old_unused/FlyingPotato.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/FlyingPotato.svelte rename to srcs/requirements/svelte/api_front/old_unused/FlyingPotato.svelte diff --git a/srcs/requirements/svelte/api_front/src/old_unused/Header.svelte b/srcs/requirements/svelte/api_front/old_unused/Header.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/Header.svelte rename to srcs/requirements/svelte/api_front/old_unused/Header.svelte diff --git a/srcs/requirements/svelte/api_front/src/old_unused/Header_Multi_old.svelte b/srcs/requirements/svelte/api_front/old_unused/Header_Multi_old.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/Header_Multi_old.svelte rename to srcs/requirements/svelte/api_front/old_unused/Header_Multi_old.svelte diff --git a/srcs/requirements/svelte/api_front/src/old_unused/HomePage_old.svelte b/srcs/requirements/svelte/api_front/old_unused/HomePage_old.svelte similarity index 98% rename from srcs/requirements/svelte/api_front/src/old_unused/HomePage_old.svelte rename to srcs/requirements/svelte/api_front/old_unused/HomePage_old.svelte index 2371dd47..1b861b0c 100644 --- a/srcs/requirements/svelte/api_front/src/old_unused/HomePage_old.svelte +++ b/srcs/requirements/svelte/api_front/old_unused/HomePage_old.svelte @@ -6,7 +6,7 @@ import Footer from "../components/Footer.svelte"; import Login from "./Login.svelte"; import Tabs from "../shared/Tabs.svelte" - import Card from "../shared/Card.svelte" + import Card from "../pieces/Card.svelte" // tmp let login = { username: '', password: ''}; // let's us track any errors in a submited form diff --git a/srcs/requirements/svelte/api_front/src/old_unused/Login.svelte b/srcs/requirements/svelte/api_front/old_unused/Login.svelte similarity index 97% rename from srcs/requirements/svelte/api_front/src/old_unused/Login.svelte rename to srcs/requirements/svelte/api_front/old_unused/Login.svelte index fe2aff16..0f4b9b6b 100644 --- a/srcs/requirements/svelte/api_front/src/old_unused/Login.svelte +++ b/srcs/requirements/svelte/api_front/old_unused/Login.svelte @@ -1,6 +1,6 @@ + + +
+ {#if user !== undefined} +
+ + + default user icon +
{user.username}
+
Rank: + + + + + + + + + + + + + + + + + {rank} + +
+
+

Match Statistics

+

Total: {user.stats.totalGame}

+

Victories: {user.stats.winGame}

+

Losses: {user.stats.loseGame}

+

Draws: {user.stats.drawGame}

+
+
+ {/if} +
+ +
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+ + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/old_unused/TwoFactorAuthentication_old.svelte b/srcs/requirements/svelte/api_front/old_unused/TwoFactorAuthentication_old.svelte new file mode 100644 index 00000000..f5526a04 --- /dev/null +++ b/srcs/requirements/svelte/api_front/old_unused/TwoFactorAuthentication_old.svelte @@ -0,0 +1,137 @@ + + +

2FA Test

+ +
+ +
+ +
+ {#if auth2} +

{auth2.json()}

+ {/if} +
+ +A QRCodeImg you must scan with google authenticator + + + + + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/old_unused/UserPage.svelte b/srcs/requirements/svelte/api_front/old_unused/UserPage.svelte similarity index 99% rename from srcs/requirements/svelte/api_front/src/old_unused/UserPage.svelte rename to srcs/requirements/svelte/api_front/old_unused/UserPage.svelte index 37c63f06..98c69c2f 100644 --- a/srcs/requirements/svelte/api_front/src/old_unused/UserPage.svelte +++ b/srcs/requirements/svelte/api_front/old_unused/UserPage.svelte @@ -35,7 +35,7 @@ let clickedLogout = async() => { console.log('clicked logout'); await fetch('http://transcendance:8080/api/v2/auth/logout',); - $loginStatus = false; + // $loginStatus = false; // maybe use replace() ? push('/'); }; diff --git a/srcs/requirements/svelte/api_front/src/old_unused/UserStore.js b/srcs/requirements/svelte/api_front/old_unused/UserStore.js similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/UserStore.js rename to srcs/requirements/svelte/api_front/old_unused/UserStore.js diff --git a/srcs/requirements/svelte/api_front/old_unused/loginStatusStore.js b/srcs/requirements/svelte/api_front/old_unused/loginStatusStore.js new file mode 100644 index 00000000..0e5420d0 --- /dev/null +++ b/srcs/requirements/svelte/api_front/old_unused/loginStatusStore.js @@ -0,0 +1,24 @@ +import { writable } from "svelte/store"; + +// an alternative way of doing things where i have a svelte store connected to localStorage + +// do in need to adapt this to work with 2fa? + +let _user = localStorage.getItem('42User'); + +// turns out a simple store is actually the easiest :) +// export const userStore = writable(_user ? JSON.parse(_user) : null); // we start with no user, but go get one if one exists +// export const userStore = writable(null); + +// ok so this will happen no matter what, basically we are telling it what to do if the store containing the user changes +userStore.subscribe((value) => { + if (value) + localStorage.setItem('42User', JSON.stringify(value)); + else + localStorage.removeItem('42User'); // for logout +}); + +export const userLogout = () => userStore.set(null); + + +// export const tmpStore = userStore \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/old_unused/loginStatusStore_old.js b/srcs/requirements/svelte/api_front/old_unused/loginStatusStore_old.js new file mode 100644 index 00000000..8070229c --- /dev/null +++ b/srcs/requirements/svelte/api_front/old_unused/loginStatusStore_old.js @@ -0,0 +1,129 @@ +import { writable } from "svelte/store"; + +// This is a "Custom Store" see that chapter in the Svelte Tutorial, should be fine +// NVM this is definitely overkill +// function createLogin() { +// const { subscribe, update } = writable(false); + +// return { +// subscribe, +// login: () => update(s => s = true), +// logout: () => update(s => s = false), +// } +// } +// export const loginStatus = createLogin(); + +// export const loginStatus = writable({ +// 42: false, +// tfa: false, +// }); + +// function createLoginStatus() { + +// //ok it really hated all this + +// // const store = writable({ +// // fortyTwo: false, +// // tfa: false, +// // }); + +// // return { +// // ...store, +// // subscribe, +// // // toggle42: () => update( l => l.fortyTwo = !l.fortyTwo ), +// // toggle42: () => store.update( fortyTwo => !fortyTwo ), +// // // toggleTFA: () => update( l => l.tfa = !l.tfa ), +// // toggleTFA: () => store.update( tfa => !tfa ), +// // isLogged: () => store.fortyTwo && store.tfa, +// // // isLogged: this.fortyTwo && this.tfa, +// // // it really doesn't like "this." +// // // isLogged: () => (this.tfa && this.fortyTwo), +// // // this. ? or (l) => l.tfa ... ? +// // } + + +// // doesn't seem to work... +// const { subscribe, update } = writable({ +// fortyTwo: false, +// tfa: false, +// }); + +// return { +// subscribe, +// // toggle42: () => update( l => l.fortyTwo = !l.fortyTwo ), +// toggle42: () => update( fortyTwo => !fortyTwo ), +// // toggleTFA: () => update( l => l.tfa = !l.tfa ), +// toggleTFA: () => update( tfa => !tfa ), +// // isLogged: () => fortyTwo && tfa, +// // isLogged: this.fortyTwo && this.tfa, +// // it really doesn't like "this." +// // isLogged: () => (this.tfa && this.fortyTwo), +// // this. ? or (l) => l.tfa ... ? +// isLogged() { +// return fortyTwo && tfa; +// }, +// } + +// // possible other way of doing this + +// // const store = writable({ +// // fortyTwo: false, +// // tfa: false, +// // }); + +// // return { +// // ...store, +// // subscribe, +// // // toggle42: () => update( l => l.fortyTwo = !l.fortyTwo ), +// // toggle42: () => store.update( l.fortyTwo => !l.fortyTwo ), +// // toggleTFA: () => store.update( l => l.tfa = !l.tfa ), +// // isLogged: store.fortyTwo && store.tfa, +// // // isLogged: () => (this.tfa && this.fortyTwo), +// // // this. ? or (l) => l.tfa ... ? +// // } + +// } + +function createLoginStatus() { + const { subscribe, update } = writable({ + fortyTwo: false, + tfa: false, + }); + + function toggle42() { + update( (old) => ({...old, fortyTwo: !old.fortyTwo}) ); + }; + + function toggleTFA() { + // update( () => { + // self.tfa = !self.tfa; + // return self; + // }) + // console.log("testing"); + update( (old) => ({...old, tfa: !old.tfa}) ); + }; + + function isLogged() { + // return (l) => {l.fortyTwo && l.tfa}; + // return self.fortyTwo && self.tfa; + // return fortyTwo && tfa; + }; + + return { subscribe, update, toggle42, toggleTFA, isLogged }; +} + +export const loginStatus = createLoginStatus(); + +// OK let's try a totally new approach + +// const _loginStatus = writable({ +// fortyTwo: false, +// tfa: false, +// }) + +// export const loginStatus = { +// subscribe: _loginStatus.subscribe, +// set: _loginStatus.set, +// update: _loginStatus.update, +// toggle42: () => +// } \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/old_unused/possible_fonts.css b/srcs/requirements/svelte/api_front/old_unused/possible_fonts.css similarity index 100% rename from srcs/requirements/svelte/api_front/src/old_unused/possible_fonts.css rename to srcs/requirements/svelte/api_front/old_unused/possible_fonts.css diff --git a/srcs/requirements/svelte/api_front/old_unused/primaryRoutes.svelte b/srcs/requirements/svelte/api_front/old_unused/primaryRoutes.svelte new file mode 100644 index 00000000..4c254fec --- /dev/null +++ b/srcs/requirements/svelte/api_front/old_unused/primaryRoutes.svelte @@ -0,0 +1,177 @@ + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff b/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff new file mode 100644 index 00000000..72c8b293 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff differ diff --git a/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff2 b/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff2 new file mode 100644 index 00000000..27d538bf Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/fonts/Bit5x3.woff2 differ diff --git a/srcs/requirements/svelte/api_front/public/game/audio.ts b/srcs/requirements/svelte/api_front/public/game/audio.ts new file mode 100644 index 00000000..74c73336 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/audio.ts @@ -0,0 +1,16 @@ + +import * as c from "./constants.js" + +export const soundPongArr: HTMLAudioElement[] = []; +export const soundRoblox = new Audio("http://localhost:8080/sound/roblox-oof.ogg"); + +export function initAudio(muteFlag: boolean) +{ + for (let i = 0; i <= 32; i++) { + soundPongArr.push(new Audio("http://localhost:8080/sound/pong/"+i+".ogg")); + soundPongArr[i].volume = c.soundPongVolume; + soundPongArr[i].muted = muteFlag; + } + soundRoblox.volume = c.soundRobloxVolume; + soundRoblox.muted = muteFlag; +} diff --git a/srcs/requirements/svelte/api_front/public/game/class/Event.ts b/srcs/requirements/svelte/api_front/public/game/class/Event.ts new file mode 100644 index 00000000..3f0d440a --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/Event.ts @@ -0,0 +1,107 @@ + +import * as en from "../enums.js" + +/* From Server */ +class ServerEvent { + type: en.EventTypes; + constructor(type: en.EventTypes = 0) { + this.type = type; + } +} + +class EventAssignId extends ServerEvent { + id: string; + constructor(id: string) { + super(en.EventTypes.assignId); + this.id = id; + } +} + +class EventMatchmakingComplete extends ServerEvent { + side: en.PlayerSide; + constructor(side: en.PlayerSide) { + super(en.EventTypes.matchmakingComplete); + this.side = side; + } +} + +class EventGameUpdate extends ServerEvent { + playerLeft = { + y: 0 + }; + playerRight = { + y: 0 + }; + ballsArr: { + x: number, + y: number, + dirX: number, + dirY: number, + speed: number + }[] = []; + wallTop? = { + y: 0 + }; + wallBottom? = { + y: 0 + }; + lastInputId = 0; + constructor() { // TODO: constructor that take GameComponentsServer maybe ? + super(en.EventTypes.gameUpdate); + } +} + +class EventScoreUpdate extends ServerEvent { + scoreLeft: number; + scoreRight: number; + constructor(scoreLeft: number, scoreRight: number) { + super(en.EventTypes.scoreUpdate); + this.scoreLeft = scoreLeft; + this.scoreRight = scoreRight; + } +} + +class EventMatchEnd extends ServerEvent { + winner: en.PlayerSide; + constructor(winner: en.PlayerSide) { + super(en.EventTypes.matchEnd); + this.winner = winner; + } +} + + +/* From Client */ +class ClientEvent { + type: en.EventTypes; // readonly ? + constructor(type: en.EventTypes = 0) { + this.type = type; + } +} + +class ClientAnnounce extends ClientEvent { + role: en.ClientRole; + clientId: string; + matchOptions: en.MatchOptions; + constructor(role: en.ClientRole, matchOptions: en.MatchOptions, clientId: string = "") { + super(en.EventTypes.clientAnnounce); + this.role = role; + this.clientId = clientId; + this.matchOptions = matchOptions; + } +} + +class EventInput extends ClientEvent { + input: en.InputEnum; + id: number; + constructor(input: en.InputEnum = en.InputEnum.noInput, id: number = 0) { + super(en.EventTypes.clientInput); + this.input = input; + this.id = id; + } +} + +export { + ServerEvent, EventAssignId, EventMatchmakingComplete, + EventGameUpdate, EventScoreUpdate, EventMatchEnd, + ClientEvent, ClientAnnounce, EventInput +} diff --git a/srcs/requirements/svelte/api_front/public/game/class/GameArea.ts b/srcs/requirements/svelte/api_front/public/game/class/GameArea.ts new file mode 100644 index 00000000..e6921e4e --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/GameArea.ts @@ -0,0 +1,38 @@ + +import * as c from ".././constants.js" + +class GameArea { + keys: string[] = []; + handleInputInterval: number = 0; + gameLoopInterval: number = 0; + drawLoopInterval: number = 0; + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + constructor() { + this.canvas = document.createElement("canvas"); + this.ctx = this.canvas.getContext("2d") as CanvasRenderingContext2D; + this.canvas.width = c.CanvasWidth; + this.canvas.height = c.CanvasWidth / c.CanvasRatio; + let container = document.getElementById("canvas_container"); + if (container) + container.insertBefore(this.canvas, container.childNodes[0]); + } + addKey(key: string) { + key = key.toLowerCase(); + var i = this.keys.indexOf(key); + if (i == -1) + this.keys.push(key); + } + deleteKey(key: string) { + key = key.toLowerCase(); + var i = this.keys.indexOf(key); + if (i != -1) { + this.keys.splice(i, 1); + } + } + clear() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } +} + +export {GameArea} diff --git a/srcs/requirements/svelte/api_front/public/game/class/GameComponents.ts b/srcs/requirements/svelte/api_front/public/game/class/GameComponents.ts new file mode 100644 index 00000000..10e60932 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/GameComponents.ts @@ -0,0 +1,65 @@ + +import * as c from "../constants.js" +import * as en from "../../shared_js/enums.js" +import { VectorInteger } from "./Vector.js"; +import { Rectangle, MovingRectangle, Racket, Ball } from "./Rectangle.js"; +import { random } from "../utils.js"; + +class GameComponents { + wallTop: Rectangle | MovingRectangle; + wallBottom: Rectangle | MovingRectangle; + playerLeft: Racket; + playerRight: Racket; + ballsArr: Ball[] = []; + constructor(options: en.MatchOptions) + { + const pos = new VectorInteger; + + // Rackets + pos.assign(0+c.pw, c.h_mid-c.ph/2); + this.playerLeft = new Racket(pos, c.pw, c.ph, c.racketSpeed); + pos.assign(c.w-c.pw-c.pw, c.h_mid-c.ph/2); + this.playerRight = new Racket(pos, c.pw, c.ph, c.racketSpeed); + + // Balls + let ballsCount = 1; + if (options & en.MatchOptions.multiBalls) { + ballsCount = c.multiBallsCount; + } + pos.assign(-c.ballSize, -c.ballSize); // ball out =) + while (this.ballsArr.length < ballsCount) { + this.ballsArr.push(new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease)) + } + this.ballsArr.forEach((ball) => { + ball.dir.x = 1; + if (random() > 0.5) { + ball.dir.x *= -1; + } + + ball.dir.y = random(0, 0.2); + if (random() > 0.5) { + ball.dir.y *= -1; + } + + ball.dir = ball.dir.normalized(); + }); + + // Walls + if (options & en.MatchOptions.movingWalls) { + pos.assign(0, 0); + this.wallTop = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed); + (this.wallTop).dir.y = -1; + pos.assign(0, c.h-c.wallSize); + this.wallBottom = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed); + (this.wallBottom).dir.y = 1; + } + else { + pos.assign(0, 0); + this.wallTop = new Rectangle(pos, c.w, c.wallSize); + pos.assign(0, c.h-c.wallSize); + this.wallBottom = new Rectangle(pos, c.w, c.wallSize); + } + } +} + +export {GameComponents} diff --git a/srcs/requirements/svelte/api_front/public/game/class/GameComponentsClient.ts b/srcs/requirements/svelte/api_front/public/game/class/GameComponentsClient.ts new file mode 100644 index 00000000..bf90f66f --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/GameComponentsClient.ts @@ -0,0 +1,114 @@ + +import * as c from "../constants.js" +import * as en from "../../shared_js/enums.js" +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { TextElem, TextNumericValue } from "./Text.js"; +import { RectangleClient, MovingRectangleClient, RacketClient, BallClient, Line } from "./RectangleClient.js"; +import { GameComponents } from "../../shared_js/class/GameComponents.js"; +import { MovingRectangle } from "../../shared_js/class/Rectangle.js"; + +class GameComponentsExtensionForClient extends GameComponents { + wallTop: RectangleClient | MovingRectangleClient; + wallBottom: RectangleClient | MovingRectangleClient; + playerLeft: RacketClient; + playerRight: RacketClient; + ballsArr: BallClient[]; + constructor(options: en.MatchOptions, ctx: CanvasRenderingContext2D) + { + super(options); + + // Rackets + const basePL = this.playerLeft; + const basePR = this.playerRight; + this.playerLeft = new RacketClient( + basePL.pos, basePL.width, basePL.height, basePL.baseSpeed, + ctx, "white"); + this.playerRight = new RacketClient( + basePR.pos, basePR.width, basePR.height, basePR.baseSpeed, + ctx, "white"); + + // Balls + const newBallsArr: BallClient[] = []; + this.ballsArr.forEach((ball) => { + newBallsArr.push(new BallClient(ball.pos, ball.width, ball.baseSpeed, ball.speedIncrease, + ctx, "white") + ); + }); + this.ballsArr = newBallsArr; + + // Walls + if (options & en.MatchOptions.movingWalls) + { + const baseWT = this.wallTop; + const baseWB = this.wallBottom; + + this.wallTop = new MovingRectangleClient(baseWT.pos, baseWT.width, baseWT.height, baseWT.baseSpeed, + ctx, "grey"); + (this.wallTop).dir.assign(baseWT.dir.x, baseWT.dir.y); + + this.wallBottom = new MovingRectangleClient(baseWB.pos, baseWB.width, baseWB.height, baseWB.baseSpeed, + ctx, "grey"); + (this.wallBottom).dir.assign(baseWB.dir.x, baseWB.dir.y); + } + else + { + const baseWT = this.wallTop; + const baseWB = this.wallBottom; + this.wallTop = new RectangleClient(baseWT.pos, baseWT.width, baseWT.height, + ctx, "grey"); + this.wallBottom = new RectangleClient(baseWB.pos, baseWB.width, baseWB.height, + ctx, "grey"); + } + } +} + + +class GameComponentsClient extends GameComponentsExtensionForClient { + midLine: Line; + scoreLeft: TextNumericValue; + scoreRight: TextNumericValue; + text1: TextElem; + + w_grid_mid: RectangleClient; + w_grid_u1: RectangleClient; + w_grid_d1: RectangleClient; + h_grid_mid: RectangleClient; + h_grid_u1: RectangleClient; + h_grid_d1: RectangleClient; + constructor(options: en.MatchOptions, ctx: CanvasRenderingContext2D) + { + super(options, ctx); + let pos = new VectorInteger; + // Scores + pos.assign(c.w_mid-c.scoreSize*1.6, c.scoreSize*1.5); + this.scoreLeft = new TextNumericValue(pos, c.scoreSize, ctx, "white"); + pos.assign(c.w_mid+c.scoreSize*1.1, c.scoreSize*1.5); + this.scoreRight = new TextNumericValue(pos, c.scoreSize, ctx, "white"); + this.scoreLeft.value = 0; + this.scoreRight.value = 0; + + // Text + pos.assign(0, c.h_mid); + this.text1 = new TextElem(pos, Math.floor(c.w/8), ctx, "white"); + + // Dotted Midline + pos.assign(c.w_mid-c.midLineSize/2, 0+c.wallSize); + this.midLine = new Line(pos, c.midLineSize, c.h-c.wallSize*2, ctx, "white", 15); + + // Grid + pos.assign(0, c.h_mid); + this.w_grid_mid = new RectangleClient(pos, c.w, c.gridSize, ctx, "darkgreen"); + pos.assign(0, c.h/4); + this.w_grid_u1 = new RectangleClient(pos, c.w, c.gridSize, ctx, "darkgreen"); + pos.assign(0, c.h-c.h/4); + this.w_grid_d1 = new RectangleClient(pos, c.w, c.gridSize, ctx, "darkgreen"); + pos.assign(c.w_mid, 0); + this.h_grid_mid = new RectangleClient(pos, c.gridSize, c.h, ctx, "darkgreen"); + pos.assign(c.w/4, 0); + this.h_grid_u1 = new RectangleClient(pos, c.gridSize, c.h, ctx, "darkgreen"); + pos.assign(c.w-c.w/4, 0); + this.h_grid_d1 = new RectangleClient(pos, c.gridSize, c.h, ctx, "darkgreen"); + } +} + +export {GameComponentsClient} diff --git a/srcs/requirements/svelte/api_front/public/game/class/InputHistory.ts b/srcs/requirements/svelte/api_front/public/game/class/InputHistory.ts new file mode 100644 index 00000000..e4d3b8f1 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/InputHistory.ts @@ -0,0 +1,16 @@ + +import * as en from "../../shared_js/enums.js" +import * as ev from "../../shared_js/class/Event.js" + +class InputHistory { + input: en.InputEnum; + id: number; + deltaTime: number; + constructor(inputState: ev.EventInput, deltaTime: number) { + this.input = inputState.input; + this.id = inputState.id; + this.deltaTime = deltaTime; + } +} + +export {InputHistory} diff --git a/srcs/requirements/svelte/api_front/public/game/class/Rectangle.ts b/srcs/requirements/svelte/api_front/public/game/class/Rectangle.ts new file mode 100644 index 00000000..fff71dc9 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/Rectangle.ts @@ -0,0 +1,144 @@ + +import { Vector, VectorInteger } from "./Vector.js"; +import { Component, Moving } from "./interface.js"; +import * as c from "../constants.js" + +class Rectangle implements Component { + pos: VectorInteger; + width: number; + height: number; + constructor(pos: VectorInteger, width: number, height: number) { + this.pos = new VectorInteger(pos.x, pos.y); + this.width = width; + this.height = height; + } + collision(collider: Rectangle): boolean { + const thisLeft = this.pos.x; + const thisRight = this.pos.x + this.width; + const thisTop = this.pos.y; + const thisBottom = this.pos.y + this.height; + const colliderLeft = collider.pos.x; + const colliderRight = collider.pos.x + collider.width; + const colliderTop = collider.pos.y; + const colliderBottom = collider.pos.y + collider.height; + if ((thisBottom < colliderTop) + || (thisTop > colliderBottom) + || (thisRight < colliderLeft) + || (thisLeft > colliderRight)) { + return false; + } + else { + return true; + } + } +} + +class MovingRectangle extends Rectangle implements Moving { + dir: Vector = new Vector(0,0); + speed: number; + readonly baseSpeed: number; + constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) { + super(pos, width, height); + this.baseSpeed = baseSpeed; + this.speed = baseSpeed; + } + move(delta: number) { // Math.floor WIP until VectorInteger debug + // console.log(`delta: ${delta}, speed: ${this.speed}, speed*delta: ${this.speed * delta}`); + // this.pos.x += Math.floor(this.dir.x * this.speed * delta); + // this.pos.y += Math.floor(this.dir.y * this.speed * delta); + this.pos.x += this.dir.x * this.speed * delta; + this.pos.y += this.dir.y * this.speed * delta; + } + moveAndCollide(delta: number, colliderArr: Rectangle[]) { + this._moveAndCollideAlgo(delta, colliderArr); + } + protected _moveAndCollideAlgo(delta: number, colliderArr: Rectangle[]) { + let oldPos = new VectorInteger(this.pos.x, this.pos.y); + this.move(delta); + if (colliderArr.some(this.collision, this)) { + this.pos = oldPos; + } + } +} + +class Racket extends MovingRectangle { + constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) { + super(pos, width, height, baseSpeed); + } + moveAndCollide(delta: number, colliderArr: Rectangle[]) { + // let oldPos = new VectorInteger(this.pos.x, this.pos.y); // debug + this._moveAndCollideAlgo(delta, colliderArr); + // console.log(`y change: ${this.pos.y - oldPos.y}`); + } +} + +class Ball extends MovingRectangle { + readonly speedIncrease: number; + ballInPlay: boolean = false; + constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number) { + super(pos, size, size, baseSpeed); + this.speedIncrease = speedIncrease; + } + bounce(collider?: Rectangle) { + this._bounceAlgo(collider); + } + protected _bounceAlgo(collider?: Rectangle) { + /* Could be more generic, but testing only Racket is enough, + because in Pong collider can only be Racket or Wall. */ + if (collider instanceof Racket) { + this._bounceRacket(collider); + } + else { + this._bounceWall(); + } + } + moveAndBounce(delta: number, colliderArr: Rectangle[]) { + this.move(delta); + let i = colliderArr.findIndex(this.collision, this); + if (i != -1) + { + this.bounce(colliderArr[i]); + this.move(delta); + } + } + protected _bounceWall() { // Should be enough for Wall + this.dir.y = this.dir.y * -1; + } + protected _bounceRacket(racket: Racket) { + this._bounceRacketAlgo(racket); + } + protected _bounceRacketAlgo(racket: Racket) { + this.speed += this.speedIncrease; + + let x = this.dir.x * -1; + + const angleFactorDegree = 60; + const angleFactor = angleFactorDegree / 90; + const racketHalf = racket.height/2; + const ballMid = this.pos.y + this.height/2; + const racketMid = racket.pos.y + racketHalf; + + let impact = ballMid - racketMid; + const horizontalMargin = racketHalf * 0.15; + if (impact < horizontalMargin && impact > -horizontalMargin) { + impact = 0; + } + else if (impact > 0) { + impact = impact - horizontalMargin; + } + else if (impact < 0) { + impact = impact + horizontalMargin; + } + + let y = impact / (racketHalf - horizontalMargin) * angleFactor; + + this.dir.assign(x, y); + // Normalize Vector (for consistency in speed independent of direction) + if (c.normalizedSpeed) { + this.dir = this.dir.normalized(); + } + // console.log(`x: ${this.dir.x}, y: ${this.dir.y}`); + } +} + +export {Rectangle, MovingRectangle, Racket, Ball} diff --git a/srcs/requirements/svelte/api_front/public/game/class/RectangleClient.ts b/srcs/requirements/svelte/api_front/public/game/class/RectangleClient.ts new file mode 100644 index 00000000..5c251704 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/RectangleClient.ts @@ -0,0 +1,141 @@ + +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { Component, GraphicComponent, Moving } from "../../shared_js/class/interface.js"; +import { Rectangle, MovingRectangle, Racket, Ball } from "../../shared_js/class/Rectangle.js"; +import { soundPongArr } from "../audio.js" +import { random } from "../utils.js"; + +function updateRectangle(this: RectangleClient) { + this.ctx.fillStyle = this.color; + this.ctx.fillRect(this.pos.x, this.pos.y, this.width, this.height); +} + +function clearRectangle(this: RectangleClient, pos?: VectorInteger) { + if (pos) + this.ctx.clearRect(pos.x, pos.y, this.width, this.height); + else + this.ctx.clearRect(this.pos.x, this.pos.y, this.width, this.height); +} + +class RectangleClient extends Rectangle implements GraphicComponent { + ctx: CanvasRenderingContext2D; + color: string; + update: () => void; + clear: (pos?: VectorInteger) => void; + constructor(pos: VectorInteger, width: number, height: number, + ctx: CanvasRenderingContext2D, color: string) + { + super(pos, width, height); + this.ctx = ctx; + this.color = color; + this.update = updateRectangle; + this.clear = clearRectangle; + } + // update() { + // this.ctx.fillStyle = this.color; + // this.ctx.fillRect(this.pos.x, this.pos.y, this.width, this.height); + // } + // clear(pos?: VectorInteger) { + // if (pos) + // this.ctx.clearRect(pos.x, pos.y, this.width, this.height); + // else + // this.ctx.clearRect(this.pos.x, this.pos.y, this.width, this.height); + // } +} + +class MovingRectangleClient extends MovingRectangle implements GraphicComponent { + ctx: CanvasRenderingContext2D; + color: string; + update: () => void; + clear: (pos?: VectorInteger) => void; + constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number, + ctx: CanvasRenderingContext2D, color: string) + { + super(pos, width, height, baseSpeed); + this.ctx = ctx; + this.color = color; + this.update = updateRectangle; + this.clear = clearRectangle; + } +} + +class RacketClient extends Racket implements GraphicComponent { + ctx: CanvasRenderingContext2D; + color: string; + update: () => void; + clear: (pos?: VectorInteger) => void; + constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number, + ctx: CanvasRenderingContext2D, color: string) + { + super(pos, width, height, baseSpeed); + this.ctx = ctx; + this.color = color; + this.update = updateRectangle; + this.clear = clearRectangle; + } +} + +class BallClient extends Ball implements GraphicComponent { + ctx: CanvasRenderingContext2D; + color: string; + update: () => void; + clear: (pos?: VectorInteger) => void; + constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number, + ctx: CanvasRenderingContext2D, color: string) + { + super(pos, size, baseSpeed, speedIncrease); + this.ctx = ctx; + this.color = color; + this.update = updateRectangle; + this.clear = clearRectangle; + } + bounce(collider?: Rectangle) { + this._bounceAlgo(collider); + soundPongArr[ Math.floor(random(0, soundPongArr.length)) ].play(); + } + /* protected _bounceRacket(collider: Racket) { + this._bounceRacketAlgo(collider); + soundRoblox.play(); + } */ +} + +function updateLine(this: Line) { + this.ctx.fillStyle = this.color; + let pos: VectorInteger = new VectorInteger; + let i = 0; + while (i < this.segmentCount) + { + // for Horizontal Line + // pos.y = this.pos.y; + // pos.x = this.pos.x + this.segmentWidth * i; + pos.x = this.pos.x; + pos.y = this.pos.y + this.segmentHeight * i; + this.ctx.fillRect(pos.x, pos.y, this.segmentWidth, this.segmentHeight); + i += 2; + } +} + +class Line extends RectangleClient { + gapeCount: number = 0; + segmentCount: number; + segmentWidth: number; + segmentHeight: number; + constructor(pos: VectorInteger, width: number, height: number, + ctx: CanvasRenderingContext2D, color: string, gapeCount?: number) + { + super(pos, width, height, ctx, color); + this.update = updateLine; + if (gapeCount) + this.gapeCount = gapeCount; + this.segmentCount = this.gapeCount * 2 + 1; + + this.segmentWidth = this.width; + this.segmentHeight = this.height / this.segmentCount; + + // for Horizontal Line + // this.segmentWidth = this.width / this.segmentCount; + // this.segmentHeight = this.height; + } +} + +export {RectangleClient, MovingRectangleClient, RacketClient, BallClient, Line} diff --git a/srcs/requirements/svelte/api_front/public/game/class/Text.ts b/srcs/requirements/svelte/api_front/public/game/class/Text.ts new file mode 100644 index 00000000..88111131 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/Text.ts @@ -0,0 +1,58 @@ + +import { Vector, VectorInteger } from "../../shared_js/class/Vector.js"; +import { Component } from "../../shared_js/class/interface.js"; + +// conflict with Text +class TextElem implements Component { + ctx: CanvasRenderingContext2D; + pos: VectorInteger; + color: string; + size: number; + font: string; + text: string = ""; + constructor(pos: VectorInteger, size: number, + ctx: CanvasRenderingContext2D, color: string, font: string = "Bit5x3") + { + // this.pos = Object.assign({}, pos); // create bug, Uncaught TypeError: X is not a function + this.pos = new VectorInteger(pos.x, pos.y); + this.size = size; + this.ctx = ctx; + this.color = color; + this.font = font; + } + update() { + this.ctx.font = this.size + "px" + " " + this.font; + this.ctx.fillStyle = this.color; + this.ctx.fillText(this.text, this.pos.x, this.pos.y); + } + clear() { + // clear no very accurate for Text + // https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics + let textMetric = this.ctx.measureText(this.text); + // console.log("textMetric.width = "+textMetric.width); + // console.log("size = "+this.size); + // console.log("x = "+this.pos.x); + // console.log("y = "+this.pos.y); + this.ctx.clearRect(this.pos.x - 1, this.pos.y-this.size + 1, textMetric.width, this.size); + // +1 and -1 because float imprecision (and Math.floor() with VectorInteger dont work for the moment) + // (or maybe its textMetric imprecision ?) + } +} + +class TextNumericValue extends TextElem { + private _value: number = 0; + constructor(pos: VectorInteger, size: number, + ctx: CanvasRenderingContext2D, color: string, font?: string) + { + super(pos, size, ctx, color, font); + } + get value() { + return this._value; + } + set value(v: number) { + this._value = v; + this.text = v.toString(); + } +} + +export {TextElem, TextNumericValue} diff --git a/srcs/requirements/svelte/api_front/public/game/class/Vector.ts b/srcs/requirements/svelte/api_front/public/game/class/Vector.ts new file mode 100644 index 00000000..025bca36 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/Vector.ts @@ -0,0 +1,49 @@ + +class Vector { + x: number; + y: number; + constructor(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + assign(x: number, y: number) { + this.x = x; + this.y = y; + } + normalized() : Vector { + const normalizationFactor = Math.abs(this.x) + Math.abs(this.y); + return new Vector(this.x/normalizationFactor, this.y/normalizationFactor); + } +} + +class VectorInteger extends Vector { + // PLACEHOLDER + // VectorInteger with set/get dont work (No draw on the screen). Why ? +} + +/* +class VectorInteger { + // private _x: number = 0; + // private _y: number = 0; + // constructor(x: number = 0, y: number = 0) { + // this._x = x; + // this._y = y; + // } + // get x(): number { + // return this._x; + // } + // set x(v: number) { + // // this._x = Math.floor(v); + // this._x = v; + // } + // get y(): number { + // return this._y; + // } + // set y(v: number) { + // // this._y = Math.floor(v); + // this._y = v; + // } +} +*/ + +export {Vector, VectorInteger} diff --git a/srcs/requirements/svelte/api_front/public/game/class/interface.ts b/srcs/requirements/svelte/api_front/public/game/class/interface.ts new file mode 100644 index 00000000..39753de1 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/class/interface.ts @@ -0,0 +1,21 @@ + +import { Vector, VectorInteger } from "./Vector.js"; + +interface Component { + pos: VectorInteger; +} + +interface GraphicComponent extends Component { + ctx: CanvasRenderingContext2D; + color: string; + update: () => void; + clear: (pos?: VectorInteger) => void; +} + +interface Moving { + dir: Vector; + speed: number; // pixel per second + move(delta: number): void; +} + +export {Component, GraphicComponent, Moving} diff --git a/srcs/requirements/svelte/api_front/public/game/constants copy.ts b/srcs/requirements/svelte/api_front/public/game/constants copy.ts new file mode 100644 index 00000000..ae3320e5 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/constants copy.ts @@ -0,0 +1,26 @@ + +export const CanvasWidth = 1500; +export const CanvasRatio = 1.66666; +/* ratio 5/3 (1.66) */ + +export const w = CanvasWidth; +export const h = CanvasWidth / CanvasRatio; +export const w_mid = Math.floor(w/2); +export const h_mid = Math.floor(h/2); +export const pw = Math.floor(w*0.017); +export const ph = pw*6; +export const ballSize = pw; +export const wallSize = Math.floor(w*0.01); +export const racketSpeed = Math.floor(w*0.66); // pixel per second +export const ballSpeed = Math.floor(w*0.66); // pixel per second +export const ballSpeedIncrease = Math.floor(ballSpeed*0.05); // pixel per second + +export const normalizedSpeed = false; // for consistency in speed independent of direction + +export const matchStartDelay = 3000; // millisecond +export const newRoundDelay = 1500; // millisecond + +// Game Variantes +export const multiBallsCount = 3; +export const movingWallPosMax = Math.floor(w*0.12); +export const movingWallSpeed = Math.floor(w*0.08); diff --git a/srcs/requirements/svelte/api_front/public/game/constants.ts b/srcs/requirements/svelte/api_front/public/game/constants.ts new file mode 100644 index 00000000..97bae265 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/constants.ts @@ -0,0 +1,18 @@ + +import { w } from "../shared_js/constants.js" +export * from "../shared_js/constants.js" + +export const midLineSize = Math.floor(w/150); +export const scoreSize = Math.floor(w/16); +export const gridSize = Math.floor(w/500); + +// min interval on Firefox seems to be 15. Chrome can go lower. +export const handleInputIntervalMS = 15; // millisecond +export const sendLoopIntervalMS = 15; // millisecond // unused +export const gameLoopIntervalMS = 15; // millisecond +export const drawLoopIntervalMS = 15; // millisecond + +export const fixedDeltaTime = gameLoopIntervalMS/1000; // second + +export const soundRobloxVolume = 0.3; // between 0 and 1 +export const soundPongVolume = 0.3; // between 0 and 1 diff --git a/srcs/requirements/svelte/api_front/public/game/draw.ts b/srcs/requirements/svelte/api_front/public/game/draw.ts new file mode 100644 index 00000000..984c2acb --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/draw.ts @@ -0,0 +1,51 @@ + +import { pong, gc } from "./global.js" +import * as c from "./constants.js" +import * as en from "../shared_js/enums.js" +import { gridDisplay } from "./handleInput.js"; + +function drawLoop() +{ + pong.clear(); + + if (gridDisplay) { + drawGrid(); + } + + drawStatic(); + + gc.text1.update(); + + drawDynamic(); +} + +function drawDynamic() +{ + gc.scoreLeft.update(); + gc.scoreRight.update(); + gc.playerLeft.update(); + gc.playerRight.update(); + gc.ballsArr.forEach((ball) => { + ball.update(); + }); +} + +function drawStatic() +{ + gc.midLine.update(); + gc.wallTop.update(); + gc.wallBottom.update(); +} + +function drawGrid() +{ + gc.w_grid_mid.update(); + gc.w_grid_u1.update(); + gc.w_grid_d1.update(); + + gc.h_grid_mid.update(); + gc.h_grid_u1.update(); + gc.h_grid_d1.update(); +} + +export {drawLoop} diff --git a/srcs/requirements/svelte/api_front/public/game/enums.ts b/srcs/requirements/svelte/api_front/public/game/enums.ts new file mode 100644 index 00000000..dfba2aa3 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/enums.ts @@ -0,0 +1,47 @@ + +enum EventTypes { + // Class Implemented + gameUpdate = 1, + scoreUpdate, + matchEnd, + assignId, + matchmakingComplete, + + // Generic + matchmakingInProgress, + matchStart, + matchNewRound, // unused + matchPause, // unused + matchResume, // unused + + // Client + clientAnnounce, + clientPlayerReady, + clientInput, + +} + +enum InputEnum { + noInput = 0, + up = 1, + down, +} + +enum PlayerSide { + left = 1, + right +} + +enum ClientRole { + player = 1, + spectator +} + +enum MatchOptions { + // binary flags, can be mixed + noOption = 0b0, + multiBalls = 1 << 0, + movingWalls = 1 << 1 +} + +export {EventTypes, InputEnum, PlayerSide, ClientRole, MatchOptions} diff --git a/srcs/requirements/svelte/api_front/public/game/gameLoop.ts b/srcs/requirements/svelte/api_front/public/game/gameLoop.ts new file mode 100644 index 00000000..593d1eaa --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/gameLoop.ts @@ -0,0 +1,49 @@ + +import * as c from "./constants.js"; +import * as en from "../shared_js/enums.js" +import { gc, matchOptions, clientInfo } from "./global.js"; +import { wallsMovements } from "../shared_js/wallsMovement.js"; + +let actual_time: number = Date.now(); +let last_time: number; +let delta_time: number; + +function gameLoop() +{ + /* last_time = actual_time; + actual_time = Date.now(); + delta_time = (actual_time - last_time) / 1000; */ + + delta_time = c.fixedDeltaTime; + // console.log(`delta_gameLoop: ${delta_time}`); + + // interpolation + // console.log(`dir.y: ${clientInfo.opponent.dir.y}, pos.y: ${clientInfo.opponent.pos.y}, opponentNextPos.y: ${clientInfo.opponentNextPos.y}`); + if (clientInfo.opponent.dir.y != 0 ) { + opponentInterpolation(delta_time); + } + + // client prediction + gc.ballsArr.forEach((ball) => { + ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); + }); + + if (matchOptions & en.MatchOptions.movingWalls) { + wallsMovements(delta_time, gc); + } +} + +function opponentInterpolation(delta: number) +{ + // interpolation + clientInfo.opponent.moveAndCollide(delta, [gc.wallTop, gc.wallBottom]); + + if ((clientInfo.opponent.dir.y > 0 && clientInfo.opponent.pos.y > clientInfo.opponentNextPos.y) + || (clientInfo.opponent.dir.y < 0 && clientInfo.opponent.pos.y < clientInfo.opponentNextPos.y)) + { + clientInfo.opponent.dir.y = 0; + clientInfo.opponent.pos.y = clientInfo.opponentNextPos.y; + } +} + +export {gameLoop} diff --git a/srcs/requirements/svelte/api_front/public/game/global.ts b/srcs/requirements/svelte/api_front/public/game/global.ts new file mode 100644 index 00000000..7d0a7126 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/global.ts @@ -0,0 +1,3 @@ + +export {pong, gc, matchOptions} from "./pong.js" +export {socket, clientInfo} from "./ws.js" diff --git a/srcs/requirements/svelte/api_front/public/game/handleInput.ts b/srcs/requirements/svelte/api_front/public/game/handleInput.ts new file mode 100644 index 00000000..164680e1 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/handleInput.ts @@ -0,0 +1,110 @@ + +import { pong, gc, socket, clientInfo } from "./global.js" +import * as ev from "../shared_js/class/Event.js" +import * as en from "../shared_js/enums.js" +import { InputHistory } from "./class/InputHistory.js" +import * as c from "./constants.js"; + +export let gridDisplay = false; + +let actual_time: number = Date.now(); +let last_time: number; +let delta_time: number; + +const inputState: ev.EventInput = new ev.EventInput(); +const inputHistoryArr: InputHistory[] = []; + +// test +/* export function sendLoop() +{ + socket.send(JSON.stringify(inputState)); +} */ + +function handleInput() +{ + /* last_time = actual_time; + actual_time = Date.now(); + delta_time = (actual_time - last_time) / 1000; */ + + delta_time = c.fixedDeltaTime; + // console.log(`delta_time: ${delta_time}`); + + inputState.id = Date.now(); + inputState.input = en.InputEnum.noInput; + + const keys = pong.keys; + if (keys.length !== 0) + { + if (keys.indexOf("g") != -1) + { + gridDisplay = !gridDisplay; + pong.deleteKey("g"); + } + playerMovements(delta_time, keys); + } + + socket.send(JSON.stringify(inputState)); + // setTimeout(testInputDelay, 100); + inputHistoryArr.push(new InputHistory(inputState, delta_time)); + + // client prediction + if (inputState.input !== en.InputEnum.noInput) { + // TODO: peut-etre le mettre dans game loop ? + // Attention au delta time dans ce cas ! + playerMovePrediction(delta_time, inputState.input); + } +} + +function playerMovements(delta: number, keys: string[]) +{ + if (keys.indexOf("w") !== -1 || keys.indexOf("ArrowUp".toLowerCase()) !== -1) + { + if (keys.indexOf("s") === -1 && keys.indexOf("ArrowDown".toLowerCase()) === -1) { + inputState.input = en.InputEnum.up; + } + } + else if (keys.indexOf("s") !== -1 || keys.indexOf("ArrowDown".toLowerCase()) !== -1) { + inputState.input = en.InputEnum.down; + } +} + +function testInputDelay() { + socket.send(JSON.stringify(inputState)); +} + + +function playerMovePrediction(delta: number, input: en.InputEnum) +{ + // client prediction + const racket = clientInfo.racket; + if (input === en.InputEnum.up) { + racket.dir.y = -1; + } + else if (input === en.InputEnum.down) { + racket.dir.y = 1; + } + racket.moveAndCollide(delta, [gc.wallTop, gc.wallBottom]); +} + +function repeatInput(lastInputId: number) +{ + // server reconciliation + let i = inputHistoryArr.findIndex((value: InputHistory) => { + if (value.id === lastInputId) { + return true; + } + return false; + }); + + // console.log(`inputHistory total: ${inputHistoryArr.length}` ); + inputHistoryArr.splice(0, i+1); + // console.log(`inputHistory left: ${inputHistoryArr.length}` ); + + inputHistoryArr.forEach((value: InputHistory) => { + if (value.input !== en.InputEnum.noInput) { + playerMovePrediction(value.deltaTime, value.input); + } + }); +} + +export {handleInput, repeatInput} diff --git a/srcs/requirements/svelte/api_front/public/game/pong.ts b/srcs/requirements/svelte/api_front/public/game/pong.ts new file mode 100644 index 00000000..5c9dcce0 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/pong.ts @@ -0,0 +1,99 @@ + +initDom(); +function initDom() { + document.getElementById("play_pong_button").addEventListener("click", init); +} + +import * as c from "./constants.js" +import * as en from "../shared_js/enums.js" +import { GameArea } from "./class/GameArea.js"; +import { GameComponentsClient } from "./class/GameComponentsClient.js"; +import { handleInput } from "./handleInput.js"; +// import { sendLoop } from "./handleInput.js"; +import { gameLoop } from "./gameLoop.js" +import { drawLoop } from "./draw.js"; +import { countdown } from "./utils.js"; +import { initWebSocket } from "./ws.js"; +import { initAudio } from "./audio.js"; + + +/* Keys + Racket: W/S OR Up/Down + Grid On-Off: G +*/ + +/* TODO: A way to delay the init of variables, but still use "const" not "let" ? */ +export let pong: GameArea; +export let gc: GameComponentsClient; +export let matchOptions: en.MatchOptions = en.MatchOptions.noOption; + +function init() +{ + console.log("multi_balls:"+(document.getElementById("multi_balls")).checked); + console.log("moving_walls:"+(document.getElementById("moving_walls")).checked); + console.log("sound_on:"+(document.getElementById("sound_on")).checked); + + let soundMutedFlag = false; + if ( (document.getElementById("sound_off")).checked ) { + soundMutedFlag = true; + } + initAudio(soundMutedFlag); + + if ( (document.getElementById("multi_balls")).checked ) { + matchOptions |= en.MatchOptions.multiBalls; + } + if ( (document.getElementById("moving_walls")).checked ) { + matchOptions |= en.MatchOptions.movingWalls; + } + + document.getElementById("div_game_options").hidden = true; + + pong = new GameArea(); + gc = new GameComponentsClient(matchOptions, pong.ctx); + initWebSocket(matchOptions); +} + +function matchmaking() +{ + console.log("Searching an opponent..."); + gc.text1.clear(); + gc.text1.pos.assign(c.w/5, c.h_mid); + gc.text1.text = "Searching..."; + gc.text1.update(); +} + +function matchmakingComplete() +{ + console.log("Match Found !"); + gc.text1.clear(); + gc.text1.pos.assign(c.w/8, c.h_mid); + gc.text1.text = "Match Found !"; + gc.text1.update(); +} + +function startGame() { + gc.text1.pos.assign(c.w_mid, c.h_mid+c.h/4); + countdown(c.matchStartDelay/1000, (count: number) => { + gc.text1.clear(); + gc.text1.text = `${count}`; + gc.text1.update(); + }, resumeGame); +} + +function resumeGame() +{ + gc.text1.text = ""; + window.addEventListener('keydown', function (e) { + pong.addKey(e.key); + }); + window.addEventListener('keyup', function (e) { + pong.deleteKey(e.key); + }); + pong.handleInputInterval = window.setInterval(handleInput, c.handleInputIntervalMS); + // pong.handleInputInterval = window.setInterval(sendLoop, c.sendLoopIntervalMS); + pong.gameLoopInterval = window.setInterval(gameLoop, c.gameLoopIntervalMS); + pong.drawLoopInterval = window.setInterval(drawLoop, c.drawLoopIntervalMS); +} + + +export {matchmaking, matchmakingComplete, startGame} diff --git a/srcs/requirements/svelte/api_front/public/game/utils copy.ts b/srcs/requirements/svelte/api_front/public/game/utils copy.ts new file mode 100644 index 00000000..e8f7bca3 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/utils copy.ts @@ -0,0 +1,27 @@ + +import { MovingRectangle } from "./class/Rectangle.js"; + +function random(min: number = 0, max: number = 1) { + return Math.random() * (max - min) + min; +} + +function sleep (ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function clamp(n: number, min: number, max: number) : number +{ + if (n < min) + n = min; + else if (n > max) + n = max; + return (n); +} + +// Typescript hack, unused +function assertMovingRectangle(value: unknown): asserts value is MovingRectangle { + // if (value !== MovingRectangle) throw new Error("Not a MovingRectangle"); + return; +} + +export {random, sleep, clamp, assertMovingRectangle} diff --git a/srcs/requirements/svelte/api_front/public/game/utils.ts b/srcs/requirements/svelte/api_front/public/game/utils.ts new file mode 100644 index 00000000..db971447 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/utils.ts @@ -0,0 +1,18 @@ + +export * from "../shared_js/utils.js" + +function countdown(count: number, callback?: (count: number) => void, endCallback?: () => void) +{ + console.log("countdown ", count); + if (count > 0) { + if (callback) { + callback(count); + } + setTimeout(countdown, 1000, --count, callback, endCallback); + } + else if (endCallback) { + endCallback(); + } +} + +export {countdown} diff --git a/srcs/requirements/svelte/api_front/public/game/wallsMovement.ts b/srcs/requirements/svelte/api_front/public/game/wallsMovement.ts new file mode 100644 index 00000000..dbf3f558 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/wallsMovement.ts @@ -0,0 +1,20 @@ + +import * as c from "./constants.js"; +import { MovingRectangle } from "../shared_js/class/Rectangle.js"; +import { GameComponents } from "./class/GameComponents.js"; + +function wallsMovements(delta: number, gc: GameComponents) +{ + const wallTop = gc.wallTop; + const wallBottom = gc.wallBottom; + if (wallTop.pos.y <= 0 || wallTop.pos.y >= c.movingWallPosMax) { + wallTop.dir.y *= -1; + } + if (wallBottom.pos.y >= c.h-c.wallSize || wallBottom.pos.y <= c.h-c.movingWallPosMax) { + wallBottom.dir.y *= -1; + } + wallTop.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]); + wallBottom.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]); +} + +export {wallsMovements} diff --git a/srcs/requirements/svelte/api_front/public/game/ws.ts b/srcs/requirements/svelte/api_front/public/game/ws.ts new file mode 100644 index 00000000..60f1ab87 --- /dev/null +++ b/srcs/requirements/svelte/api_front/public/game/ws.ts @@ -0,0 +1,182 @@ + +import * as c from "./constants.js" +import { gc, matchOptions } from "./global.js" +import * as ev from "../shared_js/class/Event.js" +import * as en from "../shared_js/enums.js" +import { matchmaking, matchmakingComplete, startGame } from "./pong.js"; +import { RacketClient } from "./class/RectangleClient.js"; +import { repeatInput } from "./handleInput.js"; +import { soundRoblox } from "./audio.js" +import { sleep } from "./utils.js"; +import { Vector, VectorInteger } from "../shared_js/class/Vector.js"; + +class ClientInfo { + id = ""; + side: en.PlayerSide; + racket: RacketClient; + opponent: RacketClient; + opponentNextPos: VectorInteger; +} + +const wsPort = 8042; +const wsUrl = "ws://" + document.location.hostname + ":" + wsPort + "/pong"; +export let socket: WebSocket; /* TODO: A way to still use "const" not "let" ? */ +export const clientInfo = new ClientInfo(); + +export function initWebSocket(options: en.MatchOptions) +{ + socket = new WebSocket(wsUrl, "json"); + socket.addEventListener("open", (event) => { + socket.send(JSON.stringify( new ev.ClientAnnounce(en.ClientRole.player, options, clientInfo.id) )); + }); + // socket.addEventListener("message", logListener); // for testing purpose + socket.addEventListener("message", preMatchListener); +} + +function logListener(this: WebSocket, event: MessageEvent) { + console.log("%i: " + event.data, Date.now()); +} + +function preMatchListener(this: WebSocket, event: MessageEvent) +{ + const data: ev.ServerEvent = JSON.parse(event.data); + switch (data.type) { + case en.EventTypes.assignId: + clientInfo.id = (data).id; + break; + case en.EventTypes.matchmakingInProgress: + matchmaking(); + break; + case en.EventTypes.matchmakingComplete: + clientInfo.side = (data).side; + if (clientInfo.side === en.PlayerSide.left) + { + clientInfo.racket = gc.playerLeft; + clientInfo.opponent = gc.playerRight; + } + else if (clientInfo.side === en.PlayerSide.right) + { + clientInfo.racket = gc.playerRight; + clientInfo.opponent = gc.playerLeft; + } + clientInfo.opponentNextPos = new VectorInteger(clientInfo.opponent.pos.x, clientInfo.opponent.pos.y); + clientInfo.racket.color = "darkgreen"; // for testing purpose + socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientPlayerReady) )); // TODO: set an interval/timeout to resend until matchStart response (in case of network problem) + matchmakingComplete(); + break; + case en.EventTypes.matchStart: + socket.removeEventListener("message", preMatchListener); + socket.addEventListener("message", inGameListener); + startGame(); + break; + } +} + +function inGameListener(event: MessageEvent) +{ + const data: ev.ServerEvent = JSON.parse(event.data); + switch (data.type) { + case en.EventTypes.gameUpdate: + // setTimeout(gameUpdate, 500, data as ev.EventGameUpdate); // artificial latency for testing purpose + gameUpdate(data as ev.EventGameUpdate); + break; + case en.EventTypes.scoreUpdate: + scoreUpdate(data as ev.EventScoreUpdate); + break; + case en.EventTypes.matchEnd: + matchEnd(data as ev.EventMatchEnd); + break; + } +} + +function gameUpdate(data: ev.EventGameUpdate) +{ + console.log("gameUpdate"); + + if (matchOptions & en.MatchOptions.movingWalls) { + gc.wallTop.pos.y = data.wallTop.y; + gc.wallBottom.pos.y = data.wallBottom.y; + } + + data.ballsArr.forEach((ball, i) => { + gc.ballsArr[i].pos.assign(ball.x, ball.y); + gc.ballsArr[i].dir.assign(ball.dirX, ball.dirY); + gc.ballsArr[i].speed = ball.speed; + }); + /* // Equivalent to + gc.ballsArr.forEach((ball, i) => { + ball.pos.assign(data.ballsArr[i].x, data.ballsArr[i].y); + ball.dir.assign(data.ballsArr[i].dirX, data.ballsArr[i].dirY); + ball.speed = data.ballsArr[i].speed; + }); */ + + const predictionPos = new VectorInteger(clientInfo.racket.pos.x, clientInfo.racket.pos.y); // debug + + if (clientInfo.side === en.PlayerSide.left) { + clientInfo.racket.pos.assign(clientInfo.racket.pos.x, data.playerLeft.y); + } + else if (clientInfo.side === en.PlayerSide.right) { + clientInfo.racket.pos.assign(clientInfo.racket.pos.x, data.playerRight.y); + } + + // interpolation + clientInfo.opponent.pos.assign(clientInfo.opponentNextPos.x, clientInfo.opponentNextPos.y); + if (clientInfo.side === en.PlayerSide.left) { + clientInfo.opponentNextPos.assign(clientInfo.opponent.pos.x, data.playerRight.y); + } + else if (clientInfo.side === en.PlayerSide.right) { + clientInfo.opponentNextPos.assign(clientInfo.opponent.pos.x, data.playerLeft.y); + } + + clientInfo.opponent.dir = new Vector( + clientInfo.opponentNextPos.x - clientInfo.opponent.pos.x, + clientInfo.opponentNextPos.y - clientInfo.opponent.pos.y + ); + + if (Math.abs(clientInfo.opponent.dir.x) + Math.abs(clientInfo.opponent.dir.y) !== 0) { + clientInfo.opponent.dir = clientInfo.opponent.dir.normalized(); + } + + // server reconciliation + repeatInput(data.lastInputId); + + // debug + if (clientInfo.racket.pos.y > predictionPos.y + 1 + || clientInfo.racket.pos.y < predictionPos.y - 1) + { + console.log( + `Reconciliation error: + server y: ${data.playerLeft.y} + reconciliation y: ${clientInfo.racket.pos.y} + prediction y: ${predictionPos.y}` + ); + } +} + +function scoreUpdate(data: ev.EventScoreUpdate) +{ + // console.log("scoreUpdate"); + if (clientInfo.side === en.PlayerSide.left && data.scoreRight > gc.scoreRight.value) { + soundRoblox.play(); + } + else if (clientInfo.side === en.PlayerSide.right && data.scoreLeft > gc.scoreLeft.value) { + soundRoblox.play(); + } + gc.scoreLeft.value = data.scoreLeft; + gc.scoreRight.value = data.scoreRight; +} + +function matchEnd(data: ev.EventMatchEnd) +{ + if (data.winner === clientInfo.side) { + gc.text1.pos.assign(c.w*0.415, c.h_mid); + gc.text1.text = "WIN"; + } + else { + gc.text1.pos.assign(c.w*0.383, c.h_mid); + gc.text1.text = "LOSE"; + } + // matchEnded = true; +} + +// export let matchEnded = false; diff --git a/srcs/requirements/svelte/api_front/public/global.css b/srcs/requirements/svelte/api_front/public/global.css index e5845aa1..b6baa24e 100644 --- a/srcs/requirements/svelte/api_front/public/global.css +++ b/srcs/requirements/svelte/api_front/public/global.css @@ -12,6 +12,11 @@ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; /* tmp? */ background: bisque; + + /* overflow-x: hidden; */ + /* This seems to have fixed my pages that are too long */ + /* but now i can't scroll anywhere ... */ + /* overflow-y: hidden; */ } a { diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/0.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/0.ogg new file mode 100644 index 00000000..93d05409 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/0.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/1.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/1.ogg new file mode 100644 index 00000000..3a268b34 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/1.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/10.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/10.ogg new file mode 100644 index 00000000..855ad78b Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/10.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/11.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/11.ogg new file mode 100644 index 00000000..655917b5 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/11.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/12.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/12.ogg new file mode 100644 index 00000000..11336a76 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/12.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/13.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/13.ogg new file mode 100644 index 00000000..71cfead6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/13.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/14.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/14.ogg new file mode 100644 index 00000000..066fff69 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/14.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/15.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/15.ogg new file mode 100644 index 00000000..011f139c Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/15.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/16.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/16.ogg new file mode 100644 index 00000000..7e852275 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/16.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/17.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/17.ogg new file mode 100644 index 00000000..9860139d Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/17.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/18.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/18.ogg new file mode 100644 index 00000000..6ad25391 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/18.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/19.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/19.ogg new file mode 100644 index 00000000..f6fc42d6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/19.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/2.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/2.ogg new file mode 100644 index 00000000..0f09bb30 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/2.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/20.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/20.ogg new file mode 100644 index 00000000..11ac780e Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/20.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/21.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/21.ogg new file mode 100644 index 00000000..7c724dd4 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/21.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/22.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/22.ogg new file mode 100644 index 00000000..b2ca9758 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/22.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/23.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/23.ogg new file mode 100644 index 00000000..f57724b9 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/23.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/24.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/24.ogg new file mode 100644 index 00000000..90093efc Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/24.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/25.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/25.ogg new file mode 100644 index 00000000..27dfe8eb Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/25.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/26.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/26.ogg new file mode 100644 index 00000000..80cb60fa Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/26.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/27.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/27.ogg new file mode 100644 index 00000000..13332de6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/27.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/28.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/28.ogg new file mode 100644 index 00000000..29615795 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/28.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/29.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/29.ogg new file mode 100644 index 00000000..41f95343 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/29.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/3.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/3.ogg new file mode 100644 index 00000000..12448222 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/3.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/30.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/30.ogg new file mode 100644 index 00000000..bd4e4ffd Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/30.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/31.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/31.ogg new file mode 100644 index 00000000..4447b52a Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/31.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/32.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/32.ogg new file mode 100644 index 00000000..a58240a1 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/32.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/4.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/4.ogg new file mode 100644 index 00000000..688b1f81 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/4.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/5.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/5.ogg new file mode 100644 index 00000000..d2163268 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/5.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/6.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/6.ogg new file mode 100644 index 00000000..34bdd117 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/6.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/7.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/7.ogg new file mode 100644 index 00000000..9c9c994f Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/7.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/8.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/8.ogg new file mode 100644 index 00000000..0f9acf99 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/8.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/pong/9.ogg b/srcs/requirements/svelte/api_front/public/sound/pong/9.ogg new file mode 100644 index 00000000..15d82091 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/pong/9.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sound/roblox-oof.ogg b/srcs/requirements/svelte/api_front/public/sound/roblox-oof.ogg new file mode 100644 index 00000000..689946ed Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sound/roblox-oof.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/0.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/0.ogg new file mode 100644 index 00000000..93d05409 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/0.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/1.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/1.ogg new file mode 100644 index 00000000..3a268b34 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/1.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/10.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/10.ogg new file mode 100644 index 00000000..855ad78b Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/10.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/11.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/11.ogg new file mode 100644 index 00000000..655917b5 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/11.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/12.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/12.ogg new file mode 100644 index 00000000..11336a76 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/12.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/13.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/13.ogg new file mode 100644 index 00000000..71cfead6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/13.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/14.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/14.ogg new file mode 100644 index 00000000..066fff69 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/14.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/15.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/15.ogg new file mode 100644 index 00000000..011f139c Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/15.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/16.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/16.ogg new file mode 100644 index 00000000..7e852275 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/16.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/17.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/17.ogg new file mode 100644 index 00000000..9860139d Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/17.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/18.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/18.ogg new file mode 100644 index 00000000..6ad25391 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/18.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/19.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/19.ogg new file mode 100644 index 00000000..f6fc42d6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/19.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/2.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/2.ogg new file mode 100644 index 00000000..0f09bb30 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/2.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/20.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/20.ogg new file mode 100644 index 00000000..11ac780e Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/20.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/21.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/21.ogg new file mode 100644 index 00000000..7c724dd4 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/21.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/22.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/22.ogg new file mode 100644 index 00000000..b2ca9758 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/22.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/23.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/23.ogg new file mode 100644 index 00000000..f57724b9 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/23.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/24.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/24.ogg new file mode 100644 index 00000000..90093efc Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/24.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/25.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/25.ogg new file mode 100644 index 00000000..27dfe8eb Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/25.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/26.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/26.ogg new file mode 100644 index 00000000..80cb60fa Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/26.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/27.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/27.ogg new file mode 100644 index 00000000..13332de6 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/27.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/28.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/28.ogg new file mode 100644 index 00000000..29615795 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/28.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/29.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/29.ogg new file mode 100644 index 00000000..41f95343 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/29.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/3.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/3.ogg new file mode 100644 index 00000000..12448222 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/3.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/30.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/30.ogg new file mode 100644 index 00000000..bd4e4ffd Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/30.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/31.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/31.ogg new file mode 100644 index 00000000..4447b52a Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/31.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/32.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/32.ogg new file mode 100644 index 00000000..a58240a1 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/32.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/4.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/4.ogg new file mode 100644 index 00000000..688b1f81 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/4.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/5.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/5.ogg new file mode 100644 index 00000000..d2163268 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/5.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/6.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/6.ogg new file mode 100644 index 00000000..34bdd117 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/6.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/7.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/7.ogg new file mode 100644 index 00000000..9c9c994f Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/7.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/8.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/8.ogg new file mode 100644 index 00000000..0f9acf99 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/8.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/pong/9.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/9.ogg new file mode 100644 index 00000000..15d82091 Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/pong/9.ogg differ diff --git a/srcs/requirements/svelte/api_front/public/sounds/sound/roblox-oof.ogg b/srcs/requirements/svelte/api_front/public/sounds/sound/roblox-oof.ogg new file mode 100644 index 00000000..689946ed Binary files /dev/null and b/srcs/requirements/svelte/api_front/public/sounds/sound/roblox-oof.ogg differ diff --git a/srcs/requirements/svelte/api_front/src/App.svelte b/srcs/requirements/svelte/api_front/src/App.svelte index b1ef3fe9..7a383eb1 100644 --- a/srcs/requirements/svelte/api_front/src/App.svelte +++ b/srcs/requirements/svelte/api_front/src/App.svelte @@ -1,28 +1,24 @@ - + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/ProfileSettings.svelte b/srcs/requirements/svelte/api_front/src/ProfileSettings.svelte deleted file mode 100644 index ed6086b2..00000000 --- a/srcs/requirements/svelte/api_front/src/ProfileSettings.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -

this is settings

- - - \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/SplashPage.svelte b/srcs/requirements/svelte/api_front/src/SplashPage.svelte deleted file mode 100644 index de2a24fa..00000000 --- a/srcs/requirements/svelte/api_front/src/SplashPage.svelte +++ /dev/null @@ -1,190 +0,0 @@ - - - -
- - -

Potato Pong

- - -

-
Welcome to
-
Potato Pong
-

- - - -
- - - - - - diff --git a/srcs/requirements/svelte/api_front/src/TmpTest.svelte b/srcs/requirements/svelte/api_front/src/TmpTest.svelte deleted file mode 100644 index 419591b3..00000000 --- a/srcs/requirements/svelte/api_front/src/TmpTest.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - - - -

TMP TEST

\ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/main.ts b/srcs/requirements/svelte/api_front/src/main.ts index d6cacbbb..dbcefc37 100644 --- a/srcs/requirements/svelte/api_front/src/main.ts +++ b/srcs/requirements/svelte/api_front/src/main.ts @@ -3,7 +3,7 @@ import App from './App.svelte'; const app = new App({ target: document.body, props: { - name: 'world' + // name: 'world' } }); diff --git a/srcs/requirements/svelte/api_front/src/pages/GamePage.svelte b/srcs/requirements/svelte/api_front/src/pages/GamePage.svelte new file mode 100644 index 00000000..5e08c6f4 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/GamePage.svelte @@ -0,0 +1,106 @@ + + + +
+
+ game options +
+ + +
+
+ + +
+
+ + + + + +
+
+ +
+
+
+ +
+

--- keys ---

+

move up: 'w' or 'up arrow'

+

move down: 's' OR 'down arrow'

+

grid on/off: 'g'

+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/NotFound.svelte b/srcs/requirements/svelte/api_front/src/pages/NotFound.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/NotFound.svelte rename to srcs/requirements/svelte/api_front/src/pages/NotFound.svelte diff --git a/srcs/requirements/svelte/api_front/src/pages/SplashPage.svelte b/srcs/requirements/svelte/api_front/src/pages/SplashPage.svelte new file mode 100644 index 00000000..d803bf9c --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/SplashPage.svelte @@ -0,0 +1,156 @@ + + + +
+

Potato Pong

+ +

+
Welcome to
+
Potato Pong
+

+
+ + + + + + + diff --git a/srcs/requirements/svelte/api_front/src/pages/TmpTestPage.svelte b/srcs/requirements/svelte/api_front/src/pages/TmpTestPage.svelte new file mode 100644 index 00000000..53dccaa7 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/TmpTestPage.svelte @@ -0,0 +1,22 @@ + + +
+

You made it to Test

+ +
{user}
+
+ + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/pages/TwoFactorAuthentication.svelte b/srcs/requirements/svelte/api_front/src/pages/TwoFactorAuthentication.svelte new file mode 100644 index 00000000..c9b88665 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/TwoFactorAuthentication.svelte @@ -0,0 +1,105 @@ + + + +
+

2FA Sign In

+

use google authenticator

+ {#await fetchQrCodeImg} +

Please Wait...

+ {:then data} + + A QRCodeImg you must scan with google authenticator +
+ + +
+ {#if wrongCode} + +
+ {wrongCode} +
+ {/if} + {:catch} +

Unable to get QrCodeImg

+ {/await} +
+ + diff --git a/srcs/requirements/svelte/api_front/src/pages/UnauthorizedAccessPage.svelte b/srcs/requirements/svelte/api_front/src/pages/UnauthorizedAccessPage.svelte new file mode 100644 index 00000000..7b1fca10 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/UnauthorizedAccessPage.svelte @@ -0,0 +1,17 @@ + + +
+

You're not supposed to be here...

+ +
+ + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte b/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte new file mode 100644 index 00000000..4a4741b1 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/game/Game.svelte @@ -0,0 +1,99 @@ + + + + + + + + + +
.
+ +
+
+ game options +
+ + +
+
+ + +
+
+ + + + + +
+
+ +
+
+
+ +
+ +
+ + + + + diff --git a/srcs/requirements/svelte/api_front/src/pages/profile/ProfileDisplay.svelte b/srcs/requirements/svelte/api_front/src/pages/profile/ProfileDisplay.svelte new file mode 100644 index 00000000..46b7c62b --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/profile/ProfileDisplay.svelte @@ -0,0 +1,206 @@ + + + +
+ + {#if user !== undefined} + + {:else} + +

Sorry

+
Failed to load current
+ {/if} +
+ +
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+
testing when there's tons of stuff
+ + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/pages/profile/ProfileFriends.svelte b/srcs/requirements/svelte/api_front/src/pages/profile/ProfileFriends.svelte new file mode 100644 index 00000000..590a37a3 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pages/profile/ProfileFriends.svelte @@ -0,0 +1,293 @@ + + + + +
+ +
+

All Users

+ {#if allUsers === undefined} +
Failed to load all users
+ {:else} + + + + + + {#each allUsers as aUser } + +
viewAUser(aUser)}>{aUser.username}
+ +
{aUser.status}
+
+ {/each} + {/if} + +
+ + +
+ +

Main Display

+ + + + + + {#if userBeingViewed} +
{userBeingViewed.username}
+ + + + + + + {/if} + + + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/srcs/requirements/svelte/api_front/src/ProfilePage.svelte b/srcs/requirements/svelte/api_front/src/pages/profile/ProfilePage.svelte similarity index 50% rename from srcs/requirements/svelte/api_front/src/ProfilePage.svelte rename to srcs/requirements/svelte/api_front/src/pages/profile/ProfilePage.svelte index 76f0cac6..f4e587f3 100644 --- a/srcs/requirements/svelte/api_front/src/ProfilePage.svelte +++ b/srcs/requirements/svelte/api_front/src/pages/profile/ProfilePage.svelte @@ -1,16 +1,15 @@ @@ -20,14 +19,25 @@ - - +
+ +
diff --git a/srcs/requirements/svelte/api_front/src/pieces/Button.svelte b/srcs/requirements/svelte/api_front/src/pieces/Button.svelte new file mode 100644 index 00000000..a7df2e5b --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pieces/Button.svelte @@ -0,0 +1,48 @@ + + + + + + + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/components/Canvas.svelte b/srcs/requirements/svelte/api_front/src/pieces/Canvas.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/components/Canvas.svelte rename to srcs/requirements/svelte/api_front/src/pieces/Canvas.svelte diff --git a/srcs/requirements/svelte/api_front/src/shared/Card.svelte b/srcs/requirements/svelte/api_front/src/pieces/Card.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/shared/Card.svelte rename to srcs/requirements/svelte/api_front/src/pieces/Card.svelte diff --git a/srcs/requirements/svelte/api_front/src/pieces/DisplayAUser.svelte b/srcs/requirements/svelte/api_front/src/pieces/DisplayAUser.svelte new file mode 100644 index 00000000..5cf7d681 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pieces/DisplayAUser.svelte @@ -0,0 +1,59 @@ + + + + +{#if user !== undefined} + + +{:else} +

Sorry

+
Failed to load user {aUsername}
+{/if} + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/components/Footer.svelte b/srcs/requirements/svelte/api_front/src/pieces/Footer.svelte similarity index 100% rename from srcs/requirements/svelte/api_front/src/components/Footer.svelte rename to srcs/requirements/svelte/api_front/src/pieces/Footer.svelte diff --git a/srcs/requirements/svelte/api_front/src/pieces/GenerateUserDisplay.svelte b/srcs/requirements/svelte/api_front/src/pieces/GenerateUserDisplay.svelte new file mode 100644 index 00000000..7969c6f7 --- /dev/null +++ b/srcs/requirements/svelte/api_front/src/pieces/GenerateUserDisplay.svelte @@ -0,0 +1,256 @@ + + + +
+ {#if user !== undefined} +
+ + + default user icon +
{user.username}
+
Rank: + + + + + + + + + + + + + + + + + {rank} + +
+
+

Match Statistics

+

Total: {user.stats.totalGame}

+

Victories: {user.stats.winGame}

+

Losses: {user.stats.loseGame}

+

Draws: {user.stats.drawGame}

+
+
+ {/if} +
+ + + + \ No newline at end of file diff --git a/srcs/requirements/svelte/api_front/src/components/Header.svelte b/srcs/requirements/svelte/api_front/src/pieces/Header.svelte similarity index 58% rename from srcs/requirements/svelte/api_front/src/components/Header.svelte rename to srcs/requirements/svelte/api_front/src/pieces/Header.svelte index 452a81ff..dee06c62 100644 --- a/srcs/requirements/svelte/api_front/src/components/Header.svelte +++ b/srcs/requirements/svelte/api_front/src/pieces/Header.svelte @@ -1,56 +1,50 @@ - +
- - Potato Pong Logo - -

Potato Pong

- + Potato Pong Logo (push('/'))}> +

Potato Pong

+ + + + +