From a12b82f4708d6325bb5d3d06732b233116db3a85 Mon Sep 17 00:00:00 2001 From: Aelita4 Date: Fri, 1 Nov 2024 18:35:44 +0100 Subject: [PATCH] Implement fleet manager and logic --- src/components/ResourceBar.astro | 2 +- src/lib/classes/User.ts | 3 - src/lib/classes/managers/FleetManager.ts | 100 +++++- src/lib/classes/managers/LocationManager.ts | 46 +++ src/lib/classes/managers/ResourceManager.ts | 36 ++- src/lib/db/fleet.ts | 18 +- src/lib/utils/parseParams.ts | 14 + src/lib/utils/validateAccessToken.ts | 9 +- src/pages/api/fleet/send.ts | 268 ++++++++++++++++ src/pages/api/fleet/status.ts | 36 +++ src/pages/game/fleet.astro | 325 +++++++++++++++++++- src/pages/game/profile.astro | 2 +- src/types/MissionType.ts | 3 + src/types/db/DBFleet.ts | 7 +- 14 files changed, 825 insertions(+), 44 deletions(-) create mode 100644 src/lib/utils/parseParams.ts create mode 100644 src/pages/api/fleet/send.ts create mode 100644 src/pages/api/fleet/status.ts create mode 100644 src/types/MissionType.ts diff --git a/src/components/ResourceBar.astro b/src/components/ResourceBar.astro index d5cf005..2836ae5 100644 --- a/src/components/ResourceBar.astro +++ b/src/components/ResourceBar.astro @@ -15,7 +15,7 @@ const planet = locationManager.getPlanet(planetId); if(!planet) return; -planet.resources.calculateCurrentAvailableResources(); +await planet.resources.calculateCurrentAvailableResources(); const resourceArray: Resource[] = []; for(const key of planet.resources.resources) { diff --git a/src/lib/classes/User.ts b/src/lib/classes/User.ts index 2cebc7e..1b58122 100644 --- a/src/lib/classes/User.ts +++ b/src/lib/classes/User.ts @@ -1,7 +1,6 @@ import { ObjectId } from "mongodb"; import ResearchManager from "./managers/ResearchManager"; import { Planet } from "./managers/PlanetManager"; -import FleetManager from "./managers/FleetManager"; export default class User { id: ObjectId; @@ -11,7 +10,6 @@ export default class User { updatedAt: Date; lastLogin: Date; research: ResearchManager; - fleet: FleetManager; mainPlanet!: Planet; constructor(id: ObjectId, username: string, email: string, createdAt: Date, updatedAt: Date, lastLogin: Date) { @@ -22,7 +20,6 @@ export default class User { this.updatedAt = updatedAt; this.lastLogin = lastLogin; this.research = new ResearchManager(this); - this.fleet = new FleetManager(this); } async init() { diff --git a/src/lib/classes/managers/FleetManager.ts b/src/lib/classes/managers/FleetManager.ts index 72707fb..4084e25 100644 --- a/src/lib/classes/managers/FleetManager.ts +++ b/src/lib/classes/managers/FleetManager.ts @@ -1,13 +1,99 @@ -import FleetShip from "../FleetShip"; -import User from "../User"; +import { ObjectId } from "mongodb"; +import MissionType from "../../../types/MissionType"; +import DBFleet from "../../../types/db/DBFleet"; +import { updateFleet } from "../../db/fleet"; +import { Planet } from "./PlanetManager"; + +export type Fleet = { + id: ObjectId, + source: Planet, + destination: Planet, + departureTime: Date, + arrivalTime: Date, + returning: boolean, + mission: MissionType, + ships: Array<{ id: string, amount: number }>, + cargo: Array<{ id: string, amount: number }> +} export default class FleetManager { - user: User; - fleet: Array = []; + data: Fleet; - constructor(user: User) { - this.user = user; + constructor(id: ObjectId, source: Planet, destination: Planet, departureTime: Date, arrivalTime: Date, returning: boolean, mission: MissionType, ships: Array<{ id: string, amount: number }>, cargo: Array<{ id: string, amount: number }>) { + this.data = { + id, + source, + destination, + departureTime, + arrivalTime, + returning, + mission, + ships, + cargo + } } - + async checkStatus(): Promise<{ finished: boolean, fleet: Fleet }> { + if(this.data.arrivalTime.getTime() < Date.now()) { + const finished = await this.finish(); + return { finished, fleet: this.data }; + } + + return { finished: false, fleet: this.data }; + } + + async finish() { + if(this.data.returning) { + for(const ship of this.data.ships) { + this.data.source.ships.addShips(ship.id, ship.amount); + } + await this.data.source.resources.updateAmount(this.data.cargo); + await this.data.source.ships.sync(); + await this.data.source.resources.sync(); + return true; + } else { + switch(this.data.mission) { + case 'ATTACK': + return false; + case 'TRANSPORT': + await this.data.destination.resources.updateAmount(this.data.cargo); + await this.data.destination.resources.sync(); + this.data.cargo = []; + await this.initiateReturn(); + return false; + case 'TRANSFER': + await this.data.destination.resources.updateAmount(this.data.cargo); + await this.data.destination.resources.sync(); + this.data.cargo = []; + for(const ship of this.data.ships) { + this.data.destination.ships.addShips(ship.id, ship.amount); + } + await this.data.destination.ships.sync(); + return true; + } + } + } + + async initiateReturn() { + this.data.returning = true; + this.data.departureTime = new Date(); + this.data.arrivalTime = new Date(this.data.departureTime.getTime() + 1000 * 30); + await this.sync(); + } + + async sync() { + const data: DBFleet = { + _id: this.data.id, + source: this.data.source._id, + destination: this.data.destination._id, + departureTime: this.data.departureTime, + arrivalTime: this.data.arrivalTime, + returning: this.data.returning, + mission: this.data.mission, + ships: this.data.ships, + cargo: this.data.cargo + } + + await updateFleet(data); + } } \ No newline at end of file diff --git a/src/lib/classes/managers/LocationManager.ts b/src/lib/classes/managers/LocationManager.ts index edc5f55..f3eac7c 100644 --- a/src/lib/classes/managers/LocationManager.ts +++ b/src/lib/classes/managers/LocationManager.ts @@ -6,6 +6,8 @@ import { getSystemById } from "../../db/systems"; import { getAllUsers } from "../../db/users"; import User from "../User"; import StructureManager from "./StructureManager"; +import FleetManager from "./FleetManager"; +import { getAllFleet } from "../../db/fleet"; export type Galaxy = { _id: ObjectId, @@ -48,10 +50,14 @@ class LocationManager { galaxies: Galaxy[] = []; users: User[] = []; + fleet: FleetManager[] = []; async init() { + const currentTime = new Date(); + this.galaxies = []; this.users = []; + this.fleet = []; const users = await getAllUsers(); users.forEach(async user => { @@ -125,6 +131,28 @@ class LocationManager { user.mainPlanet = mainPlanet; }; + const fleets = await getAllFleet(); + for(const fleet of fleets) { + if(fleet.arrivalTime > currentTime) { + const source = this.getPlanet(fleet.source); + const destination = this.getPlanet(fleet.destination); + + if(source && destination) this.fleet.push(new FleetManager( + fleet._id, + source, + destination, + fleet.departureTime, + fleet.arrivalTime, + fleet.returning, + fleet.mission, + fleet.ships, + fleet.cargo + )); + } + } + + console.log(`Loaded ${this.fleet.length} active fleet from database`); + return this; } @@ -182,6 +210,24 @@ class LocationManager { getUser(_id: ObjectId) { return this.users.find(user => user.id.equals(_id)); } + + async updateFleet() { + for(const fleet of this.fleet) { + const { finished } = await fleet.checkStatus(); + if(finished) { + this.fleet = this.fleet.filter(f => !f.data.id.equals(fleet.data.id)); + } + } + } + + async getAllFleetByUserId(userId: string) { + await this.updateFleet(); + return userId === '' ? [] : this.fleet.filter(fleet => fleet.data.source.manager.owner.id.equals(userId) || fleet.data.destination.manager.owner.id.equals(userId)); + } + + addFleet(fleet: FleetManager) { + this.fleet.push(fleet); + } } const locationManager = LocationManager.getInstance(); diff --git a/src/lib/classes/managers/ResourceManager.ts b/src/lib/classes/managers/ResourceManager.ts index 476b832..715cd29 100644 --- a/src/lib/classes/managers/ResourceManager.ts +++ b/src/lib/classes/managers/ResourceManager.ts @@ -13,6 +13,7 @@ export type Resource = { export default class ResourceManager { resources: Array = []; + resourcesDB: DBResource[] = []; planet: Planet; constructor(planet: Planet) { @@ -22,6 +23,8 @@ export default class ResourceManager { async init(resourceData: { id: string, amount: number, lastUpdated: Date, perHourMiningRate: number }[]) { const resources = await getAllResources(); + this.resourcesDB = resources; + if(resourceData.length === 0) { resourceData = [ { @@ -109,8 +112,7 @@ export default class ResourceManager { res.amount += amountToAdd; res.lastUpdated = new Date(); }); - - + await updatePlanetResources(this.planet._id, this.resources); return this.resources; @@ -135,8 +137,34 @@ export default class ResourceManager { return difference; } - update(resources: Resource[]) { - this.resources = resources; + add(resources: Resource[]) { + for(const res of resources) { + const resource = this.resources.find(r => r.id === res.id); + if(resource) resource.amount += res.amount; + else this.resources.push(res); + } + } + + async updateAmount(resources: { id: string, amount: number }[]) { + await this.calculateCurrentAvailableResources(); + for(const res of resources) { + const resource = this.resources.find(r => r.id === res.id); + if(resource) resource.amount += res.amount; + } + } + + setAmount(resources: { id: string, amount: number }[]) { + for(const res of resources) { + const resource = this.resources.find(r => r.id === res.id); + if(resource) resource.amount = res.amount; + else this.resources.push({ + id: res.id, + amount: res.amount, + lastUpdated: new Date(), + perHourMiningRate: 0, + data: this.resourcesDB.find(r => r.id === res.id) + }); + } } async sync() { diff --git a/src/lib/db/fleet.ts b/src/lib/db/fleet.ts index b7979e0..a671cb1 100644 --- a/src/lib/db/fleet.ts +++ b/src/lib/db/fleet.ts @@ -1,6 +1,5 @@ import { ObjectId } from 'mongodb'; import DBFleet from '../../types/db/DBFleet'; -import { Planet } from '../classes/managers/PlanetManager'; import { Fleet, Planets } from '../db/mongodb'; export const getAllFleet = async () => { @@ -26,15 +25,10 @@ export const getAllFleetByUser = async (userId: ObjectId) => { return Array.from(fleets.values()); } -export const createFleet = async (source: Planet, destination: Planet, mission: string, ships: Array<{ id: string, amount: number }>) => { - const fleet = { - source: source._id, - destination: destination._id, - finished: false, - returning: false, - mission, - ships - } - - await (await Fleet()).insertOne(fleet); +export const createFleet = async (fleet: DBFleet) => { + return await (await Fleet()).insertOne(fleet); +} + +export const updateFleet = async (fleet: DBFleet) => { + return await (await Fleet()).updateOne({ _id: fleet._id }, { $set: fleet }, { upsert: true }); } \ No newline at end of file diff --git a/src/lib/utils/parseParams.ts b/src/lib/utils/parseParams.ts new file mode 100644 index 0000000..c0f3acd --- /dev/null +++ b/src/lib/utils/parseParams.ts @@ -0,0 +1,14 @@ +export default function parseParams(url: string) { + const rawParams = url.split("?")[1]?.split("&"); + if(typeof rawParams === "undefined") return []; + const params: { [key: string]: any } = {}; + for(const rawParam of rawParams) { + const k = rawParam.split("=")[0]; + const v = rawParam.split("=")[1]; + if(v === "true" || v === "false") params[k] = v === "true"; + else if(!Number.isNaN(Number(v))) params[k] = Number(v); + else params[k] = v; + } + + return params; +} \ No newline at end of file diff --git a/src/lib/utils/validateAccessToken.ts b/src/lib/utils/validateAccessToken.ts index cd0ec71..c8ac760 100644 --- a/src/lib/utils/validateAccessToken.ts +++ b/src/lib/utils/validateAccessToken.ts @@ -5,12 +5,9 @@ import { getUserById } from "../db/users"; import locationManager from "../classes/managers/LocationManager"; export default async function validateAccessToken(request: Request): Promise { - let accessToken = request.url.split("?")[1]?.split("&").filter((x) => x.split("=")[0] === "token")[0].split("=")[1]; - - if(accessToken === undefined) { - const authorization = request.headers.get("Authorization"); - if(authorization !== null && authorization.startsWith("Bearer ")) accessToken = authorization.split(" ")[1]; - } + let accessToken; + const authorization = request.headers.get("Authorization"); + if(authorization !== null && authorization.startsWith("Bearer ")) accessToken = authorization.split(" ")[1]; const cookies = request.headers.get("Cookie")?.split(";").map((x) => x.trim().split("=")) ?? []; diff --git a/src/pages/api/fleet/send.ts b/src/pages/api/fleet/send.ts new file mode 100644 index 0000000..9aad45f --- /dev/null +++ b/src/pages/api/fleet/send.ts @@ -0,0 +1,268 @@ +import { APIRoute } from "astro"; +import validateAccessToken from "../../../lib/utils/validateAccessToken"; +import { getUserByAccessToken } from "../../../lib/db/users"; +import { ObjectId } from "mongodb"; +import locationManager from "../../../lib/classes/managers/LocationManager"; +import { getAllShips } from "../../../lib/db/ships"; +import DBShip from "../../../types/db/DBShip"; +import { Planet } from "../../../lib/classes/managers/PlanetManager"; +import MissionType from "../../../types/MissionType"; +import { getAllResources } from "../../../lib/db/resources"; +import FleetManager from "../../../lib/classes/managers/FleetManager"; + +export const POST: APIRoute = async({ request }) => { + const response = await validateAccessToken(request); + if(response instanceof Response) return response; + + const userDB = await getUserByAccessToken(response); + if(userDB === null) { + return new Response( + JSON.stringify({ + code: 401, + message: "Unauthorized" + }), { status: 401 } + ) + } + + const user = locationManager.getUser(userDB._id); + if(!user) { + return new Response( + JSON.stringify({ + code: 401, + message: "Unauthorized" + }), { status: 401 } + ) + } + + let body: { source: string, destination: string, ships: Array<{ id: string, amount: number }>, cargo: Array<{ id: string, amount: number }>, mission: MissionType }; + try { + body = await request.json() + } catch(e) { + return new Response( + JSON.stringify({ + code: 400, + message: "Bad Request", + error: "Invalid JSON body" + }), { status: 400 } + ) + } + + const checkSource = checkPlanetId(body.source, 'source'); + if(typeof checkSource.error !== "undefined") return new Response(JSON.stringify(checkSource), { status: checkSource.code }); + + const checkDestination = checkPlanetId(body.destination, 'destination'); + if(typeof checkDestination.error !== "undefined") return new Response(JSON.stringify(checkDestination), { status: checkDestination.code }); + + const source = checkSource.planet; + const destination = checkDestination.planet; + + const shipsDB = await getAllShips(); + + const checkShipsBody = checkShips(body.ships, shipsDB, source); + if(typeof checkShipsBody.error !== "undefined") return new Response(JSON.stringify(checkShipsBody), { status: checkShipsBody.code }); + + const resourcesDB = await getAllResources(); + await source.resources.calculateCurrentAvailableResources(); + + const checkCargoBody = checkCargo(body.cargo, body.ships, source, body.mission); + if(typeof checkCargoBody.error !== "undefined") return new Response(JSON.stringify(checkCargoBody), { status: checkCargoBody.code }); + + const fleetManager = new FleetManager( + new ObjectId(), + source, + destination, + new Date(), + new Date(Date.now() + 1000 * 30), //TODO: calculate time based on distance + false, + body.mission, + body.ships, + body.cargo + ); + + const resourceDiff = await source.resources.getDifference(body.cargo.map(c => ({ id: c.id, amount: c.amount }))); + + for(const res of resourceDiff) { + if(res.amount < 0) { + return new Response( + JSON.stringify({ + code: 400, + message: "Bad Request", + error: "Not enough resource with ID '" + res.id + "' on source planet" + }), { status: 400 } + ) + } + } + + source.resources.setAmount(resourceDiff); + await source.resources.sync(); + + for(const ship of body.ships) { + source.ships.removeShips(ship.id, ship.amount); + } + await source.ships.sync(); + await fleetManager.sync(); + + locationManager.addFleet(fleetManager); + + return new Response( + JSON.stringify({ + code: 200, + message: "OK" + }), { status: 200 } + ) +} + +function checkPlanetId(id: string, type: string) { + if(typeof ObjectId === "undefined") return { + code: 400, + message: "Bad Request", + error: `Missing '${type}' in body` + } + + let idToCheck; + try { + idToCheck = new ObjectId(id); + } catch(e) { + return { + code: 400, + message: "Bad Request", + error: `Invalid ID in '${type}'` + } + } + + const planet = locationManager.getPlanet(idToCheck); + + if(!planet) return { + code: 404, + message: "Not Found", + error: `Non-existent planet provided in '${type}'` + } + + return { + code: 200, + message: "OK", + planet + } +} + +function checkShips(ships: Array<{ id: string, amount: number }>, shipsDB: Array, sourcePlanet: Planet) { + if(typeof ships === "undefined") return { + code: 400, + message: "Bad Request", + error: "Missing 'ships' in body" + } + + for(let i = 0; i < ships.length; i++) { + if(typeof ships[i].id === "undefined" || ships[i].id === "") return { + code: 400, + message: "Bad Request", + error: "Missing ship ID at position " + i + } + + if(!shipsDB.find(ship => ship.id === ships[i].id)) return { + code: 404, + message: "Not Found", + error: "Non-existent ship ID '" + ships[i].id + "' at position " + i + } + + if(typeof ships[i].amount === "undefined") return { + code: 400, + message: "Bad Request", + error: "Missing ship amount for ID '" + ships[i].id + "' at position " + i + } + + if(ships[i].amount % 1 !== 0 || ships[i].amount < 0) return { + code: 400, + message: "Bad Request", + error: "Ship amount for ID '" + ships[i].id + "' is not a non-negative integer at position " + i + } + + if(ships[i].amount > (sourcePlanet.ships.getShipById(ships[i].id)?.amount ?? 0)) return { + code: 400, + message: "Bad Request", + error: "Not enough ships on planet with ID '" + ships[i].id + "' at position " + i + } + } + + return { + code: 200, + message: "OK" + } +} + +function checkCargo(cargo: Array<{ id: string, amount: number }>, ships: Array<{ id: string, amount: number }>, planet: Planet, missionType: MissionType) { + if(missionType === "TRANSPORT" && cargo.length === 0) return { + code: 400, + message: "Bad Request", + error: "Missing 'cargo' in body for requested mission 'TRANSPORT'" + } + + for(let i = 0; i < cargo.length; i++) { + if(typeof cargo[i].id === "undefined") return { + code: 400, + message: "Bad Request", + error: "Missing resource ID at position " + i + } + + if(!planet.resources.resourcesDB.find(resource => resource.id === cargo[i].id)) return { + code: 404, + message: "Not Found", + error: "Non-existent resource ID '" + cargo[i].id + "' at position " + i + } + + if(typeof cargo[i].amount === "undefined") return { + code: 400, + message: "Bad Request", + error: "Missing resource amount for ID '" + cargo[i].id + "' at position " + i + } + + if(cargo[i].amount % 1 !== 0 || cargo[i].amount < 0) return { + code: 400, + message: "Bad Request", + error: "Resource amount for ID '" + cargo[i].id + "' is not a non-negative integer at position " + i + } + + if(cargo[i].amount > (planet.resources.resources.find(res => res.id === cargo[i].id)?.amount ?? 0)) return { + code: 400, + message: "Bad Request", + error: "Not enough resources on planet with ID '" + cargo[i].id + "' at position " + i + } + } + + const totalCargoAvailable = { + solid: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.solid ?? 0) * ship.amount, 0), + liquid: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.liquid ?? 0) * ship.amount, 0), + gas: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.gas ?? 0) * ship.amount, 0) + } + + const totalCargoUsed = { + solid: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "solid" ? acc + resource.amount : acc, 0), + liquid: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "liquid" ? acc + resource.amount : acc, 0), + gas: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "gas" ? acc + resource.amount : acc, 0) + } + + if(totalCargoUsed.solid > totalCargoAvailable.solid) return { + code: 400, + message: "Bad Request", + error: "Not enough solid cargo capacity on ships" + } + + if(totalCargoUsed.liquid > totalCargoAvailable.liquid) return { + code: 400, + message: "Bad Request", + error: "Not enough liquid cargo capacity on ships" + } + + if(totalCargoUsed.gas > totalCargoAvailable.gas) return { + code: 400, + message: "Bad Request", + error: "Not enough gas cargo capacity on ships" + } + + //TODO: check for fuel + + return { + code: 200, + message: "OK" + } +} \ No newline at end of file diff --git a/src/pages/api/fleet/status.ts b/src/pages/api/fleet/status.ts new file mode 100644 index 0000000..ee4a2bf --- /dev/null +++ b/src/pages/api/fleet/status.ts @@ -0,0 +1,36 @@ +import { APIRoute } from "astro"; +import validateAccessToken from "../../../lib/utils/validateAccessToken"; +import { getUserByAccessToken } from "../../../lib/db/users"; +import { getAllFleetByUser } from "../../../lib/db/fleet"; +import parseParams from "../../../lib/utils/parseParams"; + +export const GET: APIRoute = async({ request }) => { + const response = await validateAccessToken(request); + if(response instanceof Response) return response; + + const user = await getUserByAccessToken(response); + if(user === null) { + return new Response( + JSON.stringify({ + code: 401, + message: "Unauthorized" + }), { status: 401 } + ) + } + + let allFleet = (await getAllFleetByUser(user._id)).filter(f => f.arrivalTime.getTime() > Date.now()); + + const params = { + + } + + const URLParams = parseParams(request.url); + + return new Response( + JSON.stringify({ + code: 200, + message: "OK", + data: allFleet + }), { status: 200 } + ) +} \ No newline at end of file diff --git a/src/pages/game/fleet.astro b/src/pages/game/fleet.astro index c1c9cc6..e420f0e 100644 --- a/src/pages/game/fleet.astro +++ b/src/pages/game/fleet.astro @@ -7,6 +7,7 @@ import ResourceBar from '../../components/ResourceBar.astro'; import locationManager from '../../lib/classes/managers/LocationManager'; import { getAllFleetByUser } from '../../lib/db/fleet'; import { getAllShips } from '../../lib/db/ships'; +import { ObjectId } from 'mongodb'; const loggedToken = Astro.cookies.get('sessionToken')?.value ?? null; const username = Astro.cookies.get('username')?.value ?? ""; @@ -18,11 +19,67 @@ if(checkUser === null || checkUser.username !== username) return Astro.redirect( const user = locationManager.getUser(checkUser._id); if(!user) return Astro.redirect('/logout'); +const planetId = Astro.cookies.get('planetid')?.value ?? ""; +if(planetId === "") return "No planet selected"; + +const planet = locationManager.getPlanet(new ObjectId(planetId)); +if(!planet) return "Planet not found"; + const ships = await getAllShips(); -const fleet = await getAllFleetByUser(user.id); +if(Astro.request.method === "POST") { + const form = await Astro.request.formData(); + + const cargo: Array<{ id: string, amount: number }> = []; + + form.forEach((v, k) => { + if(k.match(/cargo\[\d\]\[id\]/)) { + const amount = parseInt(form.get(`${k.substring(0, k.indexOf("]"))}][amount]`)?.toString() ?? "0"); + + if(amount === 0 || isNaN(amount)) return; + + cargo.push({ + id: v.toString(), + amount + }); + } + }); + + const fleetData = { + source: planet._id, + destination: new ObjectId(form.get('destination-planet')?.toString() ?? ""), + mission: form.get('mission')?.toString() ?? "NULL", + ships: ships.map(ship => { + const amount = parseInt(form.get(`ship-amount-${ship.id}`)?.toString() ?? "0"); + if(amount === 0) return null; + return { + id: ship.id, + amount + } + }).filter(s => s !== null), + cargo + } + const response = await fetch(`${Astro.url.origin}/api/fleet/send`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${loggedToken}` + }, + body: JSON.stringify(fleetData) + }); + + console.log(await response.json()); + + return Astro.redirect('/game/fleet'); +} + +await locationManager.updateFleet(); + +const fleet = (await getAllFleetByUser(user.id)).filter(f => new Date().getTime() - f.arrivalTime.getTime() < 0); +fleet.sort((a, b) => a.departureTime.getTime() - b.departureTime.getTime()); const userSystems = locationManager.getSystemsOwnedBy(user.id); +const galaxies = locationManager.galaxies; let own = 0; let friendly = 0; @@ -33,7 +90,7 @@ for(const system of userSystems) { for(const f of fleet) { if(f.source.equals(planet._id)) own++; else if(f.destination.equals(planet._id)) { - if(f.mission === 'attack') enemy++; + if(f.mission === 'ATTACK') enemy++; else { const source = locationManager.getPlanet(f.source)?.manager.owner.id; const destination = locationManager.getPlanet(f.destination)?.manager.owner.id; @@ -44,13 +101,37 @@ for(const system of userSystems) { } } +const sectorsList = galaxies.map(galaxy => { + return { + _id: galaxy._id, + name: galaxy.name, + sectors: galaxy.sectors.map(sector => { + return { + _id: sector._id, + name: sector.name, + systems: sector.systems.map(system => { + return { + _id: system._id, + name: system.name, + planets: system.planets.planets.map(planet => { + return { + _id: planet._id, + name: planet.name + } + }) + } + }) + } + }) + } +}); + const lang = await getLocales(Astro.cookies.get('language')?.value ?? await getHighestWeightedLanguage(Astro.request.headers.get('accept-language'))); --- - - - +
+
+

Sending fleet from {planet.name}

+
+

Ships

+
+ {planet.ships.ships.map(ship =>
+

{getName(lang, 'ships', ship.data.id)} - {ship.amount}

+ +
)} +
+
+

Mission

+ + + +
+

Send to:

+
+

Galaxy

+ +

Sector

+ +

System

+ +
+

Planet

+ +
+
+
+

Cargo

+
+
+ + +
+
+
Add new +
+
+ +
+
\ No newline at end of file + + .fleet-send-container { + margin-top: 40px; + background-color: gray; + border-radius: 10px; + padding: 2px; + } + + .fleet-send-ships { + display: flex; + flex-direction: row; + flex-wrap: wrap; + row-gap: 40px; + column-gap: 2%; + margin-top: 40px; + } + + .fleet-ship-card { + background-color: gray; + border-radius: 10px; + padding: 2px; + } + + .fleet-ship-card h3 { + margin: 0; + } + + .fleet-ship-card input { + width: 10rem; + color: black; + } + + .fleet-destination select { + width: 10rem; + height: 3rem; + color: black; + background-color: darkgray; + } + + .cargo-add-new { + background-color: #aaaaaa; + border-radius: 10px; + padding: 2px; + width: fit-content; + color: black; + } + + .select, .input { + color: black; + } + + \ No newline at end of file diff --git a/src/pages/game/profile.astro b/src/pages/game/profile.astro index aa9f9df..ecd8957 100644 --- a/src/pages/game/profile.astro +++ b/src/pages/game/profile.astro @@ -44,7 +44,7 @@ const currentLanguage = Astro.cookies.get('language')?.value ?? "en"; - + {loggedToken}

{format(getName(lang, 'general', 'user-creation-date'), user?.createdAt.toISOString().slice(0, 19).replace(/-/g, "/").replace("T", " ").toString() ?? "")}

{getName(lang, 'general', 'nav-logout')} diff --git a/src/types/MissionType.ts b/src/types/MissionType.ts new file mode 100644 index 0000000..6014d92 --- /dev/null +++ b/src/types/MissionType.ts @@ -0,0 +1,3 @@ +type MissionType = "TRANSPORT" | "ATTACK" | "TRANSFER"; + +export default MissionType; \ No newline at end of file diff --git a/src/types/db/DBFleet.ts b/src/types/db/DBFleet.ts index 742712d..e5342f2 100644 --- a/src/types/db/DBFleet.ts +++ b/src/types/db/DBFleet.ts @@ -1,11 +1,14 @@ import { ObjectId } from "mongodb"; +import MissionType from "../MissionType"; export default interface DBFleet { _id: ObjectId; source: ObjectId; destination: ObjectId; - finished: boolean; + departureTime: Date; + arrivalTime: Date; returning: boolean; - mission: string; + mission: MissionType; ships: Array<{ id: string, amount: number }>; + cargo: Array<{ id: string, amount: number }>; } \ No newline at end of file