Files
artcraft/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts
T
2024-03-30 01:00:18 +07:00

329 lines
8.6 KiB
TypeScript

import { useCallback, useState } from "react";
import {
Clip,
CharacterGroup,
ClipGroup,
ClipType,
MediaClip,
} from "~/pages/PageEnigma/models/track";
import * as uuid from "uuid";
import Queue from "~/pages/PageEnigma/Queue/Queue";
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
export default function useUpdateCharacters() {
const [characters, setCharacters] = useState<CharacterGroup[]>([
{
id: "CH1",
muted: false,
animationClips: [],
positionClips: [],
lipSyncClips: [],
},
]);
const updateCharacters = useCallback(
({
type,
id,
offset,
length,
}: {
type: "animations" | "positions" | "lipSync";
id: string;
length: number;
offset: number;
}) => {
if (type === "animations") {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
const newAnimationClips = [...character.animationClips];
const clipIndex = newAnimationClips.findIndex(
(row) => row.clip_uuid === id,
);
if (clipIndex === -1) {
return { ...character };
}
const clip = newAnimationClips[clipIndex];
clip.offset = offset;
clip.length = length;
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_CLIP,
data: clip,
});
return {
...character,
animationClips: newAnimationClips,
};
});
});
return;
}
if (type === "positions") {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
const newPositionClips = [...character.positionClips];
const clipIndex = newPositionClips.findIndex(
(row) => row.clip_uuid === id,
);
if (clipIndex === -1) {
return { ...character };
}
const clip = newPositionClips[clipIndex];
clip.offset = offset;
clip.length = length;
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_CLIP,
data: clip,
});
return {
...character,
positionClips: newPositionClips,
};
});
});
return;
}
if (type === "lipSync") {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
const newLipSyncClips = [...character.lipSyncClips];
const clipIndex = newLipSyncClips.findIndex(
(row) => row.clip_uuid === id,
);
if (clipIndex === -1) {
return { ...character };
}
const clip = newLipSyncClips[clipIndex];
clip.offset = offset;
clip.length = length;
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_CLIP,
data: clip,
});
return {
...character,
lipSyncClips: newLipSyncClips,
};
});
});
}
},
[],
);
const addCharacterAnimation = useCallback(
({
clipId,
characterId,
animationClips,
offset,
}: {
clipId: string;
characterId: string;
animationClips: MediaClip[];
offset: number;
}) => {
const clip = animationClips.find((row) => row.media_id === clipId);
if (!clip) {
return;
}
const clip_uuid = uuid.v4();
const newClip = {
...clip,
group: ClipGroup.CHARACTER,
offset,
clip_uuid,
object_uuid: characterId,
} as Clip;
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
if (character.id !== characterId) {
return { ...character };
}
return {
...character,
animationClips: [...character.animationClips, newClip].sort(
(clipA, clipB) => clipA.offset - clipB.offset,
),
};
});
});
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.ADD_CLIP,
data: newClip,
});
},
[],
);
const addCharacterAudio = useCallback(
({
clipId,
characterId,
audioClips,
offset,
}: {
clipId: string;
characterId: string;
audioClips: MediaClip[];
offset: number;
}) => {
const clip = audioClips.find((row) => row.media_id === clipId);
if (!clip) {
return;
}
const clip_uuid = uuid.v4();
const newClip = {
...clip,
type: ClipType.AUDIO,
group: ClipGroup.CHARACTER,
offset,
clip_uuid,
object_uuid: characterId,
} as Clip;
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
if (character.id !== characterId) {
return { ...character };
}
return {
...character,
lipSyncClips: [...character.lipSyncClips, newClip].sort(
(clipA, clipB) => clipA.offset - clipB.offset,
),
};
});
});
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.ADD_CLIP,
data: newClip,
});
},
[],
);
const toggleLipSyncMute = useCallback((characterId: string) => {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
if (character.id === characterId) {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: character?.muted
? toEngineActions.UNMUTE
: toEngineActions.MUTE,
data: {
version: 1,
type: ClipType.AUDIO,
group: ClipGroup.CHARACTER,
object_uuid: characterId,
},
});
}
return {
...character,
muted:
character.id === characterId ? !character.muted : character.muted,
};
});
});
}, []);
const selectCharacterClip = useCallback((clipId: string) => {
setCharacters((oldCharacters) => {
return [
...oldCharacters.map((character) => ({
...character,
animationClips: character.animationClips.map((clip) => ({
...clip,
selected:
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
})),
positionClips: character.positionClips.map((clip) => ({
...clip,
selected:
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
})),
lipSyncClips: character.lipSyncClips.map((clip) => ({
...clip,
selected:
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
})),
})),
];
});
}, []);
const deleteCharacterClip = useCallback((clipId: string) => {
setCharacters((oldCharacters) => {
return [
...oldCharacters.map((character) => ({
...character,
animationClips: character.animationClips.filter((clip) => {
if (clip.clip_uuid === clipId) {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.DELETE_CLIP,
data: clip!,
});
return false;
}
return true;
}),
positionClips: character.positionClips.filter((clip) => {
if (clip.clip_uuid === clipId) {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.DELETE_CLIP,
data: clip!,
});
return false;
}
return true;
}),
lipSyncClips: character.lipSyncClips.filter((clip) => {
if (clip.clip_uuid === clipId) {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.DELETE_CLIP,
data: clip!,
});
return false;
}
return true;
}),
})),
];
});
}, []);
return {
characters,
updateCharacters,
toggleLipSyncMute,
addCharacterAnimation,
addCharacterAudio,
selectCharacterClip,
deleteCharacterClip,
};
}