Skip to content

Commit

Permalink
feat(Star Map): Add backend and API for adding, updating, and deletin…
Browse files Browse the repository at this point in the history
…g stars from solar systems. Closes #174
  • Loading branch information
alexanderson1993 committed Feb 4, 2022
1 parent 17e810a commit 10c71a3
Show file tree
Hide file tree
Showing 12 changed files with 597 additions and 12 deletions.
4 changes: 4 additions & 0 deletions server/src/classes/Plugins/Universe/SolarSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {randomFromList} from "server/src/utils/randomFromList";
import {AstronomicalUnit, LightMinute} from "server/src/utils/unitTypes";
import BasePlugin from "..";
import {Aspect} from "../Aspect";
import StarPlugin from "./Star";

export default class SolarSystemPlugin extends Aspect {
apiVersion = "solarSystem/v1" as const;
Expand Down Expand Up @@ -35,6 +36,7 @@ export default class SolarSystemPlugin extends Aspect {
* A string key that is used to procedurally generate the nebula skybox background in this system in the viewscreen.
*/
skyboxKey: string;
stars: StarPlugin[] = [];
assets = {};

constructor(params: Partial<SolarSystemPlugin>, plugin: BasePlugin) {
Expand Down Expand Up @@ -67,5 +69,7 @@ export default class SolarSystemPlugin extends Aspect {
this.habitableZoneInner = params.habitableZoneInner || 0.9;
this.habitableZoneOuter = params.habitableZoneOuter || 3.0;
this.skyboxKey = params.skyboxKey || "Random Key";

this.stars = params.stars?.map(star => new StarPlugin(star, this)) ?? [];
}
}
90 changes: 90 additions & 0 deletions server/src/classes/Plugins/Universe/Star.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {SatelliteComponent} from "server/src/components/satellite";
import {SpectralTypes, starTypes} from "server/src/spawners/starTypes";
import {
Degree,
Kelvin,
SolarMass,
SolarRadius,
Year,
} from "server/src/utils/unitTypes";
import type SolarSystemPlugin from "./SolarSystem";

const ALPHABET = "ABC";

export default class StarPlugin {
name: string;
description: string;

tags: string[];

/**
* The mass of the star in comparison to the Sun
*/
solarMass: SolarMass;

/**
* The age of the star in years
*/
age: Year;

/**
* The spectral type of the star, one of O,B,G,K,A,MG,M,D
*/
spectralType: SpectralTypes;

/**
* The color hue of the star, based on the spectral type
*/
hue: Degree;

/**
* Whether the star appears to be white
*/
isWhite: boolean;

/**
* The radius of the star compared to the radius of the Sun
*/
radius: SolarRadius;

/**
* Temperature in Kelvin (K)
*/
temperature: Kelvin;

satellite: Omit<SatelliteComponent, "init">;

constructor(
params: Partial<
Omit<StarPlugin, "satellite"> & {
satellite: Partial<Omit<SatelliteComponent, "init">>;
}
>,
solarSystem: SolarSystemPlugin
) {
this.name =
params.name ||
`${solarSystem.name} ${ALPHABET[solarSystem.stars.length]}`;
this.description = params.description || "";
this.tags = params.tags || [];

this.solarMass = params.solarMass || 1;
this.age = params.age || 4000000000;
this.spectralType = params.spectralType || "G";
this.hue = params.hue || 0;
this.isWhite = params.isWhite || false;
this.radius = params.radius || 1;

this.temperature = params.temperature || 5800;

this.satellite = {
axialTilt: params.satellite?.axialTilt || 0,
eccentricity: params.satellite?.eccentricity || 0,
inclination: params.satellite?.inclination || 0,
semiMajorAxis: params.satellite?.semiMajorAxis || 0,
orbitalArc: params.satellite?.orbitalArc || 0,
showOrbit: false,
parentId: solarSystem.name,
};
}
}
43 changes: 43 additions & 0 deletions server/src/components/satellite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {Degree, Kilometer} from "../utils/unitTypes";
import {Component} from "./utils";

export class SatelliteComponent extends Component {
static id = "satellite" as const;
/**
* The tilt of the axis of rotation in degrees
*/
axialTilt: Degree = 23.5;

/**
* Orbital mechanics based on Keplerian Elements https://en.wikipedia.org/wiki/Orbital_elements#Keplerian_elements
* Check this page if you need a visualization https://ciechanow.ski/gps/
* To simplify it, this doesn't include the Longitude of Ascending Node or the Argument of Periapsis, and
* True Anomaly is renamed to Orbital Arc to be a little easier to understand.
* Defaults based on Earth
*/
/**
* Distance from the center of the orbit to the furthest point
*/
semiMajorAxis: Kilometer = 149600000;
/**
* The shape of the orbit elliptical compared to a circle. 0 is a circular orbit.
*/
eccentricity: number = 0.01671022;
/**
* Vertical tilt of the orbit in degrees
*/
inclination: Degree = 0;
/**
* Angle where the object currently is in its orbit
*/
orbitalArc: Degree = 0;
/**
* Whether the orbit should be shown on the star map
*/
showOrbit: boolean = true;

/**
* The ID of the parent object
*/
parentId?: string | null = null;
}
122 changes: 122 additions & 0 deletions server/src/inputs/__test__/solarSystemStarsPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {starPluginInputs} from "../plugins/universe/stars";
function createMockDataContext() {
const context = {
flight: null,
server: {
plugins: [
{
id: "Test Plugin",
name: "Test Plugin",
active: true,
aspects: {
ships: [
{
name: "Test Template",
},
],
solarSystems: [
{
name: "Test System",
stars: [],
},
],
},
},
],
},
} as any;

return context;
}

describe("solar system star plugin input", () => {
it("should create a new star in the solar system", async () => {
const mockDataContext = createMockDataContext();

const system = mockDataContext.server.plugins[0].aspects.solarSystems[0];
const star = starPluginInputs.pluginStarCreate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
spectralType: "G",
});

expect(system.stars.length).toBe(1);
expect(system.stars[0].spectralType).toBe("G");

expect(star.name).toBe("Test System A");
expect(star.spectralType).toBe("G");
});
it("should adjust the orbital positions when there are two stars in the system", async () => {
const mockDataContext = createMockDataContext();

const system = mockDataContext.server.plugins[0].aspects.solarSystems[0];
const star = starPluginInputs.pluginStarCreate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
spectralType: "G",
});

const {orbitalArc, semiMajorAxis} = star.satellite;
const star2 = starPluginInputs.pluginStarCreate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
spectralType: "O",
});

