Release Healer Man 0.1.32
This commit is contained in:
1 parent
d3d6aaebdb
commit
6dcb1034e5
102 files changed
+10772
-788
No files matched your search
@@ -26,7 +26,6 @@ import { PartyPopulation } from "./PartyPopulation";
|
||||
import { GroundEffectTelegraphs } from "./GroundEffectTelegraphs";
|
||||
import { PlayerRig } from "./PlayerRig";
|
||||
import { useManastormStore } from "../game/manastormStore";
|
||||
import { ManastormPortal } from "./ManastormPortal";
|
||||
import {
|
||||
encounterWorldIsReady,
|
||||
encounterWorldKey,
|
||||
@@ -44,7 +43,6 @@ import { WailingNaralexEvent } from "./WailingNaralexEvent";
|
||||
import { GameGltfLoaderLifecycle } from "./useGameGLTF";
|
||||
import { CombatEffects } from "./CombatEffects";
|
||||
import { PLAYER_GRAVITY } from "../game/playerMovement";
|
||||
import { GmPlacementMarkers } from "./GmPlacementMarkers";
|
||||
import { useOnlineGroupStore } from "../app/onlineGroupStore";
|
||||
import { useOnlineSessionStore } from "../app/onlineSessionStore";
|
||||
import { OnlinePlayerPopulation } from "./OnlinePlayerPopulation";
|
||||
@@ -59,6 +57,7 @@ import { DungeonWorldObjects } from "./DungeonWorldObjects";
|
||||
import { ActivityAssetWarmup } from "./ActivityAssetWarmup";
|
||||
import { resolveDungeonAssets, resolveManastormStageAssets } from "../game/dungeonAssets";
|
||||
import { activeManastormStageAssetPackage } from "../game/manastormStageLoader";
|
||||
import { ShelvedGameSceneFeatures } from "@shelvedGameScene";
|
||||
import { shouldLoadPartyNavigation } from "../game/partyNavigationPolicy";
|
||||
import {
|
||||
activeDungeonCompletedObjectiveIds,
|
||||
@@ -404,8 +403,7 @@ export function GameScene() {
|
||||
allowedRuntimeIds={allowedRuntimeIds}
|
||||
/>
|
||||
<WailingNaralexEvent />
|
||||
<ManastormPortal />
|
||||
<GmPlacementMarkers />
|
||||
<ShelvedGameSceneFeatures />
|
||||
<CombatEffects active={!simulationBlocked} safeGraphics={safeGraphics} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
type OriginalCombatMeshGraph,
|
||||
} from "./originalCombatMeshRuntime";
|
||||
import { updateCombatEffectAnchorPosition } from "./combatEffectAnchorRegistry";
|
||||
import { shouldUseGeneratedOriginalFallback } from "./combatEffectRuntime";
|
||||
import { OriginalWowModel } from "./OriginalWowModel";
|
||||
import { OriginalParticleGeometry } from "./OriginalParticleGeometry";
|
||||
import {
|
||||
@@ -99,9 +100,10 @@ const vertexShader = /* glsl */ `
|
||||
vParticleAlpha = particleAlpha;
|
||||
vParticleFrame = particleFrame;
|
||||
vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
|
||||
float inheritedScale = length(modelViewMatrix[0].xyz);
|
||||
gl_Position = projectionMatrix * viewPosition;
|
||||
gl_PointSize = clamp(
|
||||
particleSize * viewportHeight / max(1.0, -viewPosition.z),
|
||||
particleSize * inheritedScale * viewportHeight / max(1.0, -viewPosition.z),
|
||||
1.0,
|
||||
256.0
|
||||
);
|
||||
@@ -894,16 +896,23 @@ export const OriginalCombatEffect = memo(function OriginalCombatEffect({
|
||||
const selection = loaded === null
|
||||
? null
|
||||
: selectCombatEffectRender("original", loaded.map((item) => item.asset));
|
||||
const hasOriginalInstantKit = event.phase === "release" && event.instantCast === true
|
||||
&& (["cast-start", "impact", "aura-start"] as const).some((phase) => (
|
||||
combatOriginalPhaseAssets({ ...event, phase }).length > 0
|
||||
));
|
||||
const resolvedFallback = shouldUseGeneratedOriginalFallback(event, hasOriginalInstantKit)
|
||||
? fallback
|
||||
: null;
|
||||
useEffect(() => {
|
||||
if (
|
||||
loaded === null
|
||||
|| selection?.kind === "original"
|
||||
|| fallback !== null
|
||||
|| resolvedFallback !== null
|
||||
|| completedMissingOriginalRef.current
|
||||
) return;
|
||||
completedMissingOriginalRef.current = true;
|
||||
onDone();
|
||||
}, [fallback, loaded, onDone, selection?.kind]);
|
||||
}, [loaded, onDone, resolvedFallback, selection?.kind]);
|
||||
|
||||
if (loaded === null || selection === null) return null;
|
||||
return selection.kind === "original" ? (
|
||||
@@ -914,7 +923,7 @@ export const OriginalCombatEffect = memo(function OriginalCombatEffect({
|
||||
loaded={loaded}
|
||||
onDone={onDone}
|
||||
/>
|
||||
) : fallback;
|
||||
) : resolvedFallback;
|
||||
}, (previous, next) => (
|
||||
previous.event === next.event
|
||||
&& previous.alternateOriginalPhase === next.alternateOriginalPhase
|
||||
|
||||
@@ -23,7 +23,7 @@ import { resolvedEquipmentItems } from "../game/heirloomEquipment";
|
||||
import type { CharacterCombatAnimationEvent } from "../game/combatAnimation";
|
||||
import { resolveDungeonAssets, resolveManastormStageAssets } from "../game/dungeonAssets";
|
||||
import { activeManastormStageAssetPackage } from "../game/manastormStageLoader";
|
||||
import { derivePartySpawnSlots } from "../game/manastormAdminConfig";
|
||||
import { derivePartySpawnSlots } from "../game/partySpawnSlots";
|
||||
import { requireDungeonDefinition } from "../game/dungeonRegistry";
|
||||
import type { DungeonBossObjective } from "../game/dungeonTypes";
|
||||
import { getMobPosition } from "../game/mobRuntimeRegistry";
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function ShelvedGameSceneFeatures() {
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { GmPlacementMarkers } from "./GmPlacementMarkers";
|
||||
import { ManastormPortal } from "./ManastormPortal";
|
||||
|
||||
export function ShelvedGameSceneFeatures() {
|
||||
return (
|
||||
<>
|
||||
<ManastormPortal />
|
||||
<GmPlacementMarkers />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
advanceCombatEffectFrame,
|
||||
originalInstantCastEvent,
|
||||
originalInstantTerminalEvent,
|
||||
shouldUseGeneratedOriginalFallback,
|
||||
updateCombatEffectQueue,
|
||||
type ActiveCombatEffect,
|
||||
} from "./combatEffectRuntime";
|
||||
@@ -168,4 +169,22 @@ describe("combat-effect runtime budget", () => {
|
||||
});
|
||||
expect(originalInstantTerminalEvent(event(22, { phase: "impact" }))).toBeNull();
|
||||
});
|
||||
|
||||
it("does not layer a generated release over an instant ability's original phases", () => {
|
||||
expect(shouldUseGeneratedOriginalFallback(event(30, {
|
||||
phase: "release",
|
||||
instantCast: true,
|
||||
}), true)).toBe(false);
|
||||
expect(shouldUseGeneratedOriginalFallback(event(31, {
|
||||
phase: "release",
|
||||
instantCast: true,
|
||||
}), false)).toBe(true);
|
||||
expect(shouldUseGeneratedOriginalFallback(event(31, {
|
||||
phase: "release",
|
||||
}), true)).toBe(true);
|
||||
expect(shouldUseGeneratedOriginalFallback(event(32, {
|
||||
phase: "impact",
|
||||
instantCast: true,
|
||||
}), true)).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -179,6 +179,15 @@ export function originalInstantTerminalEvent(
|
||||
};
|
||||
}
|
||||
|
||||
/** Instant resolutions immediately emit a terminal phase, so their missing release
|
||||
* asset must not add a generated layer over the authentic cast and terminal kits. */
|
||||
export function shouldUseGeneratedOriginalFallback(
|
||||
event: CombatPresentationEvent,
|
||||
hasOriginalInstantKit: boolean,
|
||||
): boolean {
|
||||
return event.phase !== "release" || !event.instantCast || !hasOriginalInstantKit;
|
||||
}
|
||||
|
||||
export function addOriginalOnlyEffect(
|
||||
current: readonly ActiveCombatEffect[],
|
||||
event: CombatPresentationEvent,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Matrix4, Quaternion, Vector3 } from "three";
|
||||
import { parseOriginalWowModelGraph, updateWowBoneMatrices, wowModelFrame, wowModelTextureUrls, wowParticleChild } from "./originalWowModelRuntime";
|
||||
|
||||
const manifest = JSON.parse(readFileSync(path.resolve("public/assets/game/combat-effects/manifest.json"), "utf8"));
|
||||
const rendererSource = readFileSync(new URL("./OriginalCombatEffect.tsx", import.meta.url), "utf8");
|
||||
const urls = [...new Set<string>(manifest.entries.filter((e: { source: string }) => e.source === "wow335")
|
||||
.flatMap((e: { phases: Record<string, { effectGraphUrl?: string }[]> }) => Object.values(e.phases ?? {}).flat()
|
||||
.map((a) => a.effectGraphUrl).filter(Boolean)))];
|
||||
@@ -67,4 +68,13 @@ describe("all-class original WoW models", () => {
|
||||
const dispel = parseOriginalWowModelGraph(graphs.find((g) => g.sourceModel === "spells/clense_base.m2"));
|
||||
expect(wowParticleChild(dispel, "Spells\\Dispel_Low_Recursive.mdx")!.particleGraph!.particles).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("applies recursive parent scale to Purify and Cleanse point sprites", () => {
|
||||
for (const sourceModel of ["spells/purify_base.m2", "spells/clense_base.m2"]) {
|
||||
const graph = parseOriginalWowModelGraph(graphs.find((candidate) => candidate.sourceModel === sourceModel));
|
||||
expect(graph.particleGraph!.particles.filter((particle) => particle.recursionModel)).toHaveLength(3);
|
||||
}
|
||||
expect(rendererSource).toContain("float inheritedScale = length(modelViewMatrix[0].xyz);");
|
||||
expect(rendererSource).toContain("particleSize * inheritedScale * viewportHeight");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user