Skip to content

Commit

Permalink
Merge pull request #605 from Thorium-Sim/position-refactor
Browse files Browse the repository at this point in the history
Position refactor
  • Loading branch information
alexanderson1993 authored Nov 21, 2023
2 parents 6c8d04d + d5de106 commit 1074d9d
Show file tree
Hide file tree
Showing 63 changed files with 4,119 additions and 3,060 deletions.
6 changes: 3 additions & 3 deletions client/react-test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import {
import {MockNetRequestContext} from "@thorium/live-query/client/mockContext";
import {AppRouter} from "@server/init/router";
import {inferRouterOutputs} from "@thorium/live-query/server/types";

import {vi} from "vitest";
// @ts-expect-error
global.IS_REACT_ACT_ENVIRONMENT = true;

let netSendResponse: {response: any} = {response: ""};
const netSendSpy = jest.fn((input, params) => netSendResponse);
const netSendSpy = vi.fn((input, params) => netSendResponse);
function setNetSendResponse(response: any) {
netSendResponse = {response};
}
global.fetch = jest.fn((url: URL, {body}: {body: FormData}) => {
global.fetch = vi.fn((url: URL, {body}: {body: FormData}) => {
if (url.pathname.toLowerCase() === "/netsend") {
let bodyObj: any = {};

Expand Down
9 changes: 5 additions & 4 deletions client/src/cards/OfficersLog/OfficersLog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import OfficersLog from ".";
import {render} from "client/react-test-utils";
import userEvent from "@testing-library/user-event";
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";

test("it should render without error", async () => {
const queryClient = new QueryClient();

Expand All @@ -23,12 +24,12 @@ test("it should render without error", async () => {
},
}
);
const logEl = await findByText("@560.60");
expect(logEl).toBeInTheDocument();
const logEl = await findByText("@560.60", {}, {timeout: 5000});
expect(logEl).toBeDefined();
userEvent.click(logEl);
expect(await findByText("This is a test log entry")).toBeInTheDocument();
expect(await findByText("This is a test log entry")).toBeDefined();
await userEvent.click(await findByText("Clear"));
expect(queryByText("This is a test log entry")).not.toBeInTheDocument();
expect(queryByText("This is a test log entry")).toBeNull();
await userEvent.click(await findByText("New Log Entry"));
const entryText = "This is a new log entry.";
await userEvent.type(await findByRole("textbox"), entryText);
Expand Down
13 changes: 4 additions & 9 deletions client/src/cards/Pilot/ImpulseControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,18 @@ function formatSpeed(speed: KilometerPerSecond) {
}

export function useForwardVelocity() {
const [{id: impulseId, targetSpeed}] =
q.pilot.impulseEngines.get.useNetRequest();
const [{id: warpId}] = q.pilot.warpEngines.get.useNetRequest();
const [{targetSpeed}] = q.pilot.impulseEngines.get.useNetRequest();
const [{maxVelocity: warpMax}] = q.pilot.warpEngines.get.useNetRequest();
const [ship] = q.navigation.ship.useNetRequest();
const {interpolate} = useLiveQuery();

return function getForwardVelocity(): [
KilometerPerSecond,
KilometerPerSecond
] {
const warpInterpolation = interpolate(warpId);
const {x: warpForward, y: warpMax} = warpInterpolation || {x: 0, y: 0};

const impulseInterpolation = interpolate(impulseId);
const {x: impulseForward} = impulseInterpolation || {x: 0};
const {f: forwardVelocity} = interpolate(ship.id) || {f: 0};

const targetVelocity = Math.max(targetSpeed, warpMax);
const forwardVelocity = Math.max(warpForward, impulseForward);
return [forwardVelocity, targetVelocity] as [
KilometerPerSecond,
KilometerPerSecond
Expand Down
7 changes: 2 additions & 5 deletions client/src/cards/Pilot/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,8 @@ export const pilot = t.router({
return false;
}
return Boolean(
(entity.components.position &&
entity.components.position.parentId === systemId) ||
((entity.components.isWarpEngines ||
entity.components.isImpulseEngines) &&
ctx.ship?.components.shipSystems?.shipSystems.has(entity.id))
entity.components.position &&
entity.components.position.parentId === systemId
);
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ const QuickStartProvider = ({children}: {children: React.ReactNode}) => {
});
}, [set]);

console.log(value[0]);
return (
<QuickStartContext.Provider value={value}>
{children}
Expand Down
33 changes: 31 additions & 2 deletions client/src/components/Starmap/PolarGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {PolarGridHelperProps} from "@react-three/fiber";
import {
PolarGridHelperProps,
GridHelperProps,
useFrame,
} from "@react-three/fiber";
import * as React from "react";
import {AdditiveBlending, PolarGridHelper} from "three";
import {AdditiveBlending, PolarGridHelper, GridHelper} from "three";
import {useGetStarmapStore} from "./starmapStore";

export function PolarGrid(props: PolarGridHelperProps) {
const polarRef = React.useRef<PolarGridHelper>(null);
Expand All @@ -15,3 +20,27 @@ export function PolarGrid(props: PolarGridHelperProps) {
});
return <polarGridHelper ref={polarRef} {...props} />;
}
export function Grid(props: GridHelperProps) {
const gridRef = React.useRef<GridHelper>(null);
const useStarmapStore = useGetStarmapStore();
const cameraControls = useStarmapStore(s => s.cameraControls);
React.useLayoutEffect(() => {
if (gridRef.current && !Array.isArray(gridRef.current?.material)) {
gridRef.current.material.depthWrite = false;
gridRef.current.material.transparent = true;
gridRef.current.renderOrder = -1;
gridRef.current.material.blending = AdditiveBlending;
gridRef.current.material.opacity = 0.15;
}
});
useFrame(() => {
if (gridRef.current && !Array.isArray(gridRef.current?.material)) {
const y = cameraControls?.current?.camera.position.y || Infinity;
gridRef.current.material.opacity = Math.min(
300000000 * (1 / y) * 0.15,
0.3
);
}
});
return <gridHelper ref={gridRef} {...props} />;
}
8 changes: 5 additions & 3 deletions client/src/components/Starmap/SolarSystemMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {PlanetDisclosure} from "./EditorPalettes/PlanetDisclosure";
import {OrbitDisclosure} from "./EditorPalettes/OrbitDisclosure";
import {PlanetAssetDisclosure} from "././EditorPalettes/PlanetAssetDisclosure";
import StarPlugin from "server/src/classes/Plugins/Universe/Star";
import {PolarGrid} from "./PolarGrid";
import {Grid, PolarGrid} from "./PolarGrid";
import {useSystemIds} from "./useSystemIds";
import Input from "@thorium/ui/Input";
import Checkbox from "@thorium/ui/Checkbox";
Expand All @@ -34,11 +34,12 @@ import {q} from "@client/context/AppContext";
import PlanetPlugin from "@server/classes/Plugins/Universe/Planet";
import SolarSystemPlugin from "@server/classes/Plugins/Universe/SolarSystem";
import {getOrbitPosition} from "@server/utils/getOrbitPosition";
import {SECTOR_GRID_SIZE} from "@server/init/rapier";
const ACTION = CameraControlsClass.ACTION;

// 10% further than Neptune's orbit
export const SOLAR_SYSTEM_MAX_DISTANCE: Kilometer = 4_000_000_000 * 1.1;

const CELLS = Math.ceil(SOLAR_SYSTEM_MAX_DISTANCE / SECTOR_GRID_SIZE);
function HabitableZone() {
const [pluginId, solarSystemId] = useSystemIds();
const [{habitableZoneInner = 0, habitableZoneOuter = 3, stars}] =
Expand Down Expand Up @@ -100,7 +101,6 @@ export function SolarSystemMap({
const viewingMode = useStarmapStore(store => store.viewingMode);

const isViewscreen = viewingMode === "viewscreen";

return (
<Suspense fallback={null}>
{!pluginId ? null : <HabitableZone />}
Expand All @@ -124,6 +124,8 @@ export function SolarSystemMap({
rotation={[0, (2 * Math.PI) / 12, 0]}
args={[maxDistance, 12, 20, 64, 0xffffff, 0xffffff]}
/>
{/* Adjust opacity as the camera zooms in. */}
<Grid args={[CELLS * SECTOR_GRID_SIZE, CELLS, 0xffffff, 0xffffff]} />
</>
)}
{children}
Expand Down
32 changes: 31 additions & 1 deletion client/src/cores/StarmapCore/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ export const starmapCore = t.router({

const entity = ctx.flight.ecs.getEntityById(input.shipId);
if (!entity) return null;
return {id: entity.id, systemId: entity.components.position?.parentId};
return {
id: entity.id,
systemId: entity.components.position?.parentId,
behavior: entity.components.shipBehavior,
};
}),
debugSpheres: t.procedure
.input(z.object({systemId: z.number().nullable()}))
Expand Down Expand Up @@ -250,6 +254,32 @@ export const starmapCore = t.router({
pubsub.publish.starmapCore.autopilot({systemId: id});
});
}),
setBehavior: t.procedure
.input(
z.object({
ships: z.number().array(),
behavior: z.union([
z.literal("hold"),
z.literal("seek"),
z.literal("patrol"),
z.literal("attack"),
z.literal("defend"),
z.literal("avoid"),
]),
})
)
.send(({ctx, input}) => {
input.ships.forEach(shipId => {
const entity = ctx.flight?.ecs.getEntityById(shipId);
entity?.updateComponent("shipBehavior", {
objective: input.behavior,
});

pubsub.publish.pilot.autopilot.get({shipId});
pubsub.publish.ship.get({shipId});
pubsub.publish.starmapCore.ship({shipId});
});
}),
stream: t.procedure
.input(z.object({systemId: z.number().nullable()}))
.dataStream(({entity, input}) => {
Expand Down
105 changes: 101 additions & 4 deletions client/src/cores/StarmapCore/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import useDragSelect, {
get3dSelectedObjects,
} from "client/src/hooks/useDragSelect";
import {Mesh, PerspectiveCamera, Vector3} from "three";
import {FaArrowLeft} from "react-icons/fa";
import {GiTargeted} from "react-icons/gi";
import {FaArrowLeft, FaHandPaper, FaShieldAlt} from "react-icons/fa";
import {GiBroadsword, GiTargeted} from "react-icons/gi";
import {AiFillAlert} from "react-icons/ai";
import Button from "@thorium/ui/Button";
import {useCancelFollow} from "client/src/components/Starmap/useCancelFollow";
import {useFollowEntity} from "client/src/components/Starmap/useFollowEntity";
Expand All @@ -33,6 +34,8 @@ import {Coordinates} from "server/src/utils/unitTypes";
import {q} from "@client/context/AppContext";
import {useLiveQuery} from "@thorium/live-query/client";
import {useFrame} from "@react-three/fiber";
import clsx from "clsx";
import {Tooltip} from "@thorium/ui/Tooltip";

export function StarmapCore() {
const ref = useRef<HTMLDivElement>(null);
Expand All @@ -45,14 +48,108 @@ export function StarmapCore() {
<StarmapCoreMenubar />
</div>
<CanvasWrapper />
<div className="absolute left-4 bottom-4 w-96">
<ZoomSliderComp />
<div className="absolute left-4 bottom-0 flex gap-2 items-end">
<div className="w-96">
<ZoomSliderComp />
</div>
<ShipControls />
</div>
</StarmapStoreProvider>
</div>
);
}

function ShipControls() {
const useStarmapStore = useGetStarmapStore();
const followEntityId = useStarmapStore(store => store.followEntityId);

const [starmapShip] = q.starmapCore.ship.useNetRequest({
shipId: followEntityId,
});

return (
<>
{followEntityId && starmapShip?.behavior ? (
<>
<Tooltip content="Patrol">
<Button
onClick={() =>
q.starmapCore.setBehavior.netSend({
ships: [followEntityId],
behavior: "patrol",
})
}
className={clsx("btn-sm btn-info btn-outline", {
"btn-active": starmapShip.behavior.objective === "patrol",
})}
>
<AiFillAlert />
</Button>
</Tooltip>
<Tooltip content="Hold Position">
<Button
onClick={() =>
q.starmapCore.setBehavior.netSend({
ships: [followEntityId],
behavior: "hold",
})
}
className={clsx("btn-sm btn-warning btn-outline", {
"btn-active": starmapShip.behavior.objective === "hold",
})}
>
<FaHandPaper />
</Button>
</Tooltip>
<Tooltip content="Attack">
<Button
onClick={() =>
q.starmapCore.setBehavior.netSend({
ships: [followEntityId],
behavior: "attack",
})
}
className={clsx("btn-sm btn-error btn-outline", {
"btn-active": starmapShip.behavior.objective === "attack",
})}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit="2"
clipRule="evenodd"
viewBox="0 0 700 700"
className="w-4 h-4"
>
<path
fill="currentColor"
d="M212 533L88 639l-25 48-56-9-7-55 49-24 112-119-74-78 26-27 101 74 30 31 70 105-28 26-74-78zM700 13l-70 155-368 320-11-15-30-32-13-10L540 77l160-64z"
></path>
</svg>
</Button>
</Tooltip>
<Tooltip content="Follow & Defend">
<Button
onClick={() =>
q.starmapCore.setBehavior.netSend({
ships: [followEntityId],
behavior: "defend",
})
}
className={clsx("btn-sm btn-primary btn-outline", {
"btn-active": starmapShip.behavior.objective === "defend",
})}
>
<FaShieldAlt />
</Button>
</Tooltip>
</>
) : null}
</>
);
}

function StarmapCoreMenubar() {
const useStarmapStore = useGetStarmapStore();
const [playerShips] = q.ship.players.useNetRequest();
Expand Down
9 changes: 5 additions & 4 deletions client/src/data/flight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,11 @@ export const flight = t.router({
{path: `/flights/${flightName}.flight`}
);

ctx.flight.initEcs(ctx.server);
const activePlugins = ctx.server.plugins.filter(p => p.active);
ctx.flight.pluginIds = activePlugins.map(p => p.id);

await ctx.flight.initEcs(ctx.server);
await ctx.flight.initPhysics();
// This will spawn all of the systems and planets bundled with the plugins
const solarSystemMap = ctx.flight.pluginIds.reduce(
(map: Record<string, Entity>, pluginId) => {
Expand Down Expand Up @@ -195,7 +196,6 @@ export const flight = t.router({
});
// Add inventory entities to their appropriate system
ctx.flight.ecs.cleanDirtyEntities();

// Spawn the ships that were defined when the flight was started
for (const ship of ships) {
const shipTemplate = activePlugins.reduce(
Expand Down Expand Up @@ -317,7 +317,7 @@ export const flight = t.router({
}),
load: t.procedure
.input(z.object({flightName: z.string()}))
.send(({ctx, input}) => {
.send(async ({ctx, input}) => {
inputAuth(ctx);
if (ctx.flight) return ctx.flight;

Expand All @@ -329,7 +329,8 @@ export const flight = t.router({
},
{path: `/flights/${input.flightName}.flight`}
);
ctx.flight.initEcs(ctx.server);
await ctx.flight.initEcs(ctx.server);
await ctx.flight.initPhysics();

ctx.server.activeFlightName = input.flightName;
pubsub.publish.flight.active();
Expand Down
Loading

0 comments on commit 1074d9d

Please sign in to comment.