From ba619c19757691e9650fe2fc9fd336444f6683cd Mon Sep 17 00:00:00 2001 From: Damon Murdoch Date: Wed, 20 Jul 2022 17:29:28 +1000 Subject: [PATCH] Committing changes pre-merge --- prisma/schema.prisma | 269 ++++++++++++++++++++++------------------ src/modules/game.ts | 287 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 424 insertions(+), 132 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 06d42a9..2cc9abd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -2,158 +2,185 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" } datasource db { - provider = "postgresql" - url = env("POSTGRES_URL") + provider = "postgresql" + url = env("POSTGRES_URL") } model User { - id Int @id @default(autoincrement()) - chipId String @unique - accessCode String - cars Car[] - unusedTickets UserItem[] - tutorials Boolean[] - userBanned Boolean @default(false) + id Int @id @default(autoincrement()) + chipId String @unique + accessCode String + cars Car[] + unusedTickets UserItem[] + tutorials Boolean[] + userBanned Boolean @default(false) + Bookmarks Bookmarks[] + ScratchSheet ScratchSheet[] + currentSheet Int @default(0) + lastSheet Int @default(0) +} + +model ScratchSheet { + id Int @id @default(autoincrement()) + User User @relation(fields: [userId], references: [id]) + userId Int @unique + squares ScratchSquare[] +} + +model ScratchSquare { + id Int @id @default(autoincrement()) + Sheet ScratchSheet @relation(fields: [sheetId], references: [id]) + sheetId Int + category Int + itemId Int + earned Boolean +} + +model Bookmarks { + id Int @id @default(autoincrement()) + User User @relation(fields: [userId], references: [id]) + userId Int @unique + carId Int[] } model UserItem { - dbId Int @id @default(autoincrement()) - category Int - itemId Int - User User @relation(fields: [userId], references: [id]) - userId Int + dbId Int @id @default(autoincrement()) + category Int + itemId Int + User User @relation(fields: [userId], references: [id]) + userId Int } model Car { - user User @relation(fields: [userId], references: [id]) - userId Int + user User @relation(fields: [userId], references: [id]) + userId Int - // This is the Car object itself - carId Int @id @default(autoincrement()) - name String - manufacturer Int - regionId Int @default(0) - model Int - visualModel Int - customColor Int @default(0) - defaultColor Int - wheel Int @default(0) - wheelColor Int @default(0) - aero Int @default(0) - bonnet Int @default(0) - wing Int @default(0) - mirror Int @default(0) - neon Int @default(0) - trunk Int @default(0) - plate Int @default(0) - plateColor Int @default(0) - plateNumber Int @default(0) - tunePower Int @default(0) - tuneHandling Int @default(0) - title String @default("New Car") - level Int @default(0) - windowSticker Boolean @default(false) - windowStickerString String @default("WANGAN") - windowStickerFont Int @default(0) - rivalMarker Int @default(0) - aura Int @default(0) - auraMotif Int @default(0) - ghostLevel Int @default(1) + // This is the Car object itself + carId Int @id @default(autoincrement()) + name String + manufacturer Int + regionId Int @default(0) + model Int + visualModel Int + customColor Int @default(0) + defaultColor Int + wheel Int @default(0) + wheelColor Int @default(0) + aero Int @default(0) + bonnet Int @default(0) + wing Int @default(0) + mirror Int @default(0) + neon Int @default(0) + trunk Int @default(0) + plate Int @default(0) + plateColor Int @default(0) + plateNumber Int @default(0) + tunePower Int @default(0) + tuneHandling Int @default(0) + title String @default("New Car") + level Int @default(0) + windowSticker Boolean @default(false) + windowStickerString String @default("WANGAN") + windowStickerFont Int @default(0) + rivalMarker Int @default(0) + aura Int @default(0) + auraMotif Int @default(0) + ghostLevel Int @default(1) - // This is more data about the car - tuningPoints Int @default(0) - odometer Int @default(0) - playCount Int @default(0) - earnedCustomColor Boolean @default(false) - carSettingsDbId Int @unique - settings CarSettings @relation(fields: [carSettingsDbId], references: [dbId]) - vsPlayCount Int @default(0) - vsBurstCount Int @default(0) - vsStarCount Int @default(0) - vsCoolOrWild Int @default(0) - vsSmoothOrRough Int @default(0) - vsTripleStarMedals Int @default(0) - vsDoubleStarMedals Int @default(0) - vsSingleStarMedals Int @default(0) - vsPlainMedals Int @default(0) - rgPlayCount Int @default(0) - rgWinCount Int @default(0) - rgTrophy Int @default(0) - rgScore Int @default(0) - rgStamp Int @default(0) - rgAcquireAllCrowns Boolean @default(false) - dressupLevel Int @default(0) - dressupPoint Int @default(0) - stPlayCount Int @default(0) - stClearBits Int @default(0) - stClearDivCount Int @default(0) - stClearCount Int @default(0) - stLoseBits BigInt @default(0) - stConsecutiveWins Int @default(0) - stConsecutiveWinsMax Int @default(0) - stCompleted100Episodes Boolean @default(false) + // This is more data about the car + tuningPoints Int @default(0) + odometer Int @default(0) + playCount Int @default(0) + earnedCustomColor Boolean @default(false) + carSettingsDbId Int @unique + settings CarSettings @relation(fields: [carSettingsDbId], references: [dbId]) + vsPlayCount Int @default(0) + vsBurstCount Int @default(0) + vsStarCount Int @default(0) + vsCoolOrWild Int @default(0) + vsSmoothOrRough Int @default(0) + vsTripleStarMedals Int @default(0) + vsDoubleStarMedals Int @default(0) + vsSingleStarMedals Int @default(0) + vsPlainMedals Int @default(0) + rgPlayCount Int @default(0) + rgWinCount Int @default(0) + rgTrophy Int @default(0) + rgScore Int @default(0) + rgStamp Int @default(0) + rgAcquireAllCrowns Boolean @default(false) + dressupLevel Int @default(0) + dressupPoint Int @default(0) + stPlayCount Int @default(0) + stClearBits Int @default(0) + stClearDivCount Int @default(0) + stClearCount Int @default(0) + stLoseBits BigInt @default(0) + stConsecutiveWins Int @default(0) + stConsecutiveWinsMax Int @default(0) + stCompleted100Episodes Boolean @default(false) - items CarItem[] + items CarItem[] - carStateDbId Int @unique - state CarState @relation(fields: [carStateDbId], references: [dbId]) - TimeAttackRecord TimeAttackRecord[] + carStateDbId Int @unique + state CarState @relation(fields: [carStateDbId], references: [dbId]) + TimeAttackRecord TimeAttackRecord[] } model CarItem { - Car Car? @relation(fields: [carId], references: [carId]) - carId Int @unique + Car Car? @relation(fields: [carId], references: [carId]) + carId Int @unique - category Int - itemId Int - amount Int + category Int + itemId Int + amount Int } model CarSettings { - dbId Int @id @default(autoincrement()) - car Car? + dbId Int @id @default(autoincrement()) + car Car? - view Boolean @default(true) - transmission Boolean @default(false) - retire Boolean @default(false) - meter Int @default(0) - navigationMap Boolean @default(true) - volume Int @default(1) - bgm Int @default(0) - nameplate Int @default(0) - nameplateColor Int @default(0) - terminalBackground Int @default(0) + view Boolean @default(true) + transmission Boolean @default(false) + retire Boolean @default(false) + meter Int @default(0) + navigationMap Boolean @default(true) + volume Int @default(1) + bgm Int @default(0) + nameplate Int @default(0) + nameplateColor Int @default(0) + terminalBackground Int @default(0) } model CarState { - dbId Int @id @default(autoincrement()) - car Car? + dbId Int @id @default(autoincrement()) + car Car? - hasOpponentGhost Boolean @default(false) - eventJoined Boolean @default(false) - transferred Boolean @default(false) - toBeDeleted Boolean @default(false) + hasOpponentGhost Boolean @default(false) + eventJoined Boolean @default(false) + transferred Boolean @default(false) + toBeDeleted Boolean @default(false) } model TimeAttackRecord { - dbId Int @id @default(autoincrement()) + dbId Int @id @default(autoincrement()) - car Car @relation(fields: [carId], references: [carId]) - carId Int + car Car @relation(fields: [carId], references: [carId]) + carId Int - model Int // Car model, literally just the `model` field from Car - time Int - course Int - isMorning Boolean - section1Time Int @map("section1Time") - section2Time Int @map("section2Time") - section3Time Int @map("section3Time") - section4Time Int @map("section4Time") - section5Time Int? @map("section5Time") - section6Time Int? @map("section6Time") - section7Time Int? @map("section7Time") + model Int // Car model, literally just the `model` field from Car + time Int + course Int + isMorning Boolean + section1Time Int @map("section1Time") + section2Time Int @map("section2Time") + section3Time Int @map("section3Time") + section4Time Int @map("section4Time") + section5Time Int? @map("section5Time") + section6Time Int? @map("section6Time") + section7Time Int? @map("section7Time") } diff --git a/src/modules/game.ts b/src/modules/game.ts index 428d827..a378c6e 100644 --- a/src/modules/game.ts +++ b/src/modules/game.ts @@ -3,7 +3,7 @@ import { Module } from "../module"; import * as wm from "../wmmt/wm.proto"; import * as svc from "../wmmt/service.proto"; import { prisma } from ".."; -import { User } from "@prisma/client"; +import { Car, ScratchSheet, ScratchSquare, User } from "@prisma/client"; import { Config } from "../config"; import Long from "long"; @@ -523,16 +523,46 @@ export default class GameModule extends Module { }) // Load user bookmarks - app.post('/method/load_bookmarks', (req, res) => { + app.post('/method/load_bookmarks', async (req, res) => { - // In future, check db for player bookmarks - console.log('todo: player bookmarks') + // Get the save bookmark request + let body = wm.wm.protobuf.LoadBookmarksRequest.decode(req.body); + + // Check if the user has any existing bookmarks + let bookmarks = await prisma.bookmarks.findFirst({ + where: { + userId: Number(body.userId) + } + }); + + // Car bookmarks placeholder + let cars : Car[] = []; + + // Bookmarks have been created + if (bookmarks) + { + // Loop over the bookmarked cars + for (let carId of bookmarks.carId) + { + // Get the car with the bookmarked car id + let car = await prisma.car.findFirst({ + where: { + carId: carId + } + }); + + // If the car is not null + if (car) + { + // Add the car to the cars list + cars.push(car); + } + } + } let msg = { error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS, - cars: [ - // No bookmarks - ] + cars: cars } let resp = wm.wm.protobuf.LoadBookmarksResponse.encode(msg); @@ -545,6 +575,57 @@ export default class GameModule extends Module { r.send(Buffer.from(end)); }) + // Save user bookmarks + app.post('/method/save_bookmarks', async (req, res) => { + + // Get the save bookmark request + let body = wm.wm.protobuf.SaveBookmarksRequest.decode(req.body); + + // Check if the user has any existing bookmarks + let bookmarks = await prisma.bookmarks.findFirst({ + where: { + userId: Number(body.userId) + } + }); + + // Bookmarks already exist + if (bookmarks) + { + // Update existing bookmarks + await prisma.bookmarks.update({ + where: { + userId: body.userId + }, + data: { + carId: body.cars + } + }) + } + else // Bookmarks not set + { + // Create new bookmark + await prisma.bookmarks.create({ + data: { + userId: body.userId, + carId: body.cars, + } + }) + } + + // Generate the response to the terminal (success messsage) + let resp = wm.wm.protobuf.LoadBookmarksResponse.encode({ + error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS + }); + + let end = resp.finish(); + let r = res + .header('Server', 'v388 wangan') + .header('Content-Type', 'application/x-protobuf; revision=8053') + .header('Content-Length', end.length.toString()) + .status(200); + r.send(Buffer.from(end)); + }) + // Car Summary Request (for bookmarks) app.get('/resource/car_summary', async (req, res) => { @@ -625,15 +706,104 @@ export default class GameModule extends Module { }) // Terminal scratch (VERY WIP) - app.post('/method/load_scratch_information', (req, res) => { + app.post('/method/load_scratch_information', async (req, res) => { + + // Get the information from the request + let body = wm.wm.protobuf.LoadScratchInformationRequest.decode(req.body); + + // Get the user's current scratch sheet + let user = await prisma.user.findFirst({ + where: { + userId: body.userId + } + }); + + // Get all of the scratch sheets for the user + let scratchSheets = await prisma.scratchSheet.findMany({ + where: { + userId: body.userId + }, + include: { + squares: true + } + }); + + // No scratch sheets for user + if (scratchSheets.length < user.currentSheet) + { + // Create a new scratch sheet for the user + let sheet = await prisma.scratchSheet.create({ + data: { + userId: body.userId + } + }) + + // Populate each square (with FT ticket for now) + for (let i=0; i<50; i++) { + await prisma.scratchSquare.create({ + data: { + sheetId: sheet.id, + category: wm.wm.protobuf.ItemCategory.CAT_CAR_TICKET_FREE, + itemId: 5, + earned: false + } + }); + } + + // In future, I will very the way this is populated based on settings + // i.e. totally random items, items based upon real arcade, etc. + + // Get the data for the newly created sheet + let newSheet = await prisma.scratchSheet.findFirst({ + where: { + userId: body.userId + }, + include: { + squares: true + } + }); + + // Sheet is created successfully + if (newSheet) + { + // Update the scratch sheet list + scratchSheets = [newSheet]; + } + } + + // Generate the scratch sheet proto + let scratch_sheets : wm.wm.protobuf.ScratchSheet[] = []; + + // Loop over all of the protos + for(let sheet of scratchSheets) + { + // Get all of the scratch squares + let scratch_squares : wm.wm.protobuf.ScratchSheet.ScratchSquare[] = []; + + // Loop over all of the squares + for (let square of sheet.squares) + { + // Add the current square to the protobuf array + scratch_squares.push(wm.wm.protobuf.ScratchSheet.ScratchSquare.create({ + category: square.category, + itemId: square.itemId, + earned: square.earned + })); + } + + // Add the scratch sheet to the sheets list + scratch_sheets.push( + wm.wm.protobuf.ScratchSheet.create({ + squares: scratch_squares + }) + ); + } let msg = { error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS, currentSheet: 0, numOfScratched: 0, - scratch_sheets: [ - - ], + scratch_sheets: scratch_sheets, owned_user_items: [ ] @@ -649,6 +819,101 @@ export default class GameModule extends Module { r.send(Buffer.from(end)); }); + app.post('/method/save_scratch_sheet', async (req, res) => { + + // Get the information from the request + let body = wm.wm.protobuf.SaveScratchSheetRequest.decode(req.body); + + // Get all of the scratch sheets for the user + let scratchSheets = await prisma.scratchSheet.findMany({ + where: { + userId: body.userId + }, + include: { + squares: true + } + }) + + // Get the target scratch sheet + let scratchSheet = scratchSheets[Number(body.targetSheet)]; + + // Get all of the squares for the scratch sheet + let scratchSquares = await prisma.scratchSquare.findMany({ + where: { + sheetId: scratchSheet.id + } + }); + + // Get the target scratch square + let scratchSquare = scratchSquares[Number(body.targetSquare)]; + + // Update the revealed scratch square + await prisma.scratchSquare.update({ + where: { + id: scratchSquare.id + }, + data: { + earned: true + } + }); + + // Get the number of scratched squares on the page + let numOfScratched = await prisma.scratchSquare.count({ + where: { + sheetId: scratchSheet.id, + earned: true + } + }) + + // Generate the scratch sheet proto + let scratch_sheets : wm.wm.protobuf.ScratchSheet[] = []; + + // Loop over all of the protos + for(let sheet of scratchSheets) + { + // Get all of the scratch squares + let scratch_squares : wm.wm.protobuf.ScratchSheet.ScratchSquare[] = []; + + // Loop over all of the squares + for (let square of sheet.squares) + { + // Add the current square to the protobuf array + scratch_squares.push(wm.wm.protobuf.ScratchSheet.ScratchSquare.create({ + category: square.category, + itemId: square.itemId, + earned: square.earned + })); + } + + // Add the scratch sheet to the sheets list + scratch_sheets.push( + wm.wm.protobuf.ScratchSheet.create({ + squares: scratch_squares + }) + ); + } + + let msg = { + error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS, + scratch_sheets : scratch_sheets, + currentSheet: body.targetSheet, + numOfScratched: numOfScratched, + earnedItem: wm.wm.protobuf.UserItem.create({ + category: scratchSquare.category, + itemId: scratchSquare.itemId, + }) + } + + let resp = wm.wm.protobuf.SaveScratchSheetResponse.encode(msg); + let end = resp.finish(); + let r = res + .header('Server', 'v388 wangan') + .header('Content-Type', 'application/x-protobuf; revision=8053') + .header('Content-Length', end.length.toString()) + .status(200); + r.send(Buffer.from(end)); + }) + app.post('/method/update_car', async (req, res) => { let body = wm.wm.protobuf.UpdateCarRequest.decode(req.body); let car = await prisma.car.findFirst({