forked from phenom/healer-man
updating buff and debuff icons. separated COA classes from WoW classes on the character creation screen
This commit is contained in:
1 parent
b5c9bce1aa
commit
c00f3211ea
39 files changed
+2037
-208
No files matched your search
@@ -39,9 +39,11 @@ import { resolveContentUrl } from "../content/contentManager";
|
||||
import {
|
||||
selectCharacterBaseClip,
|
||||
selectCharacterEventClip,
|
||||
selectCharacterVerticalClip,
|
||||
type CharacterCombatAnimationEvent,
|
||||
type CharacterBaseMotion,
|
||||
} from "../game/combatAnimation";
|
||||
import type { CharacterVerticalMotion } from "../game/playerJump";
|
||||
import { AvatarErrorBoundary } from "./AvatarErrorBoundary";
|
||||
import {
|
||||
ATTACK_PRESENTATION_DURATION_SECONDS,
|
||||
@@ -77,6 +79,7 @@ export interface CharacterModelProps {
|
||||
identity: AvatarIdentity | null | undefined;
|
||||
active?: boolean;
|
||||
movingRef?: MutableRefObject<boolean>;
|
||||
verticalMotionRef?: MutableRefObject<CharacterVerticalMotion>;
|
||||
attackPulseRef?: MutableRefObject<number>;
|
||||
animationEventRef?: MutableRefObject<CharacterCombatAnimationEvent | null>;
|
||||
onReady?: () => void;
|
||||
@@ -88,6 +91,8 @@ export interface CharacterModelProps {
|
||||
|
||||
const EMPTY_EQUIPMENT: readonly InventoryItem[] = Object.freeze([]);
|
||||
|
||||
type CharacterLocomotionMotion = CharacterBaseMotion | Exclude<CharacterVerticalMotion, "grounded">;
|
||||
|
||||
type MappedMaterial = Material & { map?: Texture | null; color?: Color };
|
||||
|
||||
function configureMaterial(material: Material): void {
|
||||
@@ -164,6 +169,7 @@ function LoadedCharacterModel({
|
||||
identity,
|
||||
manifest,
|
||||
movingRef,
|
||||
verticalMotionRef,
|
||||
attackPulseRef,
|
||||
animationEventRef,
|
||||
onReady,
|
||||
@@ -176,6 +182,7 @@ function LoadedCharacterModel({
|
||||
identity: AvatarIdentity;
|
||||
manifest: AvatarManifest;
|
||||
movingRef?: MutableRefObject<boolean>;
|
||||
verticalMotionRef?: MutableRefObject<CharacterVerticalMotion>;
|
||||
attackPulseRef?: MutableRefObject<number>;
|
||||
animationEventRef?: MutableRefObject<CharacterCombatAnimationEvent | null>;
|
||||
onReady?: () => void;
|
||||
@@ -190,7 +197,7 @@ function LoadedCharacterModel({
|
||||
const overrideAction = useRef<AnimationAction | null>(null);
|
||||
const overrideTerminal = useRef(false);
|
||||
const overrideLooping = useRef(false);
|
||||
const currentMotion = useRef<CharacterBaseMotion | null>(null);
|
||||
const currentMotion = useRef<CharacterLocomotionMotion | null>(null);
|
||||
const observedAttackPulse = useRef(attackPulseRef?.current ?? 0);
|
||||
const equipmentAttackPulseRef = useRef(attackPulseRef?.current ?? 0);
|
||||
const observedAnimationRevision = useRef(animationEventRef?.current?.revision ?? 0);
|
||||
@@ -338,19 +345,27 @@ function LoadedCharacterModel({
|
||||
?? gltf.animations[0]
|
||||
);
|
||||
|
||||
const switchMotion = (motion: CharacterBaseMotion) => {
|
||||
const switchMotion = (motion: CharacterLocomotionMotion, moving: boolean) => {
|
||||
if (overrideAction.current) return;
|
||||
if (currentMotion.current === motion) return;
|
||||
const clip = selectClip(motion);
|
||||
const verticalSelection = motion === "rising" || motion === "falling" || motion === "landing"
|
||||
? selectCharacterVerticalClip(gltf.animations, motion, moving)
|
||||
: null;
|
||||
const fallbackMotion: CharacterBaseMotion = moving ? "run" : "idle";
|
||||
const clip = verticalSelection?.clip ?? selectClip(
|
||||
motion === "idle" || motion === "walk" || motion === "run" ? motion : fallbackMotion,
|
||||
);
|
||||
if (!clip) return;
|
||||
const loop = verticalSelection?.loop ?? true;
|
||||
const next = mixer.clipAction(clip, scene);
|
||||
if (currentAction.current !== next) {
|
||||
next.enabled = true;
|
||||
next.clampWhenFinished = false;
|
||||
next.setLoop(LoopRepeat, Number.POSITIVE_INFINITY).reset().fadeIn(0.16).play();
|
||||
currentAction.current?.fadeOut(0.16);
|
||||
currentAction.current = next;
|
||||
}
|
||||
next.enabled = true;
|
||||
next.clampWhenFinished = !loop;
|
||||
next.setLoop(loop ? LoopRepeat : LoopOnce, loop ? Number.POSITIVE_INFINITY : 1)
|
||||
.reset()
|
||||
.fadeIn(0.16)
|
||||
.play();
|
||||
if (currentAction.current !== next) currentAction.current?.fadeOut(0.16);
|
||||
currentAction.current = next;
|
||||
currentMotion.current = motion;
|
||||
};
|
||||
|
||||
@@ -415,7 +430,7 @@ function LoadedCharacterModel({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
switchMotion("idle");
|
||||
switchMotion("idle", false);
|
||||
return () => {
|
||||
mixer.stopAllAction();
|
||||
mixer.uncacheRoot(scene);
|
||||
@@ -439,6 +454,10 @@ function LoadedCharacterModel({
|
||||
useFrame((_, delta) => {
|
||||
if (!active) return;
|
||||
const moving = !preview && Boolean(movingRef?.current);
|
||||
const verticalMotion = preview ? "grounded" : verticalMotionRef?.current ?? "grounded";
|
||||
const locomotionMotion: CharacterLocomotionMotion = verticalMotion === "grounded"
|
||||
? moving ? "run" : "idle"
|
||||
: verticalMotion;
|
||||
const nextAnimationEvent = animationEventRef?.current;
|
||||
if (nextAnimationEvent && nextAnimationEvent.revision !== observedAnimationRevision.current) {
|
||||
observedAnimationRevision.current = nextAnimationEvent.revision;
|
||||
@@ -455,7 +474,7 @@ function LoadedCharacterModel({
|
||||
playAnimationEvent({ revision: nextAttackPulse, kind: "attack" });
|
||||
}
|
||||
}
|
||||
switchMotion(moving ? "run" : "idle");
|
||||
switchMotion(locomotionMotion, moving);
|
||||
|
||||
const safeDelta = Math.min(delta, 0.05);
|
||||
mixer.update(safeDelta);
|
||||
@@ -468,7 +487,7 @@ function LoadedCharacterModel({
|
||||
&& !overrideLooping.current
|
||||
&& !overrideAction.current.isRunning()
|
||||
) clearOverride();
|
||||
switchMotion(moving ? "run" : "idle");
|
||||
switchMotion(locomotionMotion, moving);
|
||||
const swing = attackSwingAt(attackElapsed.current);
|
||||
attackElapsed.current = Math.min(
|
||||
ATTACK_PRESENTATION_DURATION_SECONDS,
|
||||
@@ -514,6 +533,7 @@ export function CharacterModel({
|
||||
identity,
|
||||
active = true,
|
||||
movingRef,
|
||||
verticalMotionRef,
|
||||
attackPulseRef,
|
||||
animationEventRef,
|
||||
onReady,
|
||||
@@ -546,6 +566,7 @@ export function CharacterModel({
|
||||
identity={identity}
|
||||
manifest={manifest}
|
||||
movingRef={movingRef}
|
||||
verticalMotionRef={verticalMotionRef}
|
||||
attackPulseRef={attackPulseRef}
|
||||
animationEventRef={animationEventRef}
|
||||
onReady={onReady}
|
||||
|
||||
Reference in new issue
Block a user