Skip to content

Commit

Permalink
A bit more Power Distribution work.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderson1993 committed Aug 15, 2024
1 parent ca79514 commit 4c33ce9
Show file tree
Hide file tree
Showing 14 changed files with 413 additions and 362 deletions.
40 changes: 29 additions & 11 deletions client/app/cards/SystemsMonitor/data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { pubsub } from "@server/init/pubsub";
import { t } from "@server/init/t";
import { getPowerSupplierPowerNeeded } from "@server/systems/ReactorFuelSystem";
import type { Entity } from "@server/utils/ecs";
import { getShipSystems } from "@server/utils/getShipSystem";
import { getReactorInventory } from "@server/utils/getSystemInventory";
Expand Down Expand Up @@ -32,7 +33,7 @@ export const systemsMonitor = t.router({
return {
id: r.id,
name: r.components.identity!.name,
desiredOutput: r.components.isReactor!.outputAssignment.length,
desiredOutput: getPowerSupplierPowerNeeded(r),
maxOutput: r.components.isReactor!.maxOutput,
optimalOutputPercent: r.components.isReactor!.optimalOutputPercent,
nominalHeat: r.components.heat!.nominalHeat,
Expand Down Expand Up @@ -61,6 +62,7 @@ export const systemsMonitor = t.router({
chargeRate: b.components.isBattery!.chargeRate,
outputAmount: b.components.isBattery!.outputAmount,
outputRate: b.components.isBattery!.outputRate,
powerSources: b.components.isBattery!.powerSources,
}));
}),
}),
Expand All @@ -76,18 +78,31 @@ export const systemsMonitor = t.router({
for (const systemId of ctx.ship?.components.shipSystems?.shipSystems.keys() ||
[]) {
const system = ctx.flight?.ecs.getEntityById(systemId);
if (!system) continue;
if (!system?.components.isShipSystem) continue;
// Filter out reactors and batteries
if (system.components.isReactor || system.components.isBattery)
continue;
systems.push({
id: systemId,
name: system.components.identity!.name,
requestedPower: system.components.power?.requestedPower || 0,
maxSafePower: system.components.power?.maxSafePower || 0,
requiredPower: system.components.power?.requiredPower || 0,
efficiency: system.components.efficiency!.efficiency || 1,
heat: system.components.heat?.heat || 0,
maxHeat: system.components.heat?.maxHeat || 0,
maxSafeHeat: system.components.heat?.maxSafeHeat || 0,
nominalHeat: system.components.heat?.nominalHeat || 0,
power: system.components.power
? {
requestedPower: system.components.power.requestedPower,
maxSafePower: system.components.power.maxSafePower,
requiredPower: system.components.power.requiredPower,
powerSources: system.components.power.powerSources,
}
: undefined,

efficiency: system.components.efficiency?.efficiency,
heat: system.components.heat
? {
heat: system.components.heat.heat,
maxHeat: system.components.heat.maxHeat,
maxSafeHeat: system.components.heat.maxSafeHeat,
nominalHeat: system.components.heat.nominalHeat,
}
: undefined,
});
}

Expand All @@ -97,7 +112,10 @@ export const systemsMonitor = t.router({
stream: t.procedure.dataStream(({ ctx, entity }) => {
if (!entity) return false;
return Boolean(
ctx.ship?.components.shipSystems?.shipSystems.has(entity.id),
ctx.ship?.components.shipSystems?.shipSystems.has(entity.id) &&
(entity.components.power ||
entity.components.isBattery ||
entity.components.isReactor),
);
}),
});
166 changes: 93 additions & 73 deletions client/app/cards/SystemsMonitor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
useState,
} from "react";
import { Fragment } from "react/jsx-runtime";
import { createRNG } from "@thorium/rng";

/**
* TODO:
Expand All @@ -34,7 +33,6 @@ export function SystemsMonitor({ cardLoaded }: CardProps) {
const [selectedPowerSupplier, setSelectedPowerSupplier] = useState<
number | null
>(null);
const [selectedSystem, setSelectedSystem] = useState<number | null>(null);
return (
<div className="relative grid grid-cols-5 gap-8 h-full">
<div className="flex flex-col justify-around gap-4">
Expand Down Expand Up @@ -72,8 +70,7 @@ export function SystemsMonitor({ cardLoaded }: CardProps) {
key={system.id}
{...system}
cardLoaded={cardLoaded}
selectedSystem={selectedSystem}
setSelectedSystem={setSelectedSystem}
selectedPowerSupplier={selectedPowerSupplier}
/>
))}
</div>
Expand Down Expand Up @@ -206,7 +203,7 @@ function Reactor({
<div className="flex flex-col col-span-2 mt-2">
<div className="flex-1 flex flex-wrap gap-y-1">
{Array.from({
length: desiredOutput,
length: maxOutput,
}).map((_, i) => (
<Fragment key={i}>
<div
Expand Down Expand Up @@ -243,6 +240,7 @@ function Battery({
chargeRate,
outputRate,
capacity,
powerSources,
cardLoaded,
}: {
id: number;
Expand All @@ -253,6 +251,7 @@ function Battery({
chargeRate: number;
outputRate: number;
capacity: number;
powerSources: number[];
cardLoaded: boolean;
}) {
const chargeElementRefs = useRef<Map<number, HTMLDivElement>>(new Map());
Expand All @@ -273,12 +272,22 @@ function Battery({
const chargeAmount = system.y;
const dischargeAmount = system.z;
for (const [i, el] of chargeElementRefs.current) {
let activeClass = ["bg-yellow-400", "border-yellow-400"];
if (powerSources[i] === selectedPowerSupplier) {
activeClass = ["bg-green-400", "border-green-400"];
}
el.classList.remove(
"border-gray-500",
"bg-gray-500",
"bg-green-400",
"border-green-400",
"bg-yellow-400",
"border-yellow-400",
);
if (i + 1 <= Math.ceil(chargeAmount)) {
el.classList.add("bg-yellow-400", "border-yellow-400");
el.classList.remove("border-gray-500", "bg-gray-500");
el.classList.add(...activeClass);
} else {
el.classList.add("border-gray-500", "bg-gray-500");
el.classList.remove("bg-yellow-400", "border-yellow-400");
}
}
if (storageRef.current) {
Expand Down Expand Up @@ -390,28 +399,28 @@ function Battery({
function System({
id,
name,
requestedPower,
maxSafePower,
requiredPower,
power,
efficiency,
heat,
maxSafeHeat,
maxHeat,
nominalHeat,
selectedPowerSupplier,
cardLoaded,
}: {
id: number;
name: string;
requestedPower: number;
maxSafePower: number;
requiredPower: number;
power?: {
requestedPower: number;
maxSafePower: number;
requiredPower: number;
powerSources: number[];
};
efficiency?: number;
heat?: number;
maxSafeHeat?: number;
maxHeat?: number;
nominalHeat?: number;
selectedSystem: number | null;
setSelectedSystem: Dispatch<SetStateAction<number | null>>;
heat?: {
heat: number;
maxSafeHeat: number;
maxHeat: number;
nominalHeat: number;
};
selectedPowerSupplier: number | null;
cardLoaded: boolean;
}) {
const elementRefs = useRef<Map<number, HTMLDivElement>>(new Map());
Expand All @@ -423,26 +432,36 @@ function System({
const system = interpolate(id);
if (!system) return;
const currentPower = system.y;
const heat = system.z;
const heatValue = system.z;
for (const [i, el] of elementRefs.current) {
el.classList.remove(
"border-gray-500",
"bg-gray-500",
"bg-yellow-400",
"border-yellow-400",
"bg-green-400",
"border-green-400",
);
if (i + 1 <= Math.ceil(currentPower)) {
el.classList.add("bg-yellow-400", "border-yellow-400");
el.classList.remove("border-gray-500", "bg-gray-500");
} else {
el.classList.add("border-gray-500", "bg-gray-500");
el.classList.remove("bg-yellow-400", "border-yellow-400");
}
if (power?.powerSources[i] === selectedPowerSupplier) {
el.classList.add("border-green-400");
}
}
if (heatRef.current) {
heatRef.current.innerText = `Heat: ${Math.round(heat)}K`;
heatRef.current.innerText = `Heat: ${Math.round(heatValue)}K`;
}
if (heatProgressRef.current && nominalHeat && maxHeat) {
if (heatProgressRef.current && heat) {
heatProgressRef.current.setValue(
(heat - nominalHeat) / (maxHeat - nominalHeat),
(heatValue - heat.nominalHeat) / (heat.maxHeat - heat.nominalHeat),
);
}
}, cardLoaded);

if (!power && !efficiency && !heat) return null;
return (
<div
key={id}
Expand All @@ -451,19 +470,16 @@ function System({
<div className="font-medium w-full gap-1 self-start flex items-center">
<span className="truncate">{name}</span>
<div className="flex-1" />
{typeof heat === "number" &&
typeof nominalHeat === "number" &&
maxHeat ? (
{heat ? (
<Tooltip ref={heatRef} content={`Heat: K`}>
<RadialDial
ref={heatProgressRef}
marker={
maxSafeHeat
? (maxSafeHeat - nominalHeat) / (maxHeat - nominalHeat)
: undefined
(heat.maxSafeHeat - heat.nominalHeat) /
(heat.maxHeat - heat.nominalHeat)
}
label=""
count={(0 - nominalHeat) / (maxHeat - nominalHeat)}
count={(0 - heat.nominalHeat) / (heat.maxHeat - heat.nominalHeat)}
max={1}
color="rgb(293,68,68)"
backgroundColor="#888"
Expand All @@ -487,46 +503,50 @@ function System({
) : null}
</div>

<div className="flex flex-col mt-2">
<div className="flex gap-1 items-center">
<Tooltip content="Remove Power">
<Button className="btn-xs btn-primary">
<Icon name="minus" />
</Button>
</Tooltip>
<div className="flex-1 flex flex-wrap gap-y-1">
{Array.from({
length: Math.max(requestedPower, requiredPower),
}).map((_, i) => (
<Fragment key={i}>
{/* Display a warning indicator if we're past the max safe power */}
{i + 1 === maxSafePower + 1 && (
<Tooltip content="Max Safe Power">
<div className="w-0.5 ml-px mr-px h-3 last-of-type:mr-0 bg-red-500 rounded" />
</Tooltip>
)}
<div
ref={(el) => el && elementRefs.current.set(i, el)}
className={cn("w-3 h-3 mr-1 last-of-type:mr-0 border-2", {
"mr-0": i + 1 === requiredPower || i + 1 === maxSafePower,
})}
/>
{power ? (
<div className="flex flex-col mt-2">
<div className="flex gap-1 items-center">
<Tooltip content="Remove Power">
<Button className="btn-xs btn-primary">
<Icon name="minus" />
</Button>
</Tooltip>
<div className="flex-1 flex flex-wrap gap-y-1">
{Array.from({
length: Math.max(power.requestedPower, power.requiredPower),
}).map((_, i) => (
<Fragment key={i}>
{/* Display a warning indicator if we're past the max safe power */}
{i + 1 === power.maxSafePower + 1 && (
<Tooltip content="Max Safe Power">
<div className="w-0.5 ml-px mr-px h-3 last-of-type:mr-0 bg-red-500 rounded" />
</Tooltip>
)}
<div
ref={(el) => el && elementRefs.current.set(i, el)}
className={cn("w-3 h-3 mr-1 last-of-type:mr-0 border-2", {
"mr-0":
i + 1 === power.requiredPower ||
i + 1 === power.maxSafePower,
})}
/>

{i + 1 === requiredPower && (
<Tooltip content="Required Power">
<div className="w-0.5 ml-px mr-px h-3 last-of-type:mr-0 bg-yellow-500 rounded" />
</Tooltip>
)}
</Fragment>
))}
{i + 1 === power.requiredPower && (
<Tooltip content="Required Power">
<div className="w-0.5 ml-px mr-px h-3 last-of-type:mr-0 bg-yellow-500 rounded" />
</Tooltip>
)}
</Fragment>
))}
</div>
<Tooltip content="Allocate Power">
<Button className="btn-xs btn-primary">
<Icon name="plus" />
</Button>
</Tooltip>
</div>
<Tooltip content="Allocate Power">
<Button className="btn-xs btn-primary">
<Icon name="plus" />
</Button>
</Tooltip>
</div>
</div>
) : null}
</div>
);
}
Expand Down
4 changes: 4 additions & 0 deletions server/src/components/power.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ export const power = z
powerDraw: z.number().default(0),
/** How much power is currently being requested. Could be more than the maxSafePower */
requestedPower: z.number().default(10),
/**
* Which reactor or battery each unit of power is coming from. One unit = 1MW
*/
powerSources: z.number().array().default([]),
})
.default({});
5 changes: 2 additions & 3 deletions server/src/components/shipSystems/powerGrid/isBattery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ export const isBattery = z
*/
discharging: z.boolean().default(true),
/**
* Which system the units of power are allocated.
* Each item represents 1 MW of power.
* Which reactor each unit of power is coming from. One unit = 1MW
*/
outputAssignment: z.array(z.number()).default([]),
powerSources: z.number().array().default([]),
})
.default({});
5 changes: 0 additions & 5 deletions server/src/components/shipSystems/powerGrid/isReactor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ export const isReactor = z
* It will always be less than or equal to the desired output, never more.
*/
currentOutput: z.number().default(8),
/**
* Which system the units of power are allocated.
* Each item represents 1 MW of power. The length of this is the desired output.
*/
outputAssignment: z.array(z.number()).default([]),
/**
* How much fuel is left to burn after the previous tick. Fuel is only removed
* from inventory in whole units. Any fuel not turned into power remains in the
Expand Down
Loading

0 comments on commit 4c33ce9

Please sign in to comment.