refactor: 收口草稿打开状态规则
This commit is contained in:
@@ -349,8 +349,6 @@ import {
|
||||
buildCreationWorkShelfItems,
|
||||
type CreationWorkShelfItem,
|
||||
isPersistedBarkBattleDraftGenerating,
|
||||
isPersistedPuzzleDraftGenerating,
|
||||
resolvePuzzleWorkCoverImageSrc,
|
||||
} from '../custom-world-home/creationWorkShelf';
|
||||
import {
|
||||
buildPlatformRecommendFeedEntries,
|
||||
@@ -437,7 +435,6 @@ import {
|
||||
import {
|
||||
buildCreationWorkShelfRuntimeState,
|
||||
buildDraftCompletionDialogSource,
|
||||
buildDraftFailedShelfSummary,
|
||||
buildPendingBarkBattleWorks,
|
||||
buildPendingBigFishWorks,
|
||||
buildPendingJumpHopWorks,
|
||||
@@ -451,19 +448,17 @@ import {
|
||||
createPendingDraftShelfState,
|
||||
type DraftGenerationNoticeMap,
|
||||
type DraftGenerationNoticeStatus,
|
||||
getDraftGenerationNotice,
|
||||
getGenerationNoticeShelfKeys,
|
||||
hasDraftGenerationNoticeStatus,
|
||||
hasUnreadDraftGenerationUpdates,
|
||||
hasUnreadReadyDraftGenerationNotice,
|
||||
isPersistedDraftFailed,
|
||||
isPersistedDraftGenerating,
|
||||
mergeBigFishWorkSummary,
|
||||
mergePuzzleWorkSummary,
|
||||
normalizeDraftNoticeId,
|
||||
type PendingDraftShelfKind,
|
||||
type PendingDraftShelfMap,
|
||||
type PendingDraftShelfMetadata,
|
||||
resolveMatch3DDraftOpenIntent,
|
||||
resolvePuzzleDraftOpenIntent,
|
||||
} from './platformDraftGenerationShelfModel';
|
||||
import {
|
||||
canExposePublicWork,
|
||||
@@ -2012,26 +2007,11 @@ export function PlatformEntryFlowShellImpl({
|
||||
activePuzzleGenerationSessionIdRef.current === sessionId
|
||||
);
|
||||
}, []);
|
||||
const isDraftNoticeGenerating = useCallback(
|
||||
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
|
||||
hasDraftGenerationNoticeStatus(
|
||||
draftGenerationNotices,
|
||||
kind,
|
||||
ids,
|
||||
'generating',
|
||||
),
|
||||
[draftGenerationNotices],
|
||||
);
|
||||
const isDraftNoticeFailed = useCallback(
|
||||
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
|
||||
hasDraftGenerationNoticeStatus(draftGenerationNotices, kind, ids, 'failed'),
|
||||
[draftGenerationNotices],
|
||||
);
|
||||
const isDraftNoticeReadyUnread = useCallback(
|
||||
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
|
||||
hasUnreadReadyDraftGenerationNotice(draftGenerationNotices, kind, ids),
|
||||
[draftGenerationNotices],
|
||||
);
|
||||
const ensureEnoughDraftGenerationPointsFromServer = useCallback(
|
||||
async (pointsCost: number) => {
|
||||
try {
|
||||
@@ -10221,83 +10201,67 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
const openPuzzleDraft = useCallback(
|
||||
async (item: PuzzleWorkSummary) => {
|
||||
const noticeKeys = collectDraftNoticeKeys('puzzle', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
buildPuzzleResultWorkId(item.sourceSessionId),
|
||||
buildPuzzleResultProfileId(item.sourceSessionId),
|
||||
]);
|
||||
const failedNotice = getDraftGenerationNotice(
|
||||
draftGenerationNotices,
|
||||
noticeKeys,
|
||||
);
|
||||
const isPersistedFailed = isPersistedDraftFailed(item.generationStatus);
|
||||
const hasGeneratingNotice = isDraftNoticeGenerating('puzzle', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
buildPuzzleResultWorkId(item.sourceSessionId),
|
||||
buildPuzzleResultProfileId(item.sourceSessionId),
|
||||
]);
|
||||
const hasFailedNotice = isDraftNoticeFailed('puzzle', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
buildPuzzleResultWorkId(item.sourceSessionId),
|
||||
buildPuzzleResultProfileId(item.sourceSessionId),
|
||||
]);
|
||||
const noticeErrorMessage =
|
||||
failedNotice?.status === 'failed'
|
||||
? (failedNotice.message ?? buildDraftFailedShelfSummary('puzzle'))
|
||||
: buildDraftFailedShelfSummary('puzzle');
|
||||
const isMarkedGenerating =
|
||||
!hasFailedNotice &&
|
||||
((hasGeneratingNotice && !resolvePuzzleWorkCoverImageSrc(item)) ||
|
||||
isPersistedPuzzleDraftGenerating(item));
|
||||
const sourceSessionId = item.sourceSessionId?.trim() ?? '';
|
||||
const backgroundTask = sourceSessionId
|
||||
? getPuzzleBackgroundCompileTask(sourceSessionId)
|
||||
: null;
|
||||
const activeGenerationState =
|
||||
backgroundTask?.generationState ?? puzzleGenerationViewState;
|
||||
const openIntent = resolvePuzzleDraftOpenIntent({
|
||||
item,
|
||||
notices: draftGenerationNotices,
|
||||
generation: {
|
||||
activeSessionId: puzzleSession?.sessionId,
|
||||
hasActiveGenerationFailure:
|
||||
activeGenerationState?.phase === 'failed',
|
||||
hasActiveGenerationRunning: isMiniGameDraftGenerating(
|
||||
activeGenerationState ?? null,
|
||||
),
|
||||
hasBackgroundGenerationFailure:
|
||||
backgroundTask?.generationState.phase === 'failed',
|
||||
hasBackgroundGenerationRunning: isMiniGameDraftGenerating(
|
||||
backgroundTask?.generationState ?? null,
|
||||
),
|
||||
},
|
||||
});
|
||||
const { noticeKeys } = openIntent;
|
||||
setPuzzleOperation(null);
|
||||
setPuzzleRun(null);
|
||||
setPuzzleRuntimeAuthMode('default');
|
||||
setSelectedPuzzleDetail(null);
|
||||
if (!item.sourceSessionId?.trim()) {
|
||||
if (item.publicationStatus === 'published') {
|
||||
await openPuzzleDetail(item.profileId, { tab: 'create' });
|
||||
return;
|
||||
}
|
||||
|
||||
setPuzzleError('这份拼图草稿缺少会话信息,请重新开始创作。');
|
||||
if (openIntent.type === 'open-published-detail') {
|
||||
await openPuzzleDetail(item.profileId, { tab: 'create' });
|
||||
return;
|
||||
}
|
||||
|
||||
const backgroundTask = getPuzzleBackgroundCompileTask(
|
||||
item.sourceSessionId,
|
||||
);
|
||||
const activeGenerationState =
|
||||
backgroundTask?.generationState ?? puzzleGenerationViewState;
|
||||
const failedGenerationState =
|
||||
backgroundTask?.generationState.phase === 'failed'
|
||||
? backgroundTask.generationState
|
||||
: item.sourceSessionId === puzzleSession?.sessionId &&
|
||||
activeGenerationState?.phase === 'failed'
|
||||
? activeGenerationState
|
||||
: hasFailedNotice || isPersistedFailed
|
||||
? createFailedMiniGameDraftGenerationStateForRestoredDraft(
|
||||
if (openIntent.type === 'missing-session') {
|
||||
setPuzzleError(openIntent.errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (openIntent.type === 'failed-generation') {
|
||||
const failedGenerationState =
|
||||
openIntent.source === 'background'
|
||||
? backgroundTask?.generationState
|
||||
: openIntent.source === 'active'
|
||||
? activeGenerationState
|
||||
: createFailedMiniGameDraftGenerationStateForRestoredDraft(
|
||||
'puzzle',
|
||||
item.updatedAt,
|
||||
noticeErrorMessage,
|
||||
openIntent.errorMessage,
|
||||
{ puzzleAiRedraw: true },
|
||||
)
|
||||
: null;
|
||||
|
||||
if ((hasFailedNotice || isPersistedFailed) && failedGenerationState) {
|
||||
);
|
||||
if (!failedGenerationState) {
|
||||
return;
|
||||
}
|
||||
let failedSession = backgroundTask?.session ?? null;
|
||||
let failedPayload = backgroundTask?.payload ?? null;
|
||||
const failedError =
|
||||
backgroundTask?.error ?? failedNotice?.message ?? noticeErrorMessage;
|
||||
const failedError = backgroundTask?.error ?? openIntent.errorMessage;
|
||||
if (!failedSession) {
|
||||
try {
|
||||
const { session: latestSession } = await getPuzzleAgentSession(
|
||||
item.sourceSessionId,
|
||||
sourceSessionId,
|
||||
);
|
||||
failedSession = latestSession;
|
||||
failedPayload = buildPuzzleFormPayloadFromSession(latestSession);
|
||||
@@ -10330,16 +10294,13 @@ export function PlatformEntryFlowShellImpl({
|
||||
}
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'puzzle-generating';
|
||||
activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
|
||||
setPuzzleGenerationState(failedGenerationState);
|
||||
setSelectionStage('puzzle-generating');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
item.sourceSessionId === puzzleSession?.sessionId &&
|
||||
isMiniGameDraftGenerating(activeGenerationState)
|
||||
) {
|
||||
if (openIntent.type === 'active-generation') {
|
||||
if (!activeGenerationState) {
|
||||
return;
|
||||
}
|
||||
@@ -10347,7 +10308,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
rebaseMiniGameDraftGenerationStateForDisplay(activeGenerationState);
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'puzzle-generating';
|
||||
activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
|
||||
setPuzzleGenerationState(rebasedGenerationState);
|
||||
if (backgroundTask) {
|
||||
setPuzzleBackgroundCompileTasks((current) => ({
|
||||
@@ -10362,10 +10323,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
backgroundTask &&
|
||||
isMiniGameDraftGenerating(backgroundTask.generationState)
|
||||
) {
|
||||
if (openIntent.type === 'background-generation' && backgroundTask) {
|
||||
const rebasedTask =
|
||||
rebaseMiniGameDraftBackgroundCompileTaskForDisplay(backgroundTask);
|
||||
puzzleFlow.setSession(rebasedTask.session);
|
||||
@@ -10380,15 +10338,15 @@ export function PlatformEntryFlowShellImpl({
|
||||
}
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'puzzle-generating';
|
||||
activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
|
||||
setSelectionStage('puzzle-generating');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMarkedGenerating) {
|
||||
if (openIntent.type === 'restore-generating') {
|
||||
try {
|
||||
const { session: latestSession } = await getPuzzleAgentSession(
|
||||
item.sourceSessionId,
|
||||
sourceSessionId,
|
||||
);
|
||||
const payload = buildPuzzleFormPayloadFromSession(latestSession);
|
||||
const startedAtMs = resolveMiniGameDraftGenerationStartedAtMs(
|
||||
@@ -10424,7 +10382,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
}));
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'puzzle-generating';
|
||||
activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activePuzzleGenerationSessionIdRef.current = sourceSessionId;
|
||||
setSelectionStage('puzzle-generating');
|
||||
return;
|
||||
} catch (error) {
|
||||
@@ -10439,7 +10397,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
|
||||
const restoredSession = await puzzleFlow.restoreDraft(
|
||||
item.sourceSessionId,
|
||||
sourceSessionId,
|
||||
);
|
||||
if (!restoredSession) {
|
||||
await refreshPuzzleShelf().catch(() => undefined);
|
||||
@@ -10459,8 +10417,6 @@ export function PlatformEntryFlowShellImpl({
|
||||
enterCreateTab,
|
||||
draftGenerationNotices,
|
||||
getPuzzleBackgroundCompileTask,
|
||||
isDraftNoticeFailed,
|
||||
isDraftNoticeGenerating,
|
||||
markDraftNoticeSeen,
|
||||
openPuzzleDetail,
|
||||
puzzleFlow,
|
||||
@@ -10478,78 +10434,52 @@ export function PlatformEntryFlowShellImpl({
|
||||
item: Match3DWorkSummary,
|
||||
options: { forceDraft?: boolean } = {},
|
||||
) => {
|
||||
const noticeKeys = collectDraftNoticeKeys('match3d', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
]);
|
||||
const hasUnreadReadyNotice = isDraftNoticeReadyUnread('match3d', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
]);
|
||||
const sourceSessionId = item.sourceSessionId?.trim() ?? '';
|
||||
const backgroundTask = sourceSessionId
|
||||
? getMatch3DBackgroundCompileTask(sourceSessionId)
|
||||
: null;
|
||||
const activeGenerationState =
|
||||
backgroundTask?.generationState ?? match3dGenerationViewState;
|
||||
const openIntent = resolveMatch3DDraftOpenIntent({
|
||||
item,
|
||||
notices: draftGenerationNotices,
|
||||
forceDraft: options.forceDraft,
|
||||
generation: {
|
||||
activeSessionId: match3dSession?.sessionId,
|
||||
hasActiveGenerationFailure:
|
||||
activeGenerationState?.phase === 'failed',
|
||||
hasActiveGenerationRunning: isMiniGameDraftGenerating(
|
||||
activeGenerationState ?? null,
|
||||
),
|
||||
hasBackgroundGenerationFailure:
|
||||
backgroundTask?.generationState.phase === 'failed',
|
||||
hasBackgroundGenerationRunning: isMiniGameDraftGenerating(
|
||||
backgroundTask?.generationState ?? null,
|
||||
),
|
||||
},
|
||||
});
|
||||
const { noticeKeys } = openIntent;
|
||||
setMatch3DRun(null);
|
||||
setMatch3DError(null);
|
||||
setMatch3DProfile(null);
|
||||
setMatch3DRuntimeProfile(null);
|
||||
|
||||
if (item.publicationStatus === 'published' && !options.forceDraft) {
|
||||
if (openIntent.type === 'open-published-detail') {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
openPublicWorkDetail(mapMatch3DWorkToPublicWorkDetail(item));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.sourceSessionId?.trim()) {
|
||||
if (openIntent.type === 'missing-session') {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
setMatch3DError('这份抓大鹅草稿缺少会话信息,请重新开始创作。');
|
||||
setMatch3DError(openIntent.errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
const failedNotice = getDraftGenerationNotice(
|
||||
draftGenerationNotices,
|
||||
noticeKeys,
|
||||
);
|
||||
const hasFailedNotice = isDraftNoticeFailed('match3d', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
]);
|
||||
const noticeErrorMessage =
|
||||
failedNotice?.status === 'failed'
|
||||
? (failedNotice.message ?? buildDraftFailedShelfSummary('match3d'))
|
||||
: buildDraftFailedShelfSummary('match3d');
|
||||
const isMarkedGenerating =
|
||||
!hasFailedNotice &&
|
||||
(isDraftNoticeGenerating('match3d', [
|
||||
item.workId,
|
||||
item.profileId,
|
||||
item.sourceSessionId,
|
||||
]) ||
|
||||
isPersistedDraftGenerating(item.generationStatus));
|
||||
|
||||
const backgroundTask = getMatch3DBackgroundCompileTask(
|
||||
item.sourceSessionId,
|
||||
);
|
||||
const activeGenerationState =
|
||||
backgroundTask?.generationState ?? match3dGenerationViewState;
|
||||
const failedGenerationState =
|
||||
backgroundTask?.generationState.phase === 'failed'
|
||||
? backgroundTask.generationState
|
||||
: item.sourceSessionId === match3dSession?.sessionId &&
|
||||
activeGenerationState?.phase === 'failed'
|
||||
? activeGenerationState
|
||||
: hasFailedNotice
|
||||
? createFailedMiniGameDraftGenerationStateForRestoredDraft(
|
||||
'match3d',
|
||||
item.updatedAt,
|
||||
noticeErrorMessage,
|
||||
)
|
||||
: null;
|
||||
|
||||
if (hasUnreadReadyNotice) {
|
||||
if (openIntent.type === 'ready-unread') {
|
||||
try {
|
||||
const { session: latestSession } =
|
||||
await match3dCreationClient.getSession(item.sourceSessionId);
|
||||
await match3dCreationClient.getSession(sourceSessionId);
|
||||
setMatch3DSession(latestSession);
|
||||
setMatch3DFormDraftPayload(null);
|
||||
const profileId = latestSession.draft?.profileId ?? item.profileId;
|
||||
@@ -10577,15 +10507,27 @@ export function PlatformEntryFlowShellImpl({
|
||||
}
|
||||
}
|
||||
|
||||
if (failedGenerationState) {
|
||||
if (openIntent.type === 'failed-generation') {
|
||||
const failedGenerationState =
|
||||
openIntent.source === 'background'
|
||||
? backgroundTask?.generationState
|
||||
: openIntent.source === 'active'
|
||||
? activeGenerationState
|
||||
: createFailedMiniGameDraftGenerationStateForRestoredDraft(
|
||||
'match3d',
|
||||
item.updatedAt,
|
||||
openIntent.errorMessage,
|
||||
);
|
||||
if (!failedGenerationState) {
|
||||
return;
|
||||
}
|
||||
let failedSession = backgroundTask?.session ?? null;
|
||||
let failedPayload = backgroundTask?.payload ?? null;
|
||||
const failedError =
|
||||
backgroundTask?.error ?? failedNotice?.message ?? noticeErrorMessage;
|
||||
const failedError = backgroundTask?.error ?? openIntent.errorMessage;
|
||||
if (!failedSession) {
|
||||
try {
|
||||
const { session: latestSession } =
|
||||
await match3dCreationClient.getSession(item.sourceSessionId);
|
||||
await match3dCreationClient.getSession(sourceSessionId);
|
||||
failedSession = latestSession;
|
||||
failedPayload = buildMatch3DFormPayloadFromSession(latestSession);
|
||||
} catch {
|
||||
@@ -10617,16 +10559,13 @@ export function PlatformEntryFlowShellImpl({
|
||||
}
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'match3d-generating';
|
||||
activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activeMatch3DGenerationSessionIdRef.current = sourceSessionId;
|
||||
setMatch3DGenerationState(failedGenerationState);
|
||||
setSelectionStage('match3d-generating');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
item.sourceSessionId === match3dSession?.sessionId &&
|
||||
isMiniGameDraftGenerating(activeGenerationState)
|
||||
) {
|
||||
if (openIntent.type === 'active-generation') {
|
||||
if (!activeGenerationState) {
|
||||
return;
|
||||
}
|
||||
@@ -10634,7 +10573,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
rebaseMiniGameDraftGenerationStateForDisplay(activeGenerationState);
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'match3d-generating';
|
||||
activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activeMatch3DGenerationSessionIdRef.current = sourceSessionId;
|
||||
setMatch3DGenerationState(rebasedGenerationState);
|
||||
if (backgroundTask) {
|
||||
setMatch3DBackgroundCompileTasks((current) => ({
|
||||
@@ -10649,10 +10588,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
backgroundTask &&
|
||||
isMiniGameDraftGenerating(backgroundTask.generationState)
|
||||
) {
|
||||
if (openIntent.type === 'background-generation' && backgroundTask) {
|
||||
const rebasedTask =
|
||||
rebaseMiniGameDraftBackgroundCompileTaskForDisplay(backgroundTask);
|
||||
setMatch3DSession(rebasedTask.session);
|
||||
@@ -10667,15 +10603,15 @@ export function PlatformEntryFlowShellImpl({
|
||||
}
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'match3d-generating';
|
||||
activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activeMatch3DGenerationSessionIdRef.current = sourceSessionId;
|
||||
setSelectionStage('match3d-generating');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMarkedGenerating) {
|
||||
if (openIntent.type === 'restore-generating') {
|
||||
try {
|
||||
const { session: latestSession } =
|
||||
await match3dCreationClient.getSession(item.sourceSessionId);
|
||||
await match3dCreationClient.getSession(sourceSessionId);
|
||||
setMatch3DSession(latestSession);
|
||||
setMatch3DFormDraftPayload(null);
|
||||
setMatch3DProfile(null);
|
||||
@@ -10690,7 +10626,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
setMatch3DGenerationState(generationState);
|
||||
enterCreateTab();
|
||||
selectionStageRef.current = 'match3d-generating';
|
||||
activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
|
||||
activeMatch3DGenerationSessionIdRef.current = sourceSessionId;
|
||||
setSelectionStage('match3d-generating');
|
||||
return;
|
||||
} catch (error) {
|
||||
@@ -10705,7 +10641,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
|
||||
const restoredSession = await match3dFlow.restoreDraft(
|
||||
item.sourceSessionId,
|
||||
sourceSessionId,
|
||||
);
|
||||
if (!restoredSession) {
|
||||
await refreshMatch3DShelf().catch(() => undefined);
|
||||
@@ -10729,9 +10665,6 @@ export function PlatformEntryFlowShellImpl({
|
||||
enterCreateTab,
|
||||
draftGenerationNotices,
|
||||
getMatch3DBackgroundCompileTask,
|
||||
isDraftNoticeFailed,
|
||||
isDraftNoticeGenerating,
|
||||
isDraftNoticeReadyUnread,
|
||||
markDraftNoticeSeen,
|
||||
match3dFlow,
|
||||
match3dGenerationViewState,
|
||||
|
||||
Reference in New Issue
Block a user