mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-03-24 22:59:25 +00:00
rotate sky, organize missions into groups
This commit is contained in:
parent
1b3ff5ff00
commit
6257ef57b6
7 changed files with 236 additions and 57 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { getResourceList } from "../manifest";
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { getMissionInfo, getMissionList, getSource } from "../manifest";
|
||||
import { useControls, useDebug, useSettings } from "./SettingsProvider";
|
||||
import orderBy from "lodash.orderby";
|
||||
|
||||
|
|
@ -8,16 +9,60 @@ const excludeMissions = new Set([
|
|||
"SkiFree_Randomizer",
|
||||
]);
|
||||
|
||||
const missions = orderBy(
|
||||
getResourceList()
|
||||
.map((resourcePath) => resourcePath.match(/^missions\/(.+)\.mis$/))
|
||||
.filter(Boolean)
|
||||
.map((match) => match[1])
|
||||
.filter((name) => !excludeMissions.has(name)),
|
||||
[(name) => name.toLowerCase().replace(/_/g, " ")],
|
||||
["asc"]
|
||||
const SOURCE_GROUP_NAMES = {
|
||||
"Classic_maps_v1.vl2": "Classic",
|
||||
"missions.vl2": "Official",
|
||||
"S5maps.vl2": "S5",
|
||||
"S8maps.vl2": "S8",
|
||||
"SkiFreeGameType.vl2": "SkiFree",
|
||||
"TR2final105-client.vl2": "Team Rabbit 2",
|
||||
"TWL-MapPack.vl2": "TWL",
|
||||
"TWL2-MapPack.vl2": "TWL2",
|
||||
"z_DMP2-V0.6.vl2": "DMP2 (Discord Map Pack)",
|
||||
"zAddOnsVL2s/TWL_T2arenaOfficialMaps.vl2": "Arena",
|
||||
"zAddOnsVL2s/zDiscord-Map-Pack-4.7.1.vl2": "DMP (Discord Map Pack)",
|
||||
};
|
||||
|
||||
const groupedMissions = getMissionList().reduce(
|
||||
(groupMap, missionName) => {
|
||||
const missionInfo = getMissionInfo(missionName);
|
||||
const source = getSource(missionInfo.resourcePath);
|
||||
const groupName = SOURCE_GROUP_NAMES[source] ?? null;
|
||||
const groupMissions = groupMap.get(groupName) ?? [];
|
||||
if (!excludeMissions.has(missionName)) {
|
||||
groupMissions.push({
|
||||
resourcePath: missionInfo.resourcePath,
|
||||
missionName,
|
||||
displayName: missionInfo.displayName,
|
||||
});
|
||||
groupMap.set(groupName, groupMissions);
|
||||
}
|
||||
return groupMap;
|
||||
},
|
||||
new Map<
|
||||
string | null,
|
||||
Array<{
|
||||
resourcePath: string;
|
||||
missionName: string;
|
||||
displayName: string;
|
||||
}>
|
||||
>()
|
||||
);
|
||||
|
||||
groupedMissions.forEach((groupMissions, groupName) => {
|
||||
groupedMissions.set(
|
||||
groupName,
|
||||
orderBy(
|
||||
groupMissions,
|
||||
[
|
||||
(missionInfo) =>
|
||||
(missionInfo.displayName || missionInfo.missionName).toLowerCase(),
|
||||
],
|
||||
["asc"]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
export function InspectorControls({
|
||||
missionName,
|
||||
onChangeMission,
|
||||
|
|
@ -36,6 +81,19 @@ export function InspectorControls({
|
|||
const { speedMultiplier, setSpeedMultiplier } = useControls();
|
||||
const { debugMode, setDebugMode } = useDebug();
|
||||
|
||||
const groupedMissionOptions = useMemo(() => {
|
||||
const groups = orderBy(
|
||||
Array.from(groupedMissions.entries()),
|
||||
[
|
||||
([groupName]) =>
|
||||
groupName === "Official" ? 0 : groupName == null ? 2 : 1,
|
||||
([groupName]) => (groupName ? groupName.toLowerCase() : ""),
|
||||
],
|
||||
["asc", "asc"]
|
||||
);
|
||||
return groups;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="controls"
|
||||
|
|
@ -48,9 +106,26 @@ export function InspectorControls({
|
|||
value={missionName}
|
||||
onChange={(event) => onChangeMission(event.target.value)}
|
||||
>
|
||||
{missions.map((missionName) => (
|
||||
<option key={missionName}>{missionName}</option>
|
||||
))}
|
||||
{groupedMissionOptions.map(([groupName, groupMissions]) =>
|
||||
groupName ? (
|
||||
<optgroup key={groupName} label={groupName}>
|
||||
{groupMissions.map((mission) => (
|
||||
<option key={mission.missionName} value={mission.missionName}>
|
||||
{mission.displayName || mission.missionName}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
) : (
|
||||
<Fragment key="null">
|
||||
<hr />
|
||||
{groupMissions.map((mission) => (
|
||||
<option key={mission.missionName} value={mission.missionName}>
|
||||
{mission.displayName || mission.missionName}
|
||||
</option>
|
||||
))}
|
||||
</Fragment>
|
||||
)
|
||||
)}
|
||||
</select>
|
||||
<div className="CheckboxField">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { Suspense, useMemo, useEffect, useRef } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useCubeTexture } from "@react-three/drei";
|
||||
import { Color, ShaderMaterial, BackSide } from "three";
|
||||
import { ConsoleObject, getProperty } from "../mission";
|
||||
import { Color, ShaderMaterial, BackSide, Euler } from "three";
|
||||
import { ConsoleObject, getProperty, getRotation } from "../mission";
|
||||
import { useSettings } from "./SettingsProvider";
|
||||
import { BASE_URL, getUrlForPath, loadDetailMapList } from "../loaders";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
|
||||
const FALLBACK_URL = `${BASE_URL}/black.png`;
|
||||
|
||||
|
|
@ -119,6 +120,12 @@ export function SkyBox({
|
|||
}
|
||||
}, [skyBox, fogColor, hasFog, shaderMaterial]);
|
||||
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
scene.backgroundRotation = new Euler(0, Math.PI / 2, 0);
|
||||
}, []);
|
||||
|
||||
// If fog is disabled, just use the skybox as background
|
||||
if (!hasFog) {
|
||||
return <primitive attach="background" object={skyBox} />;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue