Compare commits
No commits in common. "cc5d482a0f3b47e9a0f7e433952c33d6a437a91f" and "b13a116cd4d6ac98edce9389144ba439f53d24ef" have entirely different histories.
cc5d482a0f
...
b13a116cd4
|
@ -3,7 +3,6 @@ import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/la
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string;
|
id: string;
|
||||||
level: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
image: string;
|
image: string;
|
||||||
|
@ -18,7 +17,7 @@ const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.hea
|
||||||
<div class="item-card" data-id={Astro.props.id}>
|
<div class="item-card" data-id={Astro.props.id}>
|
||||||
<img class="item-card-image" src={Astro.props.image} />
|
<img class="item-card-image" src={Astro.props.image} />
|
||||||
<div class="item-card-main-field">
|
<div class="item-card-main-field">
|
||||||
<div class="item-card-name">{Astro.props.name} | {Astro.props.level}</div>
|
<div class="item-card-name">{Astro.props.name}</div>
|
||||||
<div class="item-card-description">{Astro.props.description}</div>
|
<div class="item-card-description">{Astro.props.description}</div>
|
||||||
<a id={`button_${Astro.props.id}`} href="#" class="item-card-build">{getName(lang, Astro.props.button_type, Astro.props.button_name)}</a>
|
<a id={`button_${Astro.props.id}`} href="#" class="item-card-build">{getName(lang, Astro.props.button_type, Astro.props.button_name)}</a>
|
||||||
<div class="item-card-info-button">i</div>
|
<div class="item-card-info-button">i</div>
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
---
|
---
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
|
import { calculateCurrentAvailableResources } from '../lib/utils/resourceManager';
|
||||||
import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/langDriver';
|
import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/langDriver';
|
||||||
import { getAllResources } from '../lib/db/resources';
|
import { getAllResources } from '../lib/db/resources';
|
||||||
import locationManager from '../lib/classes/managers/LocationManager';
|
|
||||||
import { Resource } from '../lib/classes/managers/ResourceManager';
|
|
||||||
|
|
||||||
const resourceTypes = await getAllResources();
|
const resourceTypes = await getAllResources();
|
||||||
|
|
||||||
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
|
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
|
||||||
|
|
||||||
const planetId = new ObjectId(Astro.cookies.get('planetid')?.value ?? '');
|
const resources = await calculateCurrentAvailableResources(new ObjectId(Astro.cookies.get('planetid')?.value ?? ''));
|
||||||
|
|
||||||
const resources = locationManager.getPlanet(planetId)?.resources;
|
const resourceArray = [];
|
||||||
|
for(const key in resources) {
|
||||||
if(!resources) return;
|
resourceArray.push(resources[key as never]);
|
||||||
|
|
||||||
resources.calculateCurrentAvailableResources();
|
|
||||||
|
|
||||||
const resourceArray: Resource[] = [];
|
|
||||||
for(const key of resources.resources) {
|
|
||||||
resourceArray.push(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
<div id="resourcebar">
|
<div id="resourcebar">
|
||||||
<div class="resourcebar-item-identifier">
|
<div class="resourcebar-item-identifier">
|
||||||
|
@ -29,16 +23,16 @@ for(const key of resources.resources) {
|
||||||
<div id="resourcebar-elements" class="resourcebar-elements">
|
<div id="resourcebar-elements" class="resourcebar-elements">
|
||||||
{resourceArray.map(res =>
|
{resourceArray.map(res =>
|
||||||
<div class="resourcebar-item"
|
<div class="resourcebar-item"
|
||||||
data-res-type={resourceTypes.find(x => x.id === res.id)?.type ?? "solid"}
|
data-res-type={resourceTypes.find(x => x.id === res.name)?.type ?? "solid"}
|
||||||
data-res-amount={res.amount}
|
data-res-amount={res.amount}
|
||||||
data-res-mining-rate={res.perHourMiningRate}
|
data-res-mining-rate={res.perHourMiningRate}
|
||||||
style={(resourceTypes.find(x => x.id === res.id)?.type ?? "solid") === "solid" ? "" : "display: none;"}
|
style={(resourceTypes.find(x => x.id === res.name)?.type ?? "solid") === "solid" ? "" : "display: none;"}
|
||||||
>
|
>
|
||||||
<div class="resourcebar-item-icon">
|
<div class="resourcebar-item-icon">
|
||||||
<img src={resourceTypes.find(x => x.id === res.id)?.icon ?? "#"} alt={res.id} />
|
<img src={resourceTypes.find(x => x.id === res.name)?.icon ?? "#"} alt={res.name} />
|
||||||
</div>
|
</div>
|
||||||
<div class="resourcebar-item-text-wrapper" data-resname={res.id}>
|
<div class="resourcebar-item-text-wrapper" data-resname={res.name}>
|
||||||
<div class="resourcebar-item-text">{getName(lang, 'resources', res.id)}</div>
|
<div class="resourcebar-item-text">{getName(lang, 'resources', res.name)}</div>
|
||||||
<div class="resourcebar-item-amount">[fetching]</div>
|
<div class="resourcebar-item-amount">[fetching]</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="resourcebar-item-tooltip">
|
<div class="resourcebar-item-tooltip">
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
import DBBuilding from "../../types/db/DBBuilding";
|
|
||||||
import BuildingManager from "./managers/BuildingManager";
|
|
||||||
|
|
||||||
export default class Building {
|
|
||||||
manager: BuildingManager
|
|
||||||
data: DBBuilding;
|
|
||||||
level: number;
|
|
||||||
|
|
||||||
constructor(manager: BuildingManager, data: DBBuilding, level: number) {
|
|
||||||
this.manager = manager;
|
|
||||||
this.data = data;
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkRequiredResources(level: number): Promise<boolean> {
|
|
||||||
const resources = await this.manager.planet.resources.calculateCurrentAvailableResources();
|
|
||||||
|
|
||||||
const requirements = this.data.requirements.resources;
|
|
||||||
|
|
||||||
let canBuild = true;
|
|
||||||
|
|
||||||
for(let res of requirements) {
|
|
||||||
const resource = resources.find(r => r.id === res.id);
|
|
||||||
if(!resource) return false;
|
|
||||||
|
|
||||||
const required = Math.pow(this.data.multiplier, level) * res.amount;
|
|
||||||
|
|
||||||
if(resource.amount < required) {
|
|
||||||
canBuild = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return canBuild;
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkRequirements(): Promise<{ canBuild: boolean, error: string }> {
|
|
||||||
const playerBuildings = this.manager.buildings;
|
|
||||||
let playerBuildingsCanBuild = { canBuild: true, missing: "" };
|
|
||||||
this.data.requirements.buildings.forEach((buildingReq: any) => {
|
|
||||||
if(playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0 < buildingReq.level) {
|
|
||||||
playerBuildingsCanBuild = { canBuild: false, missing: `${buildingReq.id} level ${buildingReq.level} required, found ${playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0}` };
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if(!playerBuildingsCanBuild.canBuild) return {
|
|
||||||
canBuild: false,
|
|
||||||
error: playerBuildingsCanBuild.missing
|
|
||||||
}
|
|
||||||
|
|
||||||
// research
|
|
||||||
const playerResearch = this.manager.planet.manager.owner.research;
|
|
||||||
let playerResearchCanBuild = { canBuild: true, missing: "" };
|
|
||||||
for(const researchReq of this.data.requirements.research) {
|
|
||||||
if(playerResearch.research.find((research) => research.id === researchReq.id)?.level ?? 0 < researchReq.level) {
|
|
||||||
playerResearchCanBuild = { canBuild: false, missing: `${researchReq.id} level ${researchReq.level} required, found ${playerResearch.research.find((research) => research.id === researchReq.id)?.level ?? 0}` };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!playerResearchCanBuild.canBuild) return {
|
|
||||||
canBuild: false,
|
|
||||||
error: playerResearchCanBuild.missing
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
canBuild: true,
|
|
||||||
error: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import ResearchManager from "./managers/ResearchManager";
|
|
||||||
import { Planet } from "./managers/PlanetManager";
|
|
||||||
|
|
||||||
export default class User {
|
|
||||||
id: ObjectId;
|
|
||||||
username: string;
|
|
||||||
email: string;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
lastLogin: Date;
|
|
||||||
research: ResearchManager;
|
|
||||||
mainPlanet!: Planet;
|
|
||||||
|
|
||||||
constructor(id: ObjectId, username: string, email: string, createdAt: Date, updatedAt: Date, lastLogin: Date) {
|
|
||||||
this.id = id;
|
|
||||||
this.username = username;
|
|
||||||
this.email = email;
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
this.lastLogin = lastLogin;
|
|
||||||
this.research = new ResearchManager(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
await this.research.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
addMainPlanet(planet: Planet) {
|
|
||||||
this.mainPlanet = planet;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
import { getAllBuildings } from '../../db/buildings';
|
|
||||||
import DBBuilding from '../../../types/db/DBBuilding';
|
|
||||||
import { Planet } from './PlanetManager';
|
|
||||||
import { updatePlanetBuildings } from '../../db/planets';
|
|
||||||
import Building from '../Building';
|
|
||||||
|
|
||||||
export default class BuildingManager {
|
|
||||||
buildings: Array<Building> = [];
|
|
||||||
buildingsDB: Array<DBBuilding> = []
|
|
||||||
planet: Planet;
|
|
||||||
|
|
||||||
constructor(planet: Planet) {
|
|
||||||
this.planet = planet;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init(buildingData: { id: string, level: number }[]) {
|
|
||||||
this.buildingsDB = await getAllBuildings();
|
|
||||||
buildingData.forEach(building => {
|
|
||||||
const buildingToFind = this.buildingsDB.find(b => b.id === building.id);
|
|
||||||
|
|
||||||
if(buildingToFind) this.buildings.push(new Building(
|
|
||||||
this,
|
|
||||||
buildingToFind,
|
|
||||||
building.level
|
|
||||||
))
|
|
||||||
})
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBuildingById(id: string) {
|
|
||||||
return this.buildings.find(building => building.data.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
addBuilding(building: Building) {
|
|
||||||
const findBuilding = this.buildings.find(b => b.data.id === building.data.id);
|
|
||||||
if(!findBuilding) this.buildings.push(building);
|
|
||||||
else findBuilding.level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeBuilding(id: string) {
|
|
||||||
this.buildings = this.buildings.filter(building => building.data.id !== id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync() {
|
|
||||||
await updatePlanetBuildings(this.planet._id, this.buildings.map(building => { return { id: building.data.id, level: building.level } }));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import PlanetManager, { Planet } from "./PlanetManager";
|
|
||||||
import { getAllGalaxies } from "../../db/galaxies";
|
|
||||||
import { getSectorById } from "../../db/sectors";
|
|
||||||
import { getSystemById } from "../../db/systems";
|
|
||||||
import { getAllUsers } from "../../db/users";
|
|
||||||
import User from "../User";
|
|
||||||
|
|
||||||
export type Galaxy = {
|
|
||||||
_id: ObjectId,
|
|
||||||
name: string,
|
|
||||||
sectors: Array<Sector>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Sector = {
|
|
||||||
_id: ObjectId,
|
|
||||||
galaxy: Galaxy,
|
|
||||||
name: string,
|
|
||||||
expedition: null,
|
|
||||||
systems: Array<System>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type System = {
|
|
||||||
_id: ObjectId,
|
|
||||||
sector: Sector,
|
|
||||||
name: string,
|
|
||||||
ownedBy: User,
|
|
||||||
planets: PlanetManager
|
|
||||||
}
|
|
||||||
|
|
||||||
class LocationManager {
|
|
||||||
private static instance: LocationManager;
|
|
||||||
|
|
||||||
private constructor() {}
|
|
||||||
|
|
||||||
public static getInstance(): LocationManager {
|
|
||||||
if (!LocationManager.instance) {
|
|
||||||
LocationManager.instance = new LocationManager();
|
|
||||||
}
|
|
||||||
return LocationManager.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
galaxies: Galaxy[] = [];
|
|
||||||
users: User[] = [];
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const users = await getAllUsers();
|
|
||||||
users.forEach(async user => {
|
|
||||||
this.users.push(new User(user._id, user.username, user.email, user.createdAt, user.updatedAt, user.lastLogin));
|
|
||||||
});
|
|
||||||
|
|
||||||
const galaxies = await getAllGalaxies();
|
|
||||||
for(const galaxy of galaxies) {
|
|
||||||
const galaxyObject: Galaxy = {
|
|
||||||
_id: galaxy._id,
|
|
||||||
name: galaxy.name,
|
|
||||||
sectors: []
|
|
||||||
};
|
|
||||||
|
|
||||||
for(const sectorId of galaxy.sectors) {
|
|
||||||
const sectorData = await getSectorById(sectorId);
|
|
||||||
|
|
||||||
const sectorObject: Sector = {
|
|
||||||
_id: sectorData._id,
|
|
||||||
galaxy: galaxyObject,
|
|
||||||
name: sectorData.name,
|
|
||||||
expedition: null,
|
|
||||||
systems: []
|
|
||||||
};
|
|
||||||
|
|
||||||
for(const systemId of sectorData.systems) {
|
|
||||||
const systemData = await getSystemById(systemId);
|
|
||||||
const user = this.users.find(user => user.id.equals(systemData.ownedBy));
|
|
||||||
|
|
||||||
if(!user) throw new Error("User not found");
|
|
||||||
|
|
||||||
const systemObject: System = {
|
|
||||||
_id: systemData._id,
|
|
||||||
sector: sectorObject,
|
|
||||||
name: systemData.name,
|
|
||||||
ownedBy: user,
|
|
||||||
planets: new PlanetManager(user)
|
|
||||||
};
|
|
||||||
|
|
||||||
await systemObject.planets.fillData(systemData.planets);
|
|
||||||
|
|
||||||
sectorObject.systems.push(systemObject);
|
|
||||||
};
|
|
||||||
|
|
||||||
galaxyObject.sectors.push(sectorObject);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.galaxies.push(galaxyObject);
|
|
||||||
};
|
|
||||||
|
|
||||||
for(const user of this.users) {
|
|
||||||
await user.init();
|
|
||||||
const userDB = users.find(u => u._id.equals(user.id));
|
|
||||||
const mainPlanet = this.getPlanet(userDB?.mainPlanet as ObjectId);
|
|
||||||
|
|
||||||
if(!mainPlanet) throw new Error("Main planet not found");
|
|
||||||
|
|
||||||
user.mainPlanet = mainPlanet;
|
|
||||||
};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getGalaxy(_id: ObjectId) {
|
|
||||||
return this.galaxies.find(galaxy => galaxy._id.equals(_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
getSector(_id: ObjectId) {
|
|
||||||
let foundSector: Sector | undefined;
|
|
||||||
this.galaxies.find(galaxy => galaxy.sectors.find(sector => {
|
|
||||||
if(sector._id.equals(_id)) foundSector = sector;
|
|
||||||
}));
|
|
||||||
return foundSector;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSystem(_id: ObjectId) {
|
|
||||||
let foundSystem: System | undefined;
|
|
||||||
this.galaxies.find(galaxy => galaxy.sectors.find(sector => sector.systems.find(system => {
|
|
||||||
if(system._id.equals(_id)) foundSystem = system
|
|
||||||
})));
|
|
||||||
return foundSystem
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlanet(_id: ObjectId) {
|
|
||||||
let foundPlanet: Planet | undefined;
|
|
||||||
|
|
||||||
for(const galaxy of this.galaxies) {
|
|
||||||
for(const sector of galaxy.sectors) {
|
|
||||||
for(const system of sector.systems) {
|
|
||||||
foundPlanet = system.planets.getPlanetById(_id);
|
|
||||||
if(foundPlanet) break;
|
|
||||||
}
|
|
||||||
if(foundPlanet) break;
|
|
||||||
}
|
|
||||||
if(foundPlanet) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundPlanet;
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser(_id: ObjectId) {
|
|
||||||
return this.users.find(user => user.id.equals(_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const locationManager = LocationManager.getInstance();
|
|
||||||
locationManager.init();
|
|
||||||
export default locationManager;
|
|
|
@ -1,51 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import BuildingManager from "./BuildingManager";
|
|
||||||
import { getPlanetById } from "../../db/planets";
|
|
||||||
import ResourceManager from "./ResourceManager";
|
|
||||||
import User from "../User";
|
|
||||||
|
|
||||||
export type Planet = {
|
|
||||||
_id: ObjectId;
|
|
||||||
manager: PlanetManager;
|
|
||||||
name: string;
|
|
||||||
fields: number;
|
|
||||||
resources: ResourceManager;
|
|
||||||
buildings: BuildingManager;
|
|
||||||
ships: Array<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class PlanetManager {
|
|
||||||
planets: Array<Planet> = [];
|
|
||||||
owner: User;
|
|
||||||
|
|
||||||
constructor(user: User) {
|
|
||||||
this.owner = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillData(planets: ObjectId[]) {
|
|
||||||
await Promise.all(planets.map(async planetId => {
|
|
||||||
const planet = await getPlanetById(planetId);
|
|
||||||
|
|
||||||
const planetObject: Planet = {
|
|
||||||
_id: planet._id,
|
|
||||||
manager: this,
|
|
||||||
name: planet.name,
|
|
||||||
fields: planet.fields,
|
|
||||||
//@ts-ignore
|
|
||||||
resources: null,
|
|
||||||
//@ts-ignore
|
|
||||||
buildings: null,
|
|
||||||
ships: planet.ships
|
|
||||||
}
|
|
||||||
|
|
||||||
planetObject.resources = await new ResourceManager(planetObject).init(planet.resources);
|
|
||||||
planetObject.buildings = await new BuildingManager(planetObject).init(planet.buildings);
|
|
||||||
|
|
||||||
this.planets.push(planetObject);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlanetById(id: ObjectId) {
|
|
||||||
return this.planets.find(planet => planet._id.equals(id));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
import DBResearch from "../../../types/db/DBResearch";
|
|
||||||
import { getAllResearch } from "../../db/research";
|
|
||||||
import { getUserResearch, updateUserResearch } from "../../db/users";
|
|
||||||
import User from "../User";
|
|
||||||
|
|
||||||
export type Research = {
|
|
||||||
id: string,
|
|
||||||
level: number,
|
|
||||||
data: DBResearch
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ResearchManager {
|
|
||||||
research: Array<Research> = [];
|
|
||||||
researchDB: Array<DBResearch> = [];
|
|
||||||
owner: User;
|
|
||||||
|
|
||||||
constructor(user: User) {
|
|
||||||
this.owner = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
this.researchDB = await getAllResearch();
|
|
||||||
const research = await getUserResearch(this.owner);
|
|
||||||
this.research = research.map(r => {
|
|
||||||
const researchData = this.researchDB.find(research => research.id === r.id);
|
|
||||||
if(!researchData) throw new Error(`Research ${r.id} not found`);
|
|
||||||
return {
|
|
||||||
id: r.id,
|
|
||||||
level: r.level,
|
|
||||||
data: researchData
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getResearchById(id: string) {
|
|
||||||
return this.research.find(research => research.data.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
addResearch(research: Research) {
|
|
||||||
const findResearch = this.research.find(r => r.data.id === research.data.id);
|
|
||||||
if(!findResearch) this.research.push(research);
|
|
||||||
else findResearch.level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync() {
|
|
||||||
await updateUserResearch(this.owner, this.research.map(r => { return { id: r.data.id, level: r.level } }));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
import DBResource from "../../../types/db/DBResource";
|
|
||||||
import { updatePlanetResources } from "../../db/planets";
|
|
||||||
import { getAllResources } from "../../db/resources";
|
|
||||||
import { Planet } from "./PlanetManager";
|
|
||||||
|
|
||||||
export type Resource = {
|
|
||||||
id: string,
|
|
||||||
amount: number,
|
|
||||||
lastUpdated: Date,
|
|
||||||
perHourMiningRate: number,
|
|
||||||
data: DBResource
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ResourceManager {
|
|
||||||
resources: Array<Resource> = [];
|
|
||||||
planet: Planet;
|
|
||||||
|
|
||||||
constructor(planet: Planet) {
|
|
||||||
this.planet = planet;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init(resourceData: { id: string, amount: number, lastUpdated: Date, perHourMiningRate: number }[]) {
|
|
||||||
const resources = await getAllResources();
|
|
||||||
|
|
||||||
if(resourceData.length === 0) {
|
|
||||||
resourceData = [
|
|
||||||
{
|
|
||||||
id: "coal",
|
|
||||||
amount: 11,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "iron",
|
|
||||||
amount: 22,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 22
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gold",
|
|
||||||
amount: 33,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 33
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "water",
|
|
||||||
amount: 44,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 44
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "sulfuric-acid",
|
|
||||||
amount: 55,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 55
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "liquid-nitrogen",
|
|
||||||
amount: 66,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 66
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "hydrogen",
|
|
||||||
amount: 77,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 77
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "oxygen",
|
|
||||||
amount: 88,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 88
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "helium-3",
|
|
||||||
amount: 99,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
perHourMiningRate: 99
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
await updatePlanetResources(this.planet._id, this.resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceData.forEach(resource => {
|
|
||||||
const resFromDB = resources.find(res => res.id === resource.id);
|
|
||||||
if(resFromDB) this.resources.push({
|
|
||||||
id: resource.id,
|
|
||||||
amount: resource.amount,
|
|
||||||
lastUpdated: resource.lastUpdated,
|
|
||||||
perHourMiningRate: resource.perHourMiningRate,
|
|
||||||
data: resFromDB
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getResourceById(resId: string) {
|
|
||||||
return this.resources.find(res => res.id === resId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculateCurrentAvailableResources() {
|
|
||||||
this.resources.forEach(res => {
|
|
||||||
const timeDiff = Math.abs((new Date()).getTime() - res.lastUpdated.getTime());
|
|
||||||
const hours = timeDiff / (1000 * 60 * 60);
|
|
||||||
const amountToAdd = hours * res.perHourMiningRate;
|
|
||||||
res.amount += amountToAdd;
|
|
||||||
res.lastUpdated = new Date();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
await updatePlanetResources(this.planet._id, this.resources);
|
|
||||||
|
|
||||||
return this.resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDifference(resources: { id: string, amount: number }[]): Promise<Array<Resource>> {
|
|
||||||
const currentResources = await this.calculateCurrentAvailableResources();
|
|
||||||
const difference: Resource[] = [];
|
|
||||||
|
|
||||||
currentResources.forEach(res => {
|
|
||||||
const currentRes = resources.find(r => r.id === res.id);
|
|
||||||
if(currentRes) difference.push({
|
|
||||||
id: res.id,
|
|
||||||
amount: res.amount - currentRes.amount,
|
|
||||||
lastUpdated: res.lastUpdated,
|
|
||||||
perHourMiningRate: res.perHourMiningRate,
|
|
||||||
data: res.data
|
|
||||||
});
|
|
||||||
else difference.push(res);
|
|
||||||
});
|
|
||||||
|
|
||||||
return difference;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(resources: Resource[]) {
|
|
||||||
this.resources = resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync() {
|
|
||||||
await updatePlanetResources(this.planet._id, this.resources.map(res => {
|
|
||||||
return {
|
|
||||||
id: res.id,
|
|
||||||
amount: res.amount,
|
|
||||||
lastUpdated: res.lastUpdated,
|
|
||||||
perHourMiningRate: res.perHourMiningRate
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { AccessTokens } from './mongodb';
|
import { AccessTokens } from './mongodb';
|
||||||
|
import type AccessToken from '../../types/AccessToken';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import DBAccessToken from '../../types/db/DBAccessToken';
|
|
||||||
import AccessToken from '../../types/AccessToken';
|
|
||||||
import locationManager from '../classes/managers/LocationManager';
|
|
||||||
|
|
||||||
export const createAccessToken = async (accessToken: AccessToken) => {
|
export const createAccessToken = async (accessToken: AccessToken) => {
|
||||||
const newAccessToken = await (await AccessTokens()).insertOne(accessToken);
|
const newAccessToken = await (await AccessTokens()).insertOne(accessToken);
|
||||||
|
@ -25,7 +23,7 @@ export const getAccessToken = async (accessToken: string) => {
|
||||||
{ createdAt },
|
{ createdAt },
|
||||||
{ user },
|
{ user },
|
||||||
{ entropy }
|
{ entropy }
|
||||||
] }) as Promise<DBAccessToken | null>;
|
] }) as Promise<AccessToken | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAllAccessTokens = async () => {
|
export const getAllAccessTokens = async () => {
|
||||||
|
@ -39,24 +37,7 @@ export const getAllAccessTokens = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const accessTokens = await AccessTokens();
|
const accessTokens = await AccessTokens();
|
||||||
const arrayOfTokens = await accessTokens.find({}).toArray() as DBAccessToken[];
|
const arrayOfTokens = await accessTokens.find({}).toArray() as AccessToken[];
|
||||||
|
let arr = [master].concat(arrayOfTokens);
|
||||||
const arr = [master];
|
|
||||||
|
|
||||||
for(const token of arrayOfTokens) {
|
|
||||||
const user = locationManager.getUser(token.user) ?? null;
|
|
||||||
|
|
||||||
const tokenObject: AccessToken = {
|
|
||||||
type: token.type,
|
|
||||||
user,
|
|
||||||
entropy: token.entropy,
|
|
||||||
createdAt: token.createdAt,
|
|
||||||
expiresAt: token.expiresAt,
|
|
||||||
createdFrom: token.createdFrom
|
|
||||||
}
|
|
||||||
|
|
||||||
arr.push(tokenObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import DBBuilding from '../../types/db/DBBuilding';
|
import DBBuilding from '../../types/DBBuilding';
|
||||||
import { Buildings } from '../db/mongodb';
|
import { Buildings } from '../db/mongodb';
|
||||||
|
|
||||||
export const getAllBuildings = async () => {
|
export const getAllBuildings = async () => {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import { Galaxies } from "./mongodb"
|
|
||||||
import DBGalaxy from "../../types/db/DBGalaxy";
|
|
||||||
|
|
||||||
export const getAllGalaxies = async () => {
|
|
||||||
return await (await Galaxies()).find({}).toArray() as DBGalaxy[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getGalaxyById = async (id: ObjectId) => {
|
|
||||||
return await (await Galaxies()).findOne({
|
|
||||||
_id: id
|
|
||||||
}) as DBGalaxy;
|
|
||||||
}
|
|
|
@ -8,6 +8,7 @@ const mongo = new MongoClient(uri, options);
|
||||||
|
|
||||||
export const connect = async () => {
|
export const connect = async () => {
|
||||||
await mongo.connect();
|
await mongo.connect();
|
||||||
|
// return mongo.db(dbName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const disconnect = async () => {
|
export const disconnect = async () => {
|
||||||
|
@ -29,21 +30,6 @@ export const AccessTokens = async () => {
|
||||||
return db.collection('accessTokens');
|
return db.collection('accessTokens');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Galaxies = async () => {
|
|
||||||
const db = await getDB();
|
|
||||||
return db.collection('galaxies');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Sectors = async () => {
|
|
||||||
const db = await getDB();
|
|
||||||
return db.collection('sectors');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Systems = async () => {
|
|
||||||
const db = await getDB();
|
|
||||||
return db.collection('systems');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Planets = async () => {
|
export const Planets = async () => {
|
||||||
const db = await getDB();
|
const db = await getDB();
|
||||||
return db.collection('planets');
|
return db.collection('planets');
|
||||||
|
|
|
@ -1,29 +1,74 @@
|
||||||
import { Planets } from '../db/mongodb';
|
import { Planets } from '../db/mongodb';
|
||||||
|
import type User from '../../types/User';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import DBPlanet from '../../types/db/DBPlanet';
|
import type Planet from '../../types/Planet';
|
||||||
|
import { getUserById } from './users';
|
||||||
|
import type Building from '../../types/Building';
|
||||||
|
import type Ship from '../../types/Ship';
|
||||||
|
import type PlayerResource from '../../types/PlayerResource';
|
||||||
|
|
||||||
export const getAllPlanets = async () => {
|
export const getAllPlanets = async (options?: { fetchUserPlanets: boolean }) => {
|
||||||
return await (await Planets()).find({}).toArray() as DBPlanet[];
|
const planets = await Planets();
|
||||||
|
const fetched = (await planets.find({}).toArray()).map(async planet => {
|
||||||
|
planet.owner = await getUserById(planet.owner);
|
||||||
|
return planet;
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.all(fetched) as unknown as Array<Planet>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createPlanet = async (options: { name: string, owner?: User, ownerId?: ObjectId, fields?: number }) => {
|
||||||
|
if(options.owner !== undefined && options.ownerId !== undefined) throw new Error("Duplicate identifier");
|
||||||
|
|
||||||
|
let user: ObjectId;
|
||||||
|
if(options.ownerId) user = options.ownerId;
|
||||||
|
else if(options.owner) user = options.owner._id;
|
||||||
|
else throw new Error("Unknown error");
|
||||||
|
|
||||||
|
if(options.fields === undefined) options.fields = 20;
|
||||||
|
|
||||||
|
//@ts-ignore TODO: find another way of handling IDs from types before inserting to database
|
||||||
|
const planet = {
|
||||||
|
owner: user,
|
||||||
|
name: options.name,
|
||||||
|
fields: options.fields,
|
||||||
|
resources: new Array<PlayerResource>,
|
||||||
|
buildings: new Array<Building>,
|
||||||
|
ships: new Array<Ship>
|
||||||
|
}
|
||||||
|
|
||||||
|
await (await Planets()).insertOne(planet);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPlanetById = async (id: ObjectId) => {
|
export const getPlanetById = async (id: ObjectId) => {
|
||||||
return await (await Planets()).findOne({ _id: id }) as DBPlanet;
|
const planets = await Planets();
|
||||||
|
const planet = await planets.findOne({
|
||||||
|
_id: id
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!planet) return null;
|
||||||
|
|
||||||
|
planet.owner = await getUserById(planet.owner);
|
||||||
|
return planet as Planet;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updatePlanetResources = async (planetId: ObjectId, resources: Array<any>) => {
|
export const createOrUpgradeBuilding = async (planetId: ObjectId, building: Building) => {
|
||||||
const planets = await Planets();
|
const planet = await getPlanetById(planetId);
|
||||||
await planets.updateOne({ _id: planetId }, {
|
if(!planet) throw new Error("Planet not found");
|
||||||
$set: {
|
|
||||||
resources
|
const buildingIndex = planet.buildings.findIndex(b => b.id === building.id);
|
||||||
}
|
if(buildingIndex === -1) {
|
||||||
});
|
planet.buildings.push(building);
|
||||||
|
} else {
|
||||||
|
planet.buildings[buildingIndex].level++;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updatePlanetBuildings = async (planetId: ObjectId, buildings: Array<{ id: string, level: number }>) => {
|
|
||||||
const planets = await Planets();
|
const planets = await Planets();
|
||||||
await planets.updateOne({ _id: planetId }, {
|
await planets.updateOne({
|
||||||
|
_id: planetId
|
||||||
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
buildings
|
buildings: planet.buildings
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import DBResearch from '../../types/db/DBResearch';
|
import DBResearch from '../../types/DBResearch';
|
||||||
import { Research } from '../db/mongodb';
|
import { Research } from '../db/mongodb';
|
||||||
|
|
||||||
export const getAllResearch = async () => {
|
export const getAllResearch = async () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DBResource from '../../types/db/DBResource';
|
import DBResource from '../../types/DBResource';
|
||||||
import { Resources } from '../db/mongodb';
|
import { Resources } from '../db/mongodb';
|
||||||
|
|
||||||
export const getAllResources = async () => {
|
export const getAllResources = async () => {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import { Sectors } from "./mongodb";
|
|
||||||
import DBSector from "../../types/db/DBSector";
|
|
||||||
|
|
||||||
export const getAllSectors = async () => {
|
|
||||||
return await (await Sectors()).find({}).toArray() as DBSector[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSectorById = async (id: ObjectId) => {
|
|
||||||
return await (await Sectors()).findOne({
|
|
||||||
_id: id
|
|
||||||
}) as DBSector;
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DBShip from '../../types/db/DBShip';
|
import DBShip from '../../types/DBShip';
|
||||||
import { Ships } from '../db/mongodb';
|
import { Ships } from '../db/mongodb';
|
||||||
|
|
||||||
export const getAllShips = async () => {
|
export const getAllShips = async () => {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
import { Systems } from "./mongodb";
|
|
||||||
import DBSystem from "../../types/db/DBSystem";
|
|
||||||
|
|
||||||
export const getAllSystems = async () => {
|
|
||||||
return await (await Systems()).find({}).toArray() as DBSystem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSystemById = async (id: ObjectId) => {
|
|
||||||
return await (await Systems()).findOne({
|
|
||||||
_id: id
|
|
||||||
}) as DBSystem;
|
|
||||||
}
|
|
|
@ -1,30 +1,33 @@
|
||||||
import { Users } from '../db/mongodb';
|
import { Planets, Users } from '../db/mongodb';
|
||||||
|
import type User from '../../types/User';
|
||||||
|
import type AccessToken from '../../types/AccessToken';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { hash } from 'argon2'
|
import { hash } from 'argon2'
|
||||||
import DBUser from '../../types/db/DBUser';
|
import { createInitialResources } from '../utils/resourceManager';
|
||||||
import User from '../classes/User';
|
import type Research from '../../types/Research';
|
||||||
import AccessToken from '../../types/AccessToken';
|
|
||||||
|
|
||||||
export const getAllUsers = async () => {
|
export const getAllUsers = async () => {
|
||||||
const users = await Users();
|
const users = await Users();
|
||||||
return users.find({}).toArray() as Promise<DBUser[]>;
|
return users.find({}).toArray() as Promise<User[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createUser = async (username: string, email: string, password: string) => {
|
export const createUser = async (username: string, email: string, password: string) => {
|
||||||
const user = {
|
const user: User = {
|
||||||
username,
|
username,
|
||||||
email,
|
email,
|
||||||
password: await hash(password),
|
password: await hash(password),
|
||||||
lastLogin: new Date(),
|
lastLogin: new Date(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
research: [],
|
//@ts-ignore
|
||||||
|
resources: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await (await Users()).insertOne(user);
|
await (await Users()).insertOne(user);
|
||||||
const newUser = await getUserByNickOrEmail(username);
|
const newUser = await getUserByNickOrEmail(username);
|
||||||
if(!newUser) return user;
|
if(!newUser) return user;
|
||||||
|
createInitialResources(newUser._id);
|
||||||
return newUser;
|
return newUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ export const getUserById = async (id: ObjectId) => {
|
||||||
const users = await Users();
|
const users = await Users();
|
||||||
return users.findOne({
|
return users.findOne({
|
||||||
_id: id
|
_id: id
|
||||||
}) as Promise<DBUser | null>;
|
}) as Promise<User | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserByNickOrEmail = async (searchString: string) => {
|
export const getUserByNickOrEmail = async (searchString: string) => {
|
||||||
|
@ -47,18 +50,14 @@ export const getUserByNickOrEmail = async (searchString: string) => {
|
||||||
{ username: searchString },
|
{ username: searchString },
|
||||||
{ email: searchString }
|
{ email: searchString }
|
||||||
]
|
]
|
||||||
}) as Promise<DBUser | null>;
|
}) as Promise<User | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserByAccessToken = async(accessToken: string | AccessToken): Promise<DBUser | null> => {
|
export const getUserByAccessToken = async(accessToken: string | AccessToken): Promise<User | null> => {
|
||||||
if(typeof accessToken === "string") {
|
if(typeof accessToken === "string") {
|
||||||
const userId = new ObjectId(Buffer.from(accessToken.split(".")[2], 'base64url').toString());
|
const userId = new ObjectId(Buffer.from(accessToken.split(".")[2], 'base64url').toString());
|
||||||
return getUserById(userId);
|
return getUserById(userId);
|
||||||
} else {
|
} else return getUserById(accessToken.user as ObjectId)
|
||||||
const user = accessToken.user;
|
|
||||||
if(!user) return null;
|
|
||||||
return getUserById(user?.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateLastLogin = async (user: User) => {
|
export const updateLastLogin = async (user: User) => {
|
||||||
|
@ -66,14 +65,54 @@ export const updateLastLogin = async (user: User) => {
|
||||||
return users.updateOne({ username: user.username }, { $set: { lastLogin: new Date() } });
|
return users.updateOne({ username: user.username }, { $set: { lastLogin: new Date() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserResearch = async (user: User): Promise<Array<{ id: string, level: number }>> => {
|
export const getUserResearch = async (user: User): Promise<Array<Research>> => {
|
||||||
const users = await Users();
|
const research: Array<Research> = [];
|
||||||
const rawUser = await users.findOne({ username: user.username });
|
|
||||||
if (!rawUser) return [];
|
if (user?.research !== undefined) {
|
||||||
return rawUser.research;
|
user?.research.forEach((res: Research) => {
|
||||||
|
research.push(res);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateUserResearch = async (user: User, research: Array<{ id: string, level: number }>) => {
|
return research;
|
||||||
const users = await Users();
|
}
|
||||||
users.updateOne({ username: user.username }, { $set: { research } });
|
|
||||||
|
export const createOrUpgradeResearch = async (userId: ObjectId, research: Research) => {
|
||||||
|
const users = await Users();
|
||||||
|
|
||||||
|
const result = await users.updateOne(
|
||||||
|
{ _id: userId, "research.id": research.id },
|
||||||
|
{ $set: { "research.$.level": research.level } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.modifiedCount === 0) {
|
||||||
|
await users.updateOne({ _id: userId },
|
||||||
|
{ $push: { research } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getUserWithPlanets = async (id: ObjectId): Promise<User | null> => {
|
||||||
|
const users = await Users();
|
||||||
|
const planets = await Planets();
|
||||||
|
|
||||||
|
const rawUser = await users.findOne({
|
||||||
|
_id: id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!rawUser) return null;
|
||||||
|
|
||||||
|
const userPlanets = (await planets.find({
|
||||||
|
owner: id
|
||||||
|
}).toArray()).map(planet => {
|
||||||
|
planet.owner = rawUser;
|
||||||
|
return planet;
|
||||||
|
});
|
||||||
|
|
||||||
|
rawUser.planets = {
|
||||||
|
partial: false,
|
||||||
|
data: userPlanets
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawUser as User;
|
||||||
}
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import type Resource from "../../types/Resource";
|
||||||
|
import type Resources from "../../types/Resources";
|
||||||
|
|
||||||
|
export default function calculateAvailableResources(userResources: Array<Resource>, buildingCost: Array<Resource>) {
|
||||||
|
let canBuild = true;
|
||||||
|
const resources = {} as Array<Resource>;
|
||||||
|
|
||||||
|
userResources.forEach((userResource) => {
|
||||||
|
const resource = buildingCost.find((buildingResource) => buildingResource.name === userResource.name);
|
||||||
|
if (resource) {
|
||||||
|
resources.push({
|
||||||
|
name: userResource.name,
|
||||||
|
amount: userResource.amount - resource.amount
|
||||||
|
});
|
||||||
|
if (userResource.amount < resource.amount) canBuild = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
canBuild,
|
||||||
|
resources
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { ObjectId } from "mongodb"
|
||||||
|
import { Planets } from "../db/mongodb";
|
||||||
|
import type PlayerResource from "../../types/PlayerResource";
|
||||||
|
import { getPlanetById } from "../db/planets";
|
||||||
|
|
||||||
|
export const createInitialResources = async (planetId: ObjectId) => {
|
||||||
|
const resources: Array<PlayerResource> = [
|
||||||
|
{
|
||||||
|
name: "coal",
|
||||||
|
amount: 11,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "iron",
|
||||||
|
amount: 22,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gold",
|
||||||
|
amount: 33,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "water",
|
||||||
|
amount: 44,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 44
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sulfuricAcid",
|
||||||
|
amount: 55,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "liquidNitrogen",
|
||||||
|
amount: 66,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 66
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hydrogen",
|
||||||
|
amount: 77,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 77
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "oxygen",
|
||||||
|
amount: 88,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 88
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "helium3",
|
||||||
|
amount: 99,
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
perHourMiningRate: 99
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
updatePlanetResources(planetId, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getResourcesFromPlanet = async (planetId: ObjectId): Promise<Array<PlayerResource> | null> => {
|
||||||
|
const planet = await getPlanetById(planetId);
|
||||||
|
|
||||||
|
if(!planet) return null;
|
||||||
|
|
||||||
|
return planet.resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updatePlanetResources = async (planetId: ObjectId, resources: Array<PlayerResource>) => {
|
||||||
|
const planets = await Planets();
|
||||||
|
await planets.updateOne({ _id: planetId }, {
|
||||||
|
$set: {
|
||||||
|
resources
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calculateCurrentAvailableResources = async (planetId: ObjectId): Promise<Array<PlayerResource>> => {
|
||||||
|
const resources = await getResourcesFromPlanet(planetId);
|
||||||
|
|
||||||
|
if(resources === null) return [];
|
||||||
|
|
||||||
|
resources.forEach(res => {
|
||||||
|
const timeDiff = Math.abs((new Date()).getTime() - res.lastUpdated.getTime());
|
||||||
|
const hours = timeDiff / (1000 * 60 * 60);
|
||||||
|
const amountToAdd = hours * res.perHourMiningRate;
|
||||||
|
res.amount += amountToAdd;
|
||||||
|
res.lastUpdated = new Date();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
updatePlanetResources(planetId, resources);
|
||||||
|
return resources;
|
||||||
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
import { ObjectId } from "mongodb";
|
import type { ObjectId } from "mongodb";
|
||||||
import AccessToken from "../../types/AccessToken";
|
import type AccessToken from "../../types/AccessToken";
|
||||||
import { getAccessToken } from "../db/accessTokens";
|
import { getAccessToken } from "../db/accessTokens";
|
||||||
import { getUserById } from "../db/users";
|
import { getUserById } from "../db/users";
|
||||||
import locationManager from "../classes/managers/LocationManager";
|
|
||||||
|
|
||||||
export default async function validateAccessToken(request: Request): Promise<Response | AccessToken> {
|
export default async function validateAccessToken(request: Request): Promise<Response | AccessToken> {
|
||||||
let accessToken = request.url.split("?")[1]?.split("&").filter((x) => x.split("=")[0] === "token")[0].split("=")[1];
|
let accessToken = request.url.split("?")[1]?.split("&").filter((x) => x.split("=")[0] === "token")[0].split("=")[1];
|
||||||
|
@ -59,12 +58,5 @@ export default async function validateAccessToken(request: Request): Promise<Res
|
||||||
}), { status: 403 }
|
}), { status: 403 }
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return response;
|
||||||
type: response.type,
|
|
||||||
user: locationManager.getUser(user._id),
|
|
||||||
entropy: response.entropy,
|
|
||||||
createdAt: response.createdAt,
|
|
||||||
expiresAt: response.expiresAt,
|
|
||||||
createdFrom: response.createdFrom
|
|
||||||
} as AccessToken;
|
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import { randomBytes, createHash } from "crypto";
|
import { randomBytes, createHash } from "crypto";
|
||||||
import type { APIRoute } from "astro";
|
import type { APIRoute } from "astro";
|
||||||
|
import type AccessToken from "../../../types/AccessToken";
|
||||||
import { createAccessToken } from "../../../lib/db/accessTokens";
|
import { createAccessToken } from "../../../lib/db/accessTokens";
|
||||||
import { getUserByNickOrEmail } from "../../../lib/db/users";
|
import { getUserByNickOrEmail } from "../../../lib/db/users";
|
||||||
import config from '../../../../config.json';
|
import config from '../../../../config.json';
|
||||||
import AccessToken from "../../../types/AccessToken";
|
import type { ObjectId } from "mongodb";
|
||||||
import locationManager from "../../../lib/classes/managers/LocationManager";
|
|
||||||
|
|
||||||
export const POST: APIRoute = async({ request }) => {
|
export const POST: APIRoute = async({ request }) => {
|
||||||
const data = await request.json().catch(() => {return new Response(
|
const data = await request.json().catch(() => {return new Response(
|
||||||
|
@ -53,25 +53,16 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timestamp = Buffer.from(String(Date.now())).toString('base64url');
|
const timestamp = Buffer.from(String(Date.now())).toString('base64url');
|
||||||
const userEncoded = Buffer.from(userFromDb._id?.toString() ?? "").toString('base64url');
|
const user = Buffer.from(userFromDb._id?.toString() ?? "").toString('base64url');
|
||||||
const random = randomBytes(16).toString("base64url");
|
const random = randomBytes(16).toString("base64url");
|
||||||
const randomHashed = createHash("sha256").update(random).digest("hex");
|
const randomHashed = createHash("sha256").update(random).digest("hex");
|
||||||
const expiresIn = (data.duration ?? 86400) * 1000;
|
const expiresIn = (data.duration ?? 86400) * 1000;
|
||||||
|
|
||||||
const tokenString = `A.${timestamp}.${userEncoded}.${random}`;
|
const tokenString = `A.${timestamp}.${user}.${random}`;
|
||||||
|
|
||||||
const user = locationManager.getUser(userFromDb._id);
|
|
||||||
if(!user) return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
code: 404,
|
|
||||||
message: "Not found",
|
|
||||||
error: `User ${data.username} not found`
|
|
||||||
}), { status: 404 }
|
|
||||||
)
|
|
||||||
|
|
||||||
const accessToken: AccessToken = {
|
const accessToken: AccessToken = {
|
||||||
type: "A",
|
type: "A",
|
||||||
user,
|
user: userFromDb._id as ObjectId,
|
||||||
entropy: randomHashed.toString(),
|
entropy: randomHashed.toString(),
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
expiresAt: new Date(now.getTime() + expiresIn),
|
expiresAt: new Date(now.getTime() + expiresIn),
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
import type { APIRoute } from "astro";
|
import type { APIRoute } from "astro";
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
import { getUserByAccessToken } from "../../../lib/db/users";
|
import { getUserByAccessToken } from "../../../lib/db/users";
|
||||||
|
import type User from "../../../types/User";
|
||||||
|
|
||||||
export const GET: APIRoute = async({ request }) => {
|
export const GET: APIRoute = async({ request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
if(response instanceof Response) return response;
|
if(response instanceof Response) return response;
|
||||||
|
|
||||||
const user = await getUserByAccessToken(response);
|
const user = (await getUserByAccessToken(response)) as User;
|
||||||
|
|
||||||
if(!user) return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
code: 404,
|
|
||||||
message: "Not found",
|
|
||||||
data: "Access token does not match any user"
|
|
||||||
}), { status: 404 }
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import { type APIRoute } from "astro";
|
import { build, type APIRoute } from "astro";
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
import { getUserByAccessToken } from "../../../lib/db/users";
|
import { calculateCurrentAvailableResources, updatePlanetResources } from "../../../lib/utils/resourceManager";
|
||||||
|
import { getUserByAccessToken, getUserResearch } from "../../../lib/db/users";
|
||||||
|
import Planet from "../../../types/Planet";
|
||||||
|
import { createOrUpgradeBuilding, getPlanetById } from "../../../lib/db/planets";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
import locationManager from "../../../lib/classes/managers/LocationManager";
|
import DBResource from "../../../types/PlayerResource";
|
||||||
import Building from "../../../lib/classes/Building";
|
import { getAllBuildings } from "../../../lib/db/buildings";
|
||||||
import { getAllResources } from "../../../lib/db/resources";
|
import DBBuilding from "../../../types/DBBuilding";
|
||||||
|
|
||||||
export const POST: APIRoute = async({ request }) => {
|
export const POST: APIRoute = async({ request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
|
@ -33,77 +36,120 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPlanet = locationManager.getPlanet(new ObjectId(body.planet));
|
const buildingId = body.building;
|
||||||
|
let buildingData: DBBuilding | null = null;
|
||||||
|
|
||||||
|
const buildings = await getAllBuildings();
|
||||||
|
|
||||||
|
buildingData = buildings.find((element) => element.id === buildingId) ?? null;
|
||||||
|
|
||||||
|
if(!buildingData) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid building id"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let userPlanet: Planet | null;
|
||||||
|
try {
|
||||||
|
userPlanet = await getPlanetById(new ObjectId(body.planetId));
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid planet id"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
if(!userPlanet) {
|
if(!userPlanet) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 400,
|
code: 404,
|
||||||
message: "Bad Request",
|
message: "Not Found",
|
||||||
error: "Invalid planet ID"
|
error: "Planet not found"
|
||||||
}), { status: 400 }
|
}), { status: 404 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildingId: string = body.building;
|
// check requirements
|
||||||
|
// buildings
|
||||||
const buildingObj = userPlanet.buildings.buildingsDB.find(b => b.id === buildingId);
|
const playerBuildings = userPlanet.buildings;
|
||||||
|
buildingData.requirements.buildings.forEach((buildingReq: any) => {
|
||||||
if(!buildingObj) return new Response(
|
if(playerBuildings.filter((building) => building.id === buildingReq.id)[0].level < buildingReq.level) {
|
||||||
JSON.stringify({
|
|
||||||
code: 400,
|
|
||||||
message: "Bad Request",
|
|
||||||
error: "Invalid building ID"
|
|
||||||
}), { status: 400 }
|
|
||||||
)
|
|
||||||
|
|
||||||
const building = new Building(userPlanet.buildings, buildingObj, 1);
|
|
||||||
|
|
||||||
const requirements = await building.checkRequirements();
|
|
||||||
const resources = await building.checkRequiredResources((userPlanet.buildings.getBuildingById(buildingId)?.level ?? 0) + 1);
|
|
||||||
|
|
||||||
if(!requirements.canBuild || !resources) {
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 400,
|
code: 400,
|
||||||
message: "Bad Request",
|
message: "Bad Request",
|
||||||
error: requirements.error + " | " + resources ? "" : "Not enough resources"
|
error: `${buildingReq.id} level ${buildingReq.level} required, found ${playerBuildings.filter((building) => building.id === buildingReq.id)[0].level}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// research
|
||||||
|
const playerResearch = await getUserResearch(user);
|
||||||
|
buildingData.requirements.research.forEach((researchReq: any) => {
|
||||||
|
if(playerResearch.filter((research) => research.id === researchReq.id)[0].level < researchReq.level) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: `${researchReq.id} level ${researchReq.level} required, found ${playerResearch.filter((research) => research.id === researchReq.id)[0].level}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// resources
|
||||||
|
const resources = await calculateCurrentAvailableResources(userPlanet._id);
|
||||||
|
if(!resources) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 500,
|
||||||
|
message: "Internal Server Error",
|
||||||
|
error: "Failed to get resources"
|
||||||
|
}), { status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const playerCurrentResearch = playerResearch.filter((element: any) => element.id === buildingId)[0];
|
||||||
|
const level = playerCurrentResearch ? playerCurrentResearch.level : 0;
|
||||||
|
const newResources = structuredClone(resources);
|
||||||
|
const missingResources: Array<{}> = [];
|
||||||
|
Object.entries(buildingData.requirements.resources).forEach(([key, value]) => {
|
||||||
|
const res = resources.filter((element: DBResource) => element.name === value.name)[0];
|
||||||
|
const cost = playerCurrentResearch ? value.amount * Math.pow((buildingData as {multiplier: number}).multiplier, level) : value.amount;
|
||||||
|
|
||||||
|
if(res.amount < cost) {
|
||||||
|
missingResources.push({
|
||||||
|
name: key,
|
||||||
|
required: cost,
|
||||||
|
available: res.amount
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else newResources.filter((element: DBResource) => element.name === value.name)[0].amount -= cost;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(missingResources.length > 0) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
data: missingResources
|
||||||
}), { status: 400 }
|
}), { status: 400 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourcesDiff = await userPlanet.resources.getDifference(building.data.requirements.resources.map(res => {
|
await updatePlanetResources(userPlanet._id, newResources);
|
||||||
return {
|
await createOrUpgradeBuilding(userPlanet._id, { id: buildingId, level: level + 1 });
|
||||||
id: res.id,
|
|
||||||
amount: Math.pow(building.data.multiplier, (userPlanet.buildings.getBuildingById(buildingId)?.level ?? 0) + 1) * res.amount
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const resourceDB = await getAllResources();
|
|
||||||
const resourcesAfter = resourcesDiff.map(res => {
|
|
||||||
const data = resourceDB.find(r => r.id === res.id);
|
|
||||||
|
|
||||||
if(!data) throw new Error("Resource not found");
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: res.id,
|
|
||||||
amount: res.amount,
|
|
||||||
lastUpdated: res.lastUpdated,
|
|
||||||
perHourMiningRate: res.perHourMiningRate,
|
|
||||||
data
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
userPlanet.resources.update(resourcesAfter);
|
|
||||||
userPlanet.buildings.addBuilding(building);
|
|
||||||
|
|
||||||
await userPlanet.buildings.sync();
|
|
||||||
await userPlanet.resources.sync();
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 200,
|
code: 200,
|
||||||
message: "OK"
|
message: "OK"
|
||||||
}), { status: 200 }
|
}), { status: 200 }
|
||||||
);
|
)
|
||||||
}
|
}
|
|
@ -1,21 +1,17 @@
|
||||||
import { APIRoute } from "astro";
|
import { APIRoute } from "astro";
|
||||||
import { getAllPlanets } from "../../../lib/db/planets";
|
import { getAllPlanets } from "../../../lib/db/planets";
|
||||||
|
import Planet from "../../../types/Planet";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
import locationManager from "../../../lib/classes/managers/LocationManager";
|
|
||||||
|
|
||||||
export const GET: APIRoute = async ({ request }) => {
|
export const GET: APIRoute = async ({ request }) => {
|
||||||
const planets = await getAllPlanets();
|
const planets = await getAllPlanets();
|
||||||
|
|
||||||
const response: Array<{planetId: ObjectId, ownerId: ObjectId, name: string}> = [];
|
const response: Array<{planetId: ObjectId, ownerId: ObjectId, name: string}> = [];
|
||||||
|
|
||||||
planets.forEach(planet => {
|
planets.forEach((planet: Planet) => {
|
||||||
const playerPlanet = locationManager.getPlanet(planet._id);
|
|
||||||
|
|
||||||
if(!playerPlanet) return;
|
|
||||||
|
|
||||||
response.push({
|
response.push({
|
||||||
planetId: planet._id,
|
planetId: planet._id,
|
||||||
ownerId: playerPlanet.manager.owner.id,
|
ownerId: planet.owner._id,
|
||||||
name: planet.name,
|
name: planet.name,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { APIRoute } from "astro";
|
import { APIRoute } from "astro";
|
||||||
|
import { getPlanetById } from "../../../../lib/db/planets";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
|
import Planet from "../../../../types/Planet";
|
||||||
|
import { calculateCurrentAvailableResources } from "../../../../lib/utils/resourceManager";
|
||||||
import validateAccessToken from "../../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../../lib/utils/validateAccessToken";
|
||||||
import { getUserByAccessToken } from "../../../../lib/db/users";
|
import { getUserByAccessToken } from "../../../../lib/db/users";
|
||||||
import locationManager from "../../../../lib/classes/managers/LocationManager";
|
|
||||||
|
|
||||||
export const GET: APIRoute = async ({ params, request }) => {
|
export const GET: APIRoute = async ({ params, request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
|
@ -26,23 +28,36 @@ export const GET: APIRoute = async ({ params, request }) => {
|
||||||
}), { status: 400 }
|
}), { status: 400 }
|
||||||
);
|
);
|
||||||
|
|
||||||
const planet = locationManager.getPlanet(new ObjectId(planetId));
|
let planet: Planet | null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
planet = await getPlanetById(new ObjectId(planetId));
|
||||||
if(!planet) return new Response(
|
if(!planet) return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 404,
|
||||||
|
message: "Not Found"
|
||||||
|
}), { status: 404 }
|
||||||
|
);
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 500,
|
code: 500,
|
||||||
message: "Internal Server Error"
|
message: "Internal Server Error"
|
||||||
}), { status: 500 }
|
}), { status: 500 }
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if(!planet.manager.owner.id.equals(user._id)) return new Response(
|
if(planet.owner._id.toString() !== user._id.toString()) return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 403,
|
code: 403,
|
||||||
message: "Forbidden"
|
message: "Forbidden"
|
||||||
}), { status: 403 }
|
}), { status: 403 }
|
||||||
);
|
);
|
||||||
|
|
||||||
await locationManager.getPlanet(planet._id)?.resources.calculateCurrentAvailableResources();
|
await calculateCurrentAvailableResources(planet._id);
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
delete planet.owner.password;
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { type APIRoute } from "astro";
|
import { type APIRoute } from "astro";
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
import { getUserByAccessToken, getUserResearch } from "../../../lib/db/users";
|
import { getUserByAccessToken, getUserResearch } from "../../../lib/db/users";
|
||||||
import locationManager from "../../../lib/classes/managers/LocationManager";
|
|
||||||
|
|
||||||
export const GET: APIRoute = async({ request }) => {
|
export const GET: APIRoute = async({ request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
|
@ -17,13 +16,11 @@ export const GET: APIRoute = async({ request }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const userResearch = locationManager.getUser(user._id)?.research.research ?? [];
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 200,
|
code: 200,
|
||||||
message: "OK",
|
message: "OK",
|
||||||
data: userResearch
|
data: await getUserResearch(user)
|
||||||
}), { status: 200 }
|
}), { status: 200 }
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,16 +1,20 @@
|
||||||
import { type APIRoute } from "astro";
|
import { type APIRoute } from "astro";
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
import { getUserByAccessToken } from "../../../lib/db/users";
|
import { createOrUpgradeResearch, getUserByAccessToken, getUserResearch } from "../../../lib/db/users";
|
||||||
|
import { getPlanetById } from "../../../lib/db/planets";
|
||||||
|
import Planet from "../../../types/Planet";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
import { getResearchById } from "../../../lib/db/research";
|
import { calculateCurrentAvailableResources, getResourcesFromPlanet, updatePlanetResources } from "../../../lib/utils/resourceManager";
|
||||||
import locationManager from "../../../lib/classes/managers/LocationManager";
|
import PlayerResource from "../../../types/PlayerResource";
|
||||||
|
import calculateAvailableResources from "../../../lib/utils/calculateAvailableResources";
|
||||||
|
import { getAllResearch, getResearchById } from "../../../lib/db/research";
|
||||||
|
|
||||||
export const POST: APIRoute = async({ request }) => {
|
export const POST: APIRoute = async({ request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
if(response instanceof Response) return response;
|
if(response instanceof Response) return response;
|
||||||
|
|
||||||
const userDB = await getUserByAccessToken(response);
|
const user = await getUserByAccessToken(response);
|
||||||
if(userDB === null) {
|
if(user === null) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 401,
|
code: 401,
|
||||||
|
@ -32,30 +36,8 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPlanet = locationManager.getPlanet(new ObjectId(body.planetId));
|
|
||||||
if(!userPlanet) {
|
|
||||||
return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
code: 404,
|
|
||||||
message: "Not Found",
|
|
||||||
error: "Planet not found"
|
|
||||||
}), { status: 404 }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = userPlanet.manager.owner;
|
const researchId = body.research;
|
||||||
|
|
||||||
if(!user.id.equals(userDB._id)) {
|
|
||||||
return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
code: 403,
|
|
||||||
message: "Forbidden",
|
|
||||||
error: "You don't own this planet"
|
|
||||||
}), { status: 403 }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const researchId = body.research as string;
|
|
||||||
const research = await getResearchById(researchId);
|
const research = await getResearchById(researchId);
|
||||||
|
|
||||||
if(!research) {
|
if(!research) {
|
||||||
|
@ -67,27 +49,47 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
}), { status: 400 }
|
}), { status: 400 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
let userPlanet: Planet | null;
|
||||||
|
try {
|
||||||
// check requirements
|
userPlanet = await getPlanetById(new ObjectId(body.planetId));
|
||||||
// buildings
|
} catch(e) {
|
||||||
const buildings = userPlanet.buildings;
|
|
||||||
for(const buildingReq of research.requirements.buildings) {
|
|
||||||
if((buildings.buildings.find((building) => building.data.id === buildingReq.id)?.level ?? 0) < buildingReq.level) {
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 400,
|
code: 400,
|
||||||
message: "Bad Request",
|
message: "Bad Request",
|
||||||
error: `${buildingReq.id} level ${buildingReq.level} required, found ${buildings.buildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0}`
|
error: "Invalid planet id"
|
||||||
}), { status: 400 }
|
}), { status: 400 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
if(!userPlanet) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 404,
|
||||||
|
message: "Not Found",
|
||||||
|
error: "Planet not found"
|
||||||
|
}), { status: 404 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check requirements
|
||||||
|
// buildings
|
||||||
|
const buildings = userPlanet.buildings;
|
||||||
|
research.requirements.buildings.forEach((buildingReq) => {
|
||||||
|
if(buildings.filter((building) => building.id === buildingReq.id)[0]?.level ?? 0 < buildingReq.level) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: `${buildingReq.id} level ${buildingReq.level} required, found ${buildings.filter((building) => building.id === buildingReq.id)[0]?.level ?? 0}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// research
|
// research
|
||||||
const playerResearch = user.research.research;
|
const playerResearch = await getUserResearch(user);
|
||||||
for(const researchReq of research.requirements.research) {
|
research.requirements.research.forEach((researchReq) => {
|
||||||
if((playerResearch.find((research) => research.id === researchReq.id)?.level ?? 0) < researchReq.level) {
|
if(playerResearch.filter((research) => research.id === researchReq.id)[0].level < researchReq.level) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 400,
|
code: 400,
|
||||||
|
@ -96,10 +98,10 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
}), { status: 400 }
|
}), { status: 400 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
const resources = await userPlanet.resources.calculateCurrentAvailableResources();
|
const resources = await calculateCurrentAvailableResources(userPlanet._id);
|
||||||
if(!resources) {
|
if(!resources) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
@ -109,25 +111,24 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
}), { status: 500 }
|
}), { status: 500 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const playerCurrentResearch = playerResearch.filter((element: any) => element.id === researchId)[0];
|
const playerCurrentResearch = playerResearch.filter((element: any) => element.id === researchId)[0];
|
||||||
const level = playerCurrentResearch ? playerCurrentResearch.level : 0;
|
const level = playerCurrentResearch ? playerCurrentResearch.level : 0;
|
||||||
const newResources = structuredClone(resources);
|
const newResources = structuredClone(resources);
|
||||||
const missingResources: Array<{ id: string, required: number, available: number }> = [];
|
const missingResources: Array<{}> = [];
|
||||||
for(const resource of research.requirements.resources) {
|
research.requirements.resources.forEach(resource => {
|
||||||
const res = resources.filter((element) => element.id === resource.id)[0];
|
const res = resources.filter((element: PlayerResource) => element.name === resource.name)[0];
|
||||||
const cost = playerCurrentResearch ? resource.amount * Math.pow(research.multiplier, level) : resource.amount;
|
const cost = playerCurrentResearch ? resource.amount * Math.pow(research.multiplier, level) : resource.amount;
|
||||||
|
|
||||||
if(res.amount < cost) {
|
if(res.amount < cost) {
|
||||||
missingResources.push({
|
missingResources.push({
|
||||||
id: resource.id,
|
name: resource.name,
|
||||||
required: cost,
|
required: cost,
|
||||||
available: res.amount
|
available: res.amount
|
||||||
});
|
});
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
else newResources.filter((element) => element.id === resource.id)[0].amount -= cost;
|
else newResources.filter((element: PlayerResource) => element.name === resource.name)[0].amount -= cost;
|
||||||
};
|
});
|
||||||
|
|
||||||
if(missingResources.length > 0) {
|
if(missingResources.length > 0) {
|
||||||
return new Response(
|
return new Response(
|
||||||
|
@ -139,15 +140,8 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
userPlanet.resources.update(newResources);
|
await updatePlanetResources(userPlanet._id, newResources);
|
||||||
userPlanet.manager.owner.research.addResearch({
|
await createOrUpgradeResearch(user._id, { id: researchId, level: level + 1 });
|
||||||
id: researchId,
|
|
||||||
level: level + 1,
|
|
||||||
data: research
|
|
||||||
});
|
|
||||||
|
|
||||||
await userPlanet.resources.sync();
|
|
||||||
await userPlanet.manager.owner.research.sync();
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
|
@ -6,9 +6,7 @@ import { getUserByAccessToken } from '../../lib/db/users';
|
||||||
import { getHighestWeightedLanguage, getLocales, getName, getObj } from '../../lib/utils/langDriver';
|
import { getHighestWeightedLanguage, getLocales, getName, getObj } from '../../lib/utils/langDriver';
|
||||||
import ResourceBar from '../../components/ResourceBar.astro';
|
import ResourceBar from '../../components/ResourceBar.astro';
|
||||||
import { getAllBuildings } from '../../lib/db/buildings';
|
import { getAllBuildings } from '../../lib/db/buildings';
|
||||||
import locationManager from '../../lib/classes/managers/LocationManager';
|
import DBBuilding from '../../types/DBBuilding';
|
||||||
import { ObjectId } from 'mongodb';
|
|
||||||
import DBBuilding from '../../types/db/DBBuilding';
|
|
||||||
|
|
||||||
const buildingsList = await getAllBuildings();
|
const buildingsList = await getAllBuildings();
|
||||||
|
|
||||||
|
@ -23,31 +21,20 @@ const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accep
|
||||||
|
|
||||||
const lang = await getLocales(locale);
|
const lang = await getLocales(locale);
|
||||||
|
|
||||||
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 modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any>, energy: number } } = {};
|
const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any>, energy: number } } = {};
|
||||||
|
|
||||||
for(const building of buildingsList) {
|
for(const building of buildingsList) {
|
||||||
modalSet[building.id] = {
|
modalSet[building.id] = {
|
||||||
resources: building.requirements.resources.map(resource => {
|
resources: building.requirements.resources,
|
||||||
return {
|
|
||||||
id: resource.id,
|
|
||||||
amount: Math.pow(building.multiplier, (planet.buildings.getBuildingById(building.id)?.level ?? 0) ) * resource.amount
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
research: building.requirements.research,
|
research: building.requirements.research,
|
||||||
buildings: building.requirements.buildings,
|
buildings: building.requirements.buildings,
|
||||||
energy: building.energy
|
energy: building.energy
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: Array<DBBuilding & { level: number }> }, building) => {
|
const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: DBBuilding[] }, building) => {
|
||||||
if(!acc[building.category]) acc[building.category] = [];
|
if(!acc[building.category]) acc[building.category] = [];
|
||||||
acc[building.category].push({ ...building, level: planet.buildings.getBuildingById(building.id)?.level ?? 0 });
|
acc[building.category].push(building);
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
---
|
---
|
||||||
|
@ -73,7 +60,6 @@ const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: Array<DB
|
||||||
{buildings.map(building => (
|
{buildings.map(building => (
|
||||||
<BuildingCard
|
<BuildingCard
|
||||||
id={building.id}
|
id={building.id}
|
||||||
level={building.level.toString()}
|
|
||||||
name={getObj(lang, "buildings", building.id).name}
|
name={getObj(lang, "buildings", building.id).name}
|
||||||
description={getObj(lang, "buildings", building.id).description ?? ""}
|
description={getObj(lang, "buildings", building.id).description ?? ""}
|
||||||
image={`/images/buildings/${building.id}.jpeg`}
|
image={`/images/buildings/${building.id}.jpeg`}
|
||||||
|
@ -199,7 +185,7 @@ const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: Array<DB
|
||||||
color: lime;
|
color: lime;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script define:vars={{ modalSet, lang, planetId }}>
|
<script define:vars={{ modalSet, lang }}>
|
||||||
const modalResources = document.getElementById("building-modal-req-resources");
|
const modalResources = document.getElementById("building-modal-req-resources");
|
||||||
const modalBuildings = document.getElementById("building-modal-req-buildings");
|
const modalBuildings = document.getElementById("building-modal-req-buildings");
|
||||||
const modalResearch = document.getElementById("building-modal-req-research");
|
const modalResearch = document.getElementById("building-modal-req-research");
|
||||||
|
@ -216,7 +202,7 @@ const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: Array<DB
|
||||||
const reqResearch = modalSet[el.parentElement.parentElement.dataset.id]?.research ?? [];
|
const reqResearch = modalSet[el.parentElement.parentElement.dataset.id]?.research ?? [];
|
||||||
|
|
||||||
modalResources.innerHTML = reqResources.length === 0 ? "None" : reqResources.map(resource => {
|
modalResources.innerHTML = reqResources.length === 0 ? "None" : reqResources.map(resource => {
|
||||||
return `${lang['resources'].find(r => r.id === resource.id).name}: ${resource.amount}`;
|
return `${lang['resources'].find(r => r.id === resource.name).name}: ${resource.amount}`;
|
||||||
}).join("<br />");
|
}).join("<br />");
|
||||||
|
|
||||||
modalBuildings.innerHTML = reqBuildings.length === 0 ? "None" : reqBuildings.map(building => {
|
modalBuildings.innerHTML = reqBuildings.length === 0 ? "None" : reqBuildings.map(building => {
|
||||||
|
@ -247,28 +233,21 @@ const buildingsByCategory = buildingsList.reduce((acc: { [key: string]: Array<DB
|
||||||
backgroundDiv.style.display = 'none';
|
backgroundDiv.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
const allButtons = document.getElementsByClassName("item-card-build");
|
const allButtons = document.getElementsByClassName("a-button");
|
||||||
|
|
||||||
for(const buildingButton of allButtons) {
|
for(const buildingButton of allButtons) {
|
||||||
buildingButton.addEventListener("click", async () => {
|
buildingButton.addEventListener("click", async () => {
|
||||||
const id = buildingButton.id.split("_")[1];
|
const id = buildingButton.id.split("_")[1];
|
||||||
|
|
||||||
const response = await fetch('/api/build/createBuilding', {
|
await fetch('/api/build/createBuilding', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
building: id,
|
building: id
|
||||||
planet: planetId
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if(response.status === 200) {
|
|
||||||
window.location.reload();
|
|
||||||
} else {
|
|
||||||
alert("Failed to build building: " + JSON.stringify(await response.json()));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -5,6 +5,7 @@ import { getUserByAccessToken } from '../../lib/db/users';
|
||||||
import { getHighestWeightedLanguage, getLocales, getName, getObj } from '../../lib/utils/langDriver';
|
import { getHighestWeightedLanguage, getLocales, getName, getObj } from '../../lib/utils/langDriver';
|
||||||
import ResourceBar from '../../components/ResourceBar.astro';
|
import ResourceBar from '../../components/ResourceBar.astro';
|
||||||
import ItemCard from '../../components/ItemCard.astro';
|
import ItemCard from '../../components/ItemCard.astro';
|
||||||
|
import DBResearch from '../../types/DBResearch';
|
||||||
import { getAllResearch } from '../../lib/db/research';
|
import { getAllResearch } from '../../lib/db/research';
|
||||||
|
|
||||||
const researchList = await getAllResearch();
|
const researchList = await getAllResearch();
|
||||||
|
@ -16,13 +17,23 @@ if(loggedToken === null || username === "") return Astro.redirect('/logout');
|
||||||
const checkUser = await getUserByAccessToken(loggedToken);
|
const checkUser = await getUserByAccessToken(loggedToken);
|
||||||
if(checkUser === null || checkUser.username !== username) return Astro.redirect('/logout');
|
if(checkUser === null || checkUser.username !== username) return Astro.redirect('/logout');
|
||||||
|
|
||||||
const planetId = Astro.cookies.get('planetid')?.value ?? "";
|
|
||||||
if(planetId === "") return Astro.redirect('/logout');
|
|
||||||
|
|
||||||
const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language'));
|
const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language'));
|
||||||
|
|
||||||
const lang = await getLocales(locale);
|
const lang = await getLocales(locale);
|
||||||
|
|
||||||
|
// type DBResearchDetails = DBResearch & { level: number };
|
||||||
|
// const researchDetails: DBResearchDetails[] = [];
|
||||||
|
// researchList.forEach(element => {
|
||||||
|
// const userLevel = checkUser.research.find(x => x.id === element.id)?.level ?? 0;
|
||||||
|
// const tempResDetails: DBResearchDetails = {
|
||||||
|
// level: userLevel,
|
||||||
|
// ...element
|
||||||
|
// }
|
||||||
|
|
||||||
|
// researchDetails.push(tempResDetails);
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any> } } = {};
|
const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any> } } = {};
|
||||||
|
|
||||||
for(const research of researchList) {
|
for(const research of researchList) {
|
||||||
|
@ -55,7 +66,6 @@ for(const research of researchList) {
|
||||||
<ItemCard
|
<ItemCard
|
||||||
id={research.id}
|
id={research.id}
|
||||||
name={getObj(lang, "research", research.id).name}
|
name={getObj(lang, "research", research.id).name}
|
||||||
level={checkUser.research.find(x => x.id === research.id)?.level.toString() ?? "0"}
|
|
||||||
description={getObj(lang, "research", research.id).description ?? ""}
|
description={getObj(lang, "research", research.id).description ?? ""}
|
||||||
image={`/images/research/${research.id}.jpeg`}
|
image={`/images/research/${research.id}.jpeg`}
|
||||||
button_type="general"
|
button_type="general"
|
||||||
|
@ -177,7 +187,7 @@ for(const research of researchList) {
|
||||||
z-index: 101;
|
z-index: 101;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script define:vars={{ modalSet, lang, planetId }}>
|
<script define:vars={{ modalSet, lang }}>
|
||||||
const modalResources = document.getElementById("research-modal-req-resources");
|
const modalResources = document.getElementById("research-modal-req-resources");
|
||||||
const modalBuildings = document.getElementById("research-modal-req-buildings");
|
const modalBuildings = document.getElementById("research-modal-req-buildings");
|
||||||
const modalResearch = document.getElementById("research-modal-req-research");
|
const modalResearch = document.getElementById("research-modal-req-research");
|
||||||
|
@ -227,28 +237,23 @@ for(const research of researchList) {
|
||||||
backgroundDiv.style.display = 'none';
|
backgroundDiv.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
const allButtons = document.getElementsByClassName("item-card-build");
|
const allButtons = document.getElementsByClassName("a-button");
|
||||||
|
|
||||||
for(const researchButton of allButtons) {
|
for(const researchButton of allButtons) {
|
||||||
researchButton.addEventListener("click", async () => {
|
researchButton.addEventListener("click", async () => {
|
||||||
const id = researchButton.id.split("_")[1];
|
const id = researchButton.id.split("_")[1];
|
||||||
|
|
||||||
const response = await fetch('/api/research/performResearch', {
|
console.log(id);
|
||||||
|
|
||||||
|
await fetch('/api/research/performResearch', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
research: id,
|
research: id
|
||||||
planetId
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if(response.status === 200) {
|
|
||||||
window.location.reload();
|
|
||||||
} else {
|
|
||||||
alert("Failed to build building: " + JSON.stringify(await response.json()));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -2,12 +2,11 @@
|
||||||
import Layout from '../layouts/Layout.astro';
|
import Layout from '../layouts/Layout.astro';
|
||||||
import NavBar from '../components/NavBar.astro';
|
import NavBar from '../components/NavBar.astro';
|
||||||
|
|
||||||
import { getUserByNickOrEmail, updateLastLogin } from '../lib/db/users';
|
import { getUserByNickOrEmail, getUserWithPlanets, updateLastLogin } from '../lib/db/users';
|
||||||
|
|
||||||
import config from '../../config.json';
|
import config from '../../config.json';
|
||||||
|
|
||||||
import { verify } from 'argon2';
|
import { verify } from 'argon2';
|
||||||
import locationManager from '../lib/classes/managers/LocationManager';
|
|
||||||
|
|
||||||
let error = "";
|
let error = "";
|
||||||
|
|
||||||
|
@ -26,11 +25,9 @@ if(Astro.request.method === "POST") {
|
||||||
Astro.redirect("/login");
|
Astro.redirect("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
const userDB = await getUserByNickOrEmail(username as string);
|
const user = await getUserByNickOrEmail(username as string);
|
||||||
|
|
||||||
if(userDB !== null && await verify(userDB.password, password as string)) {
|
if(user !== null && await verify(user.password, password as string)) {
|
||||||
const user = locationManager.getUser(userDB._id);
|
|
||||||
if(!user) throw new Error("User not found");
|
|
||||||
const sessionTime = config.SESSION_TIME_MINUTES * 60;
|
const sessionTime = config.SESSION_TIME_MINUTES * 60;
|
||||||
|
|
||||||
const res = await fetch(`http://localhost:4321/api/auth/generateAccessToken`, {
|
const res = await fetch(`http://localhost:4321/api/auth/generateAccessToken`, {
|
||||||
|
@ -64,14 +61,18 @@ if(Astro.request.method === "POST") {
|
||||||
secure: true
|
secure: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Astro.cookies.set("userid", user.id?.toString() as string, {
|
Astro.cookies.set("userid", user._id?.toString() as string, {
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: sessionTime,
|
maxAge: sessionTime,
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
secure: true
|
secure: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Astro.cookies.set("planetid", user.mainPlanet._id, {
|
const userWithPlanets = await getUserWithPlanets(user._id);
|
||||||
|
if(!userWithPlanets) return;
|
||||||
|
const planetId = userWithPlanets.planets.data[0]._id;
|
||||||
|
|
||||||
|
Astro.cookies.set("planetid", planetId.toString(), {
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: sessionTime,
|
maxAge: sessionTime,
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import User from "../lib/classes/User";
|
import type { ObjectId } from "mongodb";
|
||||||
|
|
||||||
export default interface AccessToken {
|
export default interface AccessToken {
|
||||||
type: string;
|
_id?: ObjectId;
|
||||||
user: User | null;
|
type: "A" | "X";
|
||||||
|
user: ObjectId | null;
|
||||||
entropy: string;
|
entropy: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
expiresAt: Date | null;
|
expiresAt: Date | null;
|
||||||
createdFrom: string | null;
|
createdFrom: null | 'loginForm';
|
||||||
}
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default interface Building {
|
||||||
|
id: string;
|
||||||
|
level: number;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default interface DBBuilding {
|
||||||
|
id: string,
|
||||||
|
category: string,
|
||||||
|
requirements: {
|
||||||
|
buildings: Array<{ id: string, level: number }>,
|
||||||
|
research: Array<{ id: string, level: number }>,
|
||||||
|
resources: Array<{ name: string, amount: number }>,
|
||||||
|
},
|
||||||
|
energy: number,
|
||||||
|
multiplier: number,
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
export default interface DBResearch {
|
||||||
|
id: string,
|
||||||
|
requirements: {
|
||||||
|
buildings: Array<{ id: string, level: number }>,
|
||||||
|
research: Array<{ id: string, level: number }>,
|
||||||
|
resources: Array<{ name: string, amount: number }>,
|
||||||
|
},
|
||||||
|
time: number,
|
||||||
|
multiplier: number,
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default interface DBResource {
|
||||||
|
id: string,
|
||||||
|
type: string,
|
||||||
|
icon: string
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
export default interface DBShip {
|
||||||
|
id: string,
|
||||||
|
capacity: {
|
||||||
|
solid: number,
|
||||||
|
liquid: number,
|
||||||
|
gas: number,
|
||||||
|
},
|
||||||
|
requirements: {
|
||||||
|
buildings: Array<{ id: string, level: number }>,
|
||||||
|
research: Array<{ id: string, level: number }>,
|
||||||
|
resources: Array<{ name: string, amount: number }>,
|
||||||
|
},
|
||||||
|
time: number,
|
||||||
|
structure: {
|
||||||
|
hitpoints: number,
|
||||||
|
defense: number,
|
||||||
|
attack: number,
|
||||||
|
},
|
||||||
|
speed: number,
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import type { ObjectId } from "mongodb";
|
||||||
|
import type PlayerResource from "./PlayerResource";
|
||||||
|
import type Building from "./Building";
|
||||||
|
import type Ship from "./Ship";
|
||||||
|
import type User from "./User";
|
||||||
|
|
||||||
|
export default interface Planet {
|
||||||
|
_id: ObjectId,
|
||||||
|
owner: User,
|
||||||
|
name: string,
|
||||||
|
fields: number,
|
||||||
|
resources: Array<PlayerResource>,
|
||||||
|
buildings: Array<Building>,
|
||||||
|
ships: Array<Ship>,
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import type Resource from "./Resource";
|
||||||
|
|
||||||
|
export default interface DBResource extends Resource {
|
||||||
|
lastUpdated: Date;
|
||||||
|
perHourMiningRate: number;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default interface Research {
|
||||||
|
id: string;
|
||||||
|
level: number;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default interface Resource {
|
||||||
|
name: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
export default interface Resources {
|
||||||
|
coal: number;
|
||||||
|
iron: number;
|
||||||
|
gold: number;
|
||||||
|
|
||||||
|
water: number;
|
||||||
|
sulfuricAcid: number;
|
||||||
|
liquidNitrogen: number;
|
||||||
|
|
||||||
|
hydrogen: number;
|
||||||
|
oxygen: number;
|
||||||
|
helium3: number;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default interface Ship {
|
||||||
|
id: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import type { ObjectId } from "mongodb";
|
||||||
|
import type Research from "./Research";
|
||||||
|
import type Planet from "./Planet";
|
||||||
|
|
||||||
|
export default interface User {
|
||||||
|
_id: ObjectId;
|
||||||
|
username: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
lastLogin: Date;
|
||||||
|
research: Array<Research>;
|
||||||
|
planets: {
|
||||||
|
partial: boolean;
|
||||||
|
data: Array<Planet>;
|
||||||
|
};
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBAccessToken {
|
|
||||||
_id: ObjectId;
|
|
||||||
type: string;
|
|
||||||
user: ObjectId;
|
|
||||||
entropy: string;
|
|
||||||
createdAt: Date;
|
|
||||||
expiresAt: Date;
|
|
||||||
createdFrom: string | null;
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBBuilding {
|
|
||||||
_id: ObjectId;
|
|
||||||
id: string;
|
|
||||||
category: string;
|
|
||||||
requirements: {
|
|
||||||
buildings: Array<{ id: string, level: number }>,
|
|
||||||
research: Array<{ id: string, level: number }>,
|
|
||||||
resources: Array<{ id: string, amount: number }>,
|
|
||||||
};
|
|
||||||
energy: number;
|
|
||||||
time: number;
|
|
||||||
multiplier: number;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBFleet {
|
|
||||||
_id: ObjectId;
|
|
||||||
source: ObjectId;
|
|
||||||
destination: ObjectId;
|
|
||||||
finished: boolean;
|
|
||||||
returning: boolean;
|
|
||||||
mission: string;
|
|
||||||
ships: Array<{ id: string, amount: number }>;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBGalaxy {
|
|
||||||
_id: ObjectId;
|
|
||||||
name: string;
|
|
||||||
sectors: Array<ObjectId>;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBPlanet {
|
|
||||||
_id: ObjectId;
|
|
||||||
name: string;
|
|
||||||
fields: number;
|
|
||||||
resources: Array<{ id: string, amount: number, lastUpdated: Date, perHourMiningRate: number }>;
|
|
||||||
buildings: Array<{ id: string, level: number }>;
|
|
||||||
ships: Array<{ id: string, amount: number }>;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBResearch {
|
|
||||||
_id: ObjectId;
|
|
||||||
id: string;
|
|
||||||
requirements: {
|
|
||||||
buildings: Array<{ id: string, level: number }>,
|
|
||||||
research: Array<{ id: string, level: number }>,
|
|
||||||
resources: Array<{ id: string, amount: number }>,
|
|
||||||
};
|
|
||||||
time: number;
|
|
||||||
multiplier: number;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBResource {
|
|
||||||
_id: ObjectId;
|
|
||||||
id: string;
|
|
||||||
type: string;
|
|
||||||
icon: string;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBSector {
|
|
||||||
_id: ObjectId;
|
|
||||||
name: string;
|
|
||||||
expedition: any; // TODO: Define expedition type
|
|
||||||
systems: Array<ObjectId>;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBShip {
|
|
||||||
_id: ObjectId;
|
|
||||||
id: string;
|
|
||||||
capacity: {
|
|
||||||
solid: number;
|
|
||||||
liquid: number;
|
|
||||||
gas: number;
|
|
||||||
};
|
|
||||||
requirements: {
|
|
||||||
buildings: Array<{ id: string, level: number }>,
|
|
||||||
research: Array<{ id: string, level: number }>,
|
|
||||||
resources: Array<{ id: string, amount: number }>,
|
|
||||||
};
|
|
||||||
time: number;
|
|
||||||
structure: {
|
|
||||||
hitpoints: number;
|
|
||||||
defense: number;
|
|
||||||
attack: number;
|
|
||||||
};
|
|
||||||
speed: number;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBSystem {
|
|
||||||
_id: ObjectId;
|
|
||||||
name: string;
|
|
||||||
ownedBy: ObjectId;
|
|
||||||
planets: Array<ObjectId>;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
export default interface DBUser {
|
|
||||||
_id: ObjectId;
|
|
||||||
username: string;
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
lastLogin: Date;
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
research: Array<{ id: string, level: number }>;
|
|
||||||
mainPlanet: ObjectId;
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { createUser, deleteUser, getUserByNickOrEmail } from '../src/lib/db/users';
|
||||||
|
import { connect, disconnect } from '../src/lib/db/mongodb';
|
||||||
|
import { verify } from 'argon2';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test user database functions', () => {
|
||||||
|
test('getUserByNickOrEmail', async () => {
|
||||||
|
const user = await getUserByNickOrEmail("gargamel");
|
||||||
|
expect(user).not.toBeNull();
|
||||||
|
expect(user?.username).toBe("gargamel");
|
||||||
|
expect(user?.email).toBe("gargamel@smerfy.pl");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createAndVerifyUser', async () => {
|
||||||
|
await createUser("test", "test@example.com", "password");
|
||||||
|
const user = await getUserByNickOrEmail("test");
|
||||||
|
expect(user).not.toBeNull();
|
||||||
|
if(!user) return;
|
||||||
|
expect(user?.username).toBe("test");
|
||||||
|
expect(user?.email).toBe("test@example.com");
|
||||||
|
expect(await verify(user?.password as string, "password")).toBe(true);
|
||||||
|
await deleteUser(user._id);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,85 @@
|
||||||
|
import { connect, disconnect } from "../src/lib/db/mongodb";
|
||||||
|
import { createUser, deleteUser } from "../src/lib/db/users";
|
||||||
|
import { calculateCurrentAvailableResources, getUserResources, updateUserResources } from "../src/lib/utils/resourceManager";
|
||||||
|
import User from "../src/types/User";
|
||||||
|
|
||||||
|
let user: User;
|
||||||
|
|
||||||
|
describe('Test resource manager', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await connect();
|
||||||
|
user = await createUser("test", "test@example.com", "password");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await deleteUser(user._id);
|
||||||
|
await disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test initial resources amount', () => {
|
||||||
|
test('initialResourcesAmount', async () => {
|
||||||
|
const resources = await getUserResources(user._id);
|
||||||
|
let i = 1;
|
||||||
|
resources.forEach(res => {
|
||||||
|
expect(res.amount).toBe(i * 11);
|
||||||
|
expect(res.perHourMiningRate).toBe(i * 11);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test calculation of available resources', () => {
|
||||||
|
test('calculationOfAvailableResources', async () => {
|
||||||
|
const resources = await getUserResources(user._id);
|
||||||
|
|
||||||
|
resources.forEach(res => {
|
||||||
|
res.amount = 0;
|
||||||
|
res.lastUpdated = new Date(Date.now() - 1000 * 60 * 60);
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateUserResources(user._id, resources);
|
||||||
|
const availableResources = await calculateCurrentAvailableResources(user._id);
|
||||||
|
let i = 1;
|
||||||
|
availableResources.forEach(res => {
|
||||||
|
expect(res.amount).toBeCloseTo(i * 11);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
|
||||||
|
const resourcesAfter = await getUserResources(user._id);
|
||||||
|
i = 1;
|
||||||
|
resourcesAfter.forEach(res => {
|
||||||
|
expect(res.amount).toBeCloseTo(i * 11);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test taking resources', () => {
|
||||||
|
test('takingResources', async () => {
|
||||||
|
const resources = await getUserResources(user._id);
|
||||||
|
resources.forEach(res => {
|
||||||
|
res.amount = 10_000;
|
||||||
|
});
|
||||||
|
|
||||||
|
let i = 1;
|
||||||
|
|
||||||
|
resources.forEach(res => {
|
||||||
|
res.amount -= i * 100;
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateUserResources(user._id, resources);
|
||||||
|
|
||||||
|
const resourcesAfter = await getUserResources(user._id);
|
||||||
|
i = 1;
|
||||||
|
resourcesAfter.forEach(res => {
|
||||||
|
expect(res.amount).toBeCloseTo(10_000 - i * 100);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue