Release v0.1.9 2026-07-13

This commit is contained in:
Warren H
2026-07-13 19:37:30 -04:00
parent 18c416d4d2
commit aa9f5eff20
35 changed files with 1064 additions and 48 deletions
+65 -21
View File
@@ -30,15 +30,30 @@ import type { BossId, MemberId, PulseKind } from "../game/types";
import { BossRoom } from "./BossRoom";
import { BossMechanicIndicators } from "./boss/BossMechanicIndicators";
import { bossCanTrackTarget, bossDeathOpacity } from "./boss/bossDeathVisuals";
import { GameAssetProvider, LEGACY_GAME_ASSETS_FORCED, selectedGameAssetUrl, useGameGLTF } from "./GameAssetProvider";
const PARTY_MODEL_URLS: Record<MemberId, string> = {
const PARTY_MODEL_LEGACY_URLS: Record<MemberId, string> = {
aelia: new URL("../assets/game/models/claudecraft/chars/players/druid.glb", import.meta.url).href,
brann: new URL("../assets/game/models/claudecraft/chars/players/knight.glb", import.meta.url).href,
nia: new URL("../assets/game/models/claudecraft/chars/players/ranger.glb", import.meta.url).href,
orin: new URL("../assets/game/models/claudecraft/chars/players/mage.glb", import.meta.url).href,
vale: new URL("../assets/game/models/claudecraft/chars/players/rogue.glb", import.meta.url).href,
};
const PARTY_WEAPON_URLS: Record<MemberId, { right: string; left?: string }> = {
const PARTY_MODEL_OPTIMIZED_URLS: Record<MemberId, string> = {
aelia: new URL("../assets/game/models/claudecraft/chars/players/druid-uastc.glb", import.meta.url).href,
brann: new URL("../assets/game/models/claudecraft/chars/players/knight-uastc.glb", import.meta.url).href,
nia: new URL("../assets/game/models/claudecraft/chars/players/ranger-uastc.glb", import.meta.url).href,
orin: new URL("../assets/game/models/claudecraft/chars/players/mage-uastc.glb", import.meta.url).href,
vale: new URL("../assets/game/models/claudecraft/chars/players/rogue-uastc.glb", import.meta.url).href,
};
const PARTY_MODEL_URLS = Object.fromEntries(Object.keys(PARTY_MODEL_LEGACY_URLS).map((memberId) => [
memberId,
selectedGameAssetUrl(
PARTY_MODEL_LEGACY_URLS[memberId as MemberId],
PARTY_MODEL_OPTIMIZED_URLS[memberId as MemberId],
),
])) as Record<MemberId, string>;
const PARTY_WEAPON_LEGACY_URLS: Record<MemberId, { right: string; left?: string }> = {
aelia: { right: new URL("../assets/game/models/claudecraft/weapons/adv_druid_staff.glb", import.meta.url).href },
brann: {
right: new URL("../assets/game/models/claudecraft/weapons/adv_sword_1handed.glb", import.meta.url).href,
@@ -54,6 +69,30 @@ const PARTY_WEAPON_URLS: Record<MemberId, { right: string; left?: string }> = {
left: new URL("../assets/game/models/claudecraft/weapons/adv_dagger.glb", import.meta.url).href,
},
};
const PARTY_WEAPON_OPTIMIZED_URLS: Record<MemberId, { right: string; left?: string }> = {
aelia: { right: new URL("../assets/game/models/claudecraft/weapons/adv_druid_staff-uastc.glb", import.meta.url).href },
brann: {
right: new URL("../assets/game/models/claudecraft/weapons/adv_sword_1handed-uastc.glb", import.meta.url).href,
left: new URL("../assets/game/models/claudecraft/weapons/shield_badge-uastc.glb", import.meta.url).href,
},
nia: { right: new URL("../assets/game/models/claudecraft/weapons/crossbow_2handed-uastc.glb", import.meta.url).href },
orin: {
right: new URL("../assets/game/models/claudecraft/weapons/adv_wand-uastc.glb", import.meta.url).href,
left: new URL("../assets/game/models/claudecraft/weapons/spellbook_open-uastc.glb", import.meta.url).href,
},
vale: {
right: new URL("../assets/game/models/claudecraft/weapons/adv_dagger-uastc.glb", import.meta.url).href,
left: new URL("../assets/game/models/claudecraft/weapons/adv_dagger-uastc.glb", import.meta.url).href,
},
};
const PARTY_WEAPON_URLS = Object.fromEntries(Object.keys(PARTY_WEAPON_LEGACY_URLS).map((memberId) => {
const legacy = PARTY_WEAPON_LEGACY_URLS[memberId as MemberId];
const optimized = PARTY_WEAPON_OPTIMIZED_URLS[memberId as MemberId];
return [memberId, {
right: selectedGameAssetUrl(legacy.right, optimized.right),
left: legacy.left && optimized.left ? selectedGameAssetUrl(legacy.left, optimized.left) : undefined,
}];
})) as Record<MemberId, { right: string; left?: string }>;
const PARTY_MODEL_SCALES: Record<MemberId, number> = { aelia: 0.62, brann: 0.68, nia: 0.7, orin: 0.64, vale: 0.72 };
const PARTY_ATTACK_CLIPS: Record<MemberId, string> = {
aelia: "2H_Melee_Attack_Chop",
@@ -227,12 +266,12 @@ function PartyCharacterModel({
animationState: MutableRefObject<ActorAnimationState>;
animationTrigger: MutableRefObject<number>;
}) {
const gltf = useGLTF(PARTY_MODEL_URLS[memberId], false, true);
const gltf = useGameGLTF(PARTY_MODEL_URLS[memberId]);
const actorScene = useMemo(() => cloneSkeleton(gltf.scene), [gltf.scene]);
const loadout = PARTY_WEAPON_URLS[memberId];
const grips = PARTY_WEAPON_GRIPS[memberId];
const rightWeapon = useGLTF(loadout.right, false, true);
const leftWeapon = useGLTF(loadout.left ?? loadout.right, false, true);
const rightWeapon = useGameGLTF(loadout.right);
const leftWeapon = useGameGLTF(loadout.left ?? loadout.right);
const rightHandSlot = resolveRigNode(actorScene, "handslot.r");
const leftHandSlot = resolveRigNode(actorScene, "handslot.l");
const rightWeaponScene = useMemo(
@@ -793,7 +832,8 @@ function AlternateBoss({ kind, bossIndex }: { kind: AlternateBossKind; bossIndex
const defeated = bossHp <= 0;
const group = useRef<THREE.Group>(null);
const light = useRef<THREE.PointLight>(null);
const gltf = useGLTF(config.url, false, true);
const assetUrl = selectedGameAssetUrl(config.url, config.optimizedUrl ?? config.url);
const gltf = useGameGLTF(assetUrl);
const { model, fadeMaterials } = useMemo(() => createBossRenderModel(gltf.scene), [gltf.scene]);
const { actions } = useAnimations(gltf.animations, model);
const targetPosition = useMemo(() => new THREE.Vector3(), []);
@@ -1184,23 +1224,27 @@ export function GameScene() {
camera={{ position: [0, 5.2, 12], fov: 48, near: 0.1, far: 70 }}
gl={{ alpha: false, antialias: false, powerPreference: "high-performance" }}
>
<SceneFrameScheduler dpr={dpr} onDprChange={setRenderDpr} />
<BossRoom />
<BossMechanicIndicators />
<BarrierField />
<TankAuraField />
<Party />
<BossActor />
<RangedProjectiles />
<CombatFx />
{PERFORMANCE_PROBE_ENABLED && <PerformanceProbe />}
<GameAssetProvider>
<SceneFrameScheduler dpr={dpr} onDprChange={setRenderDpr} />
<BossRoom />
<BossMechanicIndicators />
<BarrierField />
<TankAuraField />
<Party />
<BossActor />
<RangedProjectiles />
<CombatFx />
{PERFORMANCE_PROBE_ENABLED && <PerformanceProbe />}
</GameAssetProvider>
</Canvas>
);
}
for (const memberId of CRITICAL_PARTY_MEMBER_IDS) {
useGLTF.preload(PARTY_MODEL_URLS[memberId], false, true);
const loadout = PARTY_WEAPON_URLS[memberId];
useGLTF.preload(loadout.right, false, true);
if (loadout.left) useGLTF.preload(loadout.left, false, true);
if (LEGACY_GAME_ASSETS_FORCED) {
for (const memberId of CRITICAL_PARTY_MEMBER_IDS) {
useGLTF.preload(PARTY_MODEL_URLS[memberId], false, true);
const loadout = PARTY_WEAPON_URLS[memberId];
useGLTF.preload(loadout.right, false, true);
if (loadout.left) useGLTF.preload(loadout.left, false, true);
}
}