expect(system.stars.length).toBe(2);
expect(orbitalArc).toBe(star.satellite.orbitalArc);
expect(Math.round(star2.satellite.orbitalArc - orbitalArc)).toBe(180);

expect(star.satellite.semiMajorAxis).toEqual(star2.satellite.semiMajorAxis);
expect(star.satellite.semiMajorAxis).toBeGreaterThan(0);
});
it("should delete a system that has been created", () => {
const mockDataContext = createMockDataContext();

const system = mockDataContext.server.plugins[0].aspects.solarSystems[0];
const star = starPluginInputs.pluginStarCreate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
spectralType: "G",
});

expect(system.stars.length).toBe(1);

starPluginInputs.pluginStarDelete(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
starId: star.name,
});

expect(system.stars.length).toBe(0);
});
it("should update properties of a star", () => {
const mockDataContext = createMockDataContext();

const system = mockDataContext.server.plugins[0].aspects.solarSystems[0];
const star = starPluginInputs.pluginStarCreate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
spectralType: "G",
});

expect(system.stars.length).toBe(1);
expect(star.spectralType).toBe("G");

starPluginInputs.pluginStarUpdate(mockDataContext, {
pluginId: "Test Plugin",
solarSystemId: system.name,
starId: star.name,
temperature: 100,
age: 50,
name: "Test Star",
solarMass: 20,
});

expect(system.stars.length).toBe(1);
expect(star.temperature).toBe(100);
expect(star.age).toBe(50);
expect(star.name).toBe("Test Star");
expect(star.solarMass).toBe(20);
});
});
2 changes: 1 addition & 1 deletion server/src/inputs/__test__/solarSystemsPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {solarSystemsPluginInputs} from "../plugins/solarSystems";
import {solarSystemsPluginInputs} from "../plugins/universe/solarSystems";
import {promises as fs} from "fs";
function createMockDataContext() {
return {
Expand Down
2 changes: 1 addition & 1 deletion server/src/inputs/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ export {pluginInputs} from "./plugins";
export {shipsPluginInputs} from "./plugins/ships";
export {themesPluginInput} from "./plugins/themes";
export {officerLogInputs} from "./officersLog";
export {solarSystemsPluginInputs} from "./plugins/solarSystems";
export {solarSystemsPluginInputs} from "./plugins/universe/solarSystems";
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SolarSystemPlugin from "server/src/classes/Plugins/Universe/SolarSystem";
import {DataContext} from "server/src/utils/DataContext";
import {pubsub} from "server/src/utils/pubsub";
import {AstronomicalUnit, LightMinute} from "server/src/utils/unitTypes";
import {getPlugin} from "./utils";
import {getPlugin} from "../utils";

export const solarSystemsPluginInputs = {
pluginSolarSystemCreate(
Expand Down
Loading

0 comments on commit 10c71a3

Please sign in to comment.