Release Healer Man 0.1.22

This commit is contained in:
phenom committed 2026-09-09 11:21:33 -04:00
1 parent f6f2375145
commit 7f6001723a
144 files changed
+54107 -690

No files matched your search

+83 -8
View File
@@ -54,12 +54,20 @@ import { useDocumentVisibility } from "../platform/useDocumentVisibility";
import { CappedFrameLoop } from "./CappedFrameLoop";
import { selectDungeonSessionPopulation } from "../game/dungeonSpawnSelection";
import { DungeonWorldObjects } from "./DungeonWorldObjects";
import { ActivityAssetWarmup } from "./ActivityAssetWarmup";
import { resolveDungeonAssets, resolveManastormStageAssets } from "../game/dungeonAssets";
import { activeManastormStageAssetPackage } from "../game/manastormStageLoader";
import { shouldLoadPartyNavigation } from "../game/partyNavigationPolicy";
import {
activeDungeonCompletedObjectiveIds,
activeDungeonEncounterRevision,
activeDungeonEncounterSpawnGroupIds,
subscribeDungeonEncounterSnapshots,
} from "../game/dungeonEncounterRuntime";
import { activeEncounterSpawnGroupSpawns } from "../game/dungeonEncounterSpawns";
import {
activeEncounterSpawnGroupSpawns,
suppressCompletedDungeonPopulation,
} from "../game/dungeonEncounterSpawns";
export function GameScene() {
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
@@ -74,6 +82,9 @@ export function GameScene() {
activeDungeonEncounterRevision,
);
const dungeon = requireDungeonDefinition(activeDungeonId);
const completedObjectiveIds = gameMode === "dungeon"
? activeDungeonCompletedObjectiveIds(activeDungeonId)
: [];
const cameraFar = Math.max(
950,
Math.min(
@@ -100,6 +111,26 @@ export function GameScene() {
: { entities: dungeon.entities, staticSpawns: dungeon.staticSpawns },
[dungeon, gameMode, manastormEncounter],
);
const manastormAssetPackage = gameMode === "manastorm"
? activeManastormStageAssetPackage()
: null;
const activityAssets = useMemo(
() => manastormAssetPackage
? resolveManastormStageAssets(manastormAssetPackage)
: resolveDungeonAssets(dungeon),
[dungeon, manastormAssetPackage, sessionRevision],
);
const navigationUrl = activityAssets.navigation
&& shouldLoadPartyNavigation(gameMode, dungeon, manastormAssetPackage)
? activityAssets.navigation
: null;
const navigationLinks = manastormAssetPackage ? [] : dungeon.navigationLinks;
const activitySceneAssetUrls = useMemo(() => [...new Set([
...Object.values(stagePopulation.entities).flatMap((entity) => (
entity.visual.model?.url ? [entity.visual.model.url] : []
)),
...(navigationUrl ? [navigationUrl] : []),
])], [navigationUrl, stagePopulation.entities]);
const difficultyRoamingPacks = manastormStageRoamingPacks(
dungeon.roamingPacks.filter((pack) => spawnMatchesDifficulty(pack.spawnMask, difficultyMask)),
gameMode === "manastorm" ? manastormEncounter : null,
@@ -107,14 +138,19 @@ export function GameScene() {
const difficultySpawns = stagePopulation.staticSpawns.filter(
(spawn) => spawnMatchesDifficulty(spawn.spawnMask, difficultyMask),
);
const persistentPopulation = suppressCompletedDungeonPopulation(
difficultySpawns,
difficultyRoamingPacks,
completedObjectiveIds,
);
const phasedStaticSpawns = activeDungeonId === "wailing-caverns" && gameMode === "dungeon"
? wailingStaticSpawnsForPhase(difficultySpawns, wailingPhase)
: difficultySpawns;
? wailingStaticSpawnsForPhase(persistentPopulation.staticSpawns, wailingPhase)
: persistentPopulation.staticSpawns;
const sessionPopulation = selectDungeonSessionPopulation(
activeDungeonId,
sessionRevision,
phasedStaticSpawns,
difficultyRoamingPacks,
persistentPopulation.roamingPacks,
);
const activeSpawnGroupIds = activeDungeonEncounterSpawnGroupIds();
const encounterSpawns = activeEncounterSpawnGroupSpawns(
@@ -122,7 +158,7 @@ export function GameScene() {
activeSpawnGroupIds,
difficultyMask,
sessionPopulation.staticSpawns,
);
).filter((spawn) => !completedObjectiveIds.includes(spawn.id));
const staticSpawns = [
...sessionPopulation.staticSpawns,
...encounterSpawns,
@@ -136,7 +172,10 @@ export function GameScene() {
const onlineAuthority = useOnlineSessionStore((state) => state.snapshot?.authority ?? true);
const documentVisible = useDocumentVisibility();
const canvasRef = useRef<HTMLCanvasElement>(null);
const [environmentReadySessionRevision, setEnvironmentReadySessionRevision] = useState<number | null>(null);
const [activityAssetsReadySessionRevision, setActivityAssetsReadySessionRevision] = useState<number | null>(null);
const [readySessionRevision, setReadySessionRevision] = useState<number | null>(null);
const proxyAssetStateRef = useRef<{ readonly revision: number; readonly message: string | null } | null>(null);
const [safeGraphics, setSafeGraphics] = useState(false);
const [adaptiveDpr, setAdaptiveDpr] = useState(1.5);
const [canvasRevision, setCanvasRevision] = useState(0);
@@ -164,15 +203,42 @@ export function GameScene() {
[gameMode, manastormEncounter, manastormPhase],
);
const markWorldReady = useCallback(() => {
setReadySessionRevision(sessionRevision);
const markEnvironmentReady = useCallback(() => {
const game = useGameStore.getState();
proxyAssetStateRef.current = game.assetStatus === "proxy"
? { revision: sessionRevision, message: game.assetMessage }
: null;
game.setAssetStatus("loading", "Preparing party, creatures, and navigation.");
setEnvironmentReadySessionRevision(sessionRevision);
setGraphicsRecovery((state) => state === "recovering" ? null : state);
}, [sessionRevision]);
const markActivityAssetsReady = useCallback(() => {
setActivityAssetsReadySessionRevision(sessionRevision);
}, [sessionRevision]);
useEffect(() => {
if (
environmentReadySessionRevision !== sessionRevision
|| activityAssetsReadySessionRevision !== sessionRevision
) return;
setReadySessionRevision(sessionRevision);
}, [activityAssetsReadySessionRevision, environmentReadySessionRevision, sessionRevision]);
useEffect(() => {
if (!worldReady) return;
const proxy = proxyAssetStateRef.current?.revision === sessionRevision
? proxyAssetStateRef.current
: null;
useGameStore.getState().setAssetStatus(proxy ? "proxy" : "ready", proxy?.message ?? null);
}, [sessionRevision, worldReady]);
const restartRenderer = useCallback(() => {
releasePointerLock();
useGameStore.getState().resetAtActiveSpawn();
setSafeGraphics(true);
setEnvironmentReadySessionRevision(null);
setActivityAssetsReadySessionRevision(null);
setReadySessionRevision(null);
setGraphicsRecovery("recovering");
setCanvasRevision((revision) => revision + 1);
@@ -273,6 +339,15 @@ export function GameScene() {
/>
)}
<GameGltfLoaderLifecycle>
{!worldReady && (
<ActivityAssetWarmup
key={`activity-warmup:${sessionRevision}`}
navigationLinks={navigationLinks}
navigationUrl={navigationUrl}
sceneAssetUrls={activitySceneAssetUrls}
onReady={markActivityAssetsReady}
/>
)}
{!safeGraphics && worldReady && (
<AdaptiveGraphicsQuality
frameRateLimit={gameplayFrameRate}
@@ -306,7 +381,7 @@ export function GameScene() {
paused={simulationBlocked}
timeStep={1 / 60}
>
<DungeonEnvironment onReady={markWorldReady} />
<DungeonEnvironment onReady={markEnvironmentReady} />
{worldReady && (
<>
<PlayerRig />