Make 3D cache save cancellable with flag

This commit is contained in:
Tanish Manku committed 2025-06-06 22:48:58 -07:00
1 parent 3de468389e
commit 72f960a5d4
3 files changed
+56 -30

No files matched your search

@@ -1,4 +1,4 @@
import { useState } from "react";
import { useState } from "react";
import {
faGear,
faImages,
@@ -23,19 +23,21 @@ import {
MenuIconSelector,
MenuIconItem,
} from "@storyteller/ui-menu-icon-selector";
import { signal } from "@preact/signals-react";
import { signal } from "@preact/signals-react";
import { useSignals } from "@preact/signals-react/runtime";
import { setLogoutStates } from "~/signals/authentication/utilities";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useTabStore } from "~/pages/Stores/TabState";
import { set3DPageMounted } from "~/pages/PageEnigma/Editor/editor";
import {
is3DEditorInitialized,
is3DSceneLoaded,
set3DPageMounted,
} from "~/pages/PageEnigma/Editor/editor";
interface Props {
pageName: string;
}
const appMenuTabs: MenuIconItem[] = [
{
id: "2D",
@@ -62,9 +64,7 @@ const appMenuTabs: MenuIconItem[] = [
export const topNavMediaId = signal<string>("");
export const topNavMediaUrl = signal<string>("");
export const TopBar = ({
pageName
}: Props) => {
export const TopBar = ({ pageName }: Props) => {
useSignals();
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
@@ -73,9 +73,19 @@ export const TopBar = ({
galleryModalVisibleViewMode.value = true;
galleryModalVisibleDuringDrag.value = true;
};
const tabStore = useTabStore();
const is3DSceneReady = is3DSceneLoaded.value;
const is3DEditorReady = is3DEditorInitialized.value;
const disableTabSwitcher = () => {
return (
useTabStore.getState().activeTabId === "3D" &&
!is3DEditorReady &&
!is3DSceneReady
);
};
return (
<>
<header className="fixed left-0 top-0 z-[60] w-full border-b border-white/5 bg-ui-background">
@@ -95,7 +105,7 @@ export const TopBar = ({
<MenuIconSelector
menuItems={appMenuTabs}
activeMenu={tabStore.activeTabId}
disabled={false}
disabled={disableTabSwitcher()}
onMenuChange={(tabId) => {
// Disable 3d engine to prevent memory leak.
if (tabId === "3D") {
@@ -103,9 +113,7 @@ export const TopBar = ({
} else {
set3DPageMounted(false);
}
useTabStore
.getState()
.setActiveTab(tabId);
useTabStore.getState().setActiveTab(tabId);
}}
className="w-fit"
/>
@@ -158,10 +166,7 @@ export const TopBar = ({
globalAccountLogoutCallback={() => setLogoutStates()}
/>
<GalleryModal
mode="view"
onDownloadClicked={downloadFileFromUrl}
/>
<GalleryModal mode="view" onDownloadClicked={downloadFileFromUrl} />
</>
);
};
@@ -63,15 +63,24 @@ export type EditorInitializeConfig = {
};
// ONLY USED IN THIS CLASS
// Need this one to ensure the canvas is inflated and non-zero sized
const is3DPageMounted = signal(false);
export const set3DPageMounted = (isMounted: boolean) => {
is3DPageMounted.value = isMounted;
};
// Need this one to know when the engine has initialized (but not necessarily loaded saves)
export const is3DEditorInitialized = signal(false);
export const setIs3DEditorInitialized = (isInitialized: boolean) => {
is3DEditorInitialized.value = isInitialized;
};
// Need this one to know when the engine is done loading stuff into the scene for display
export const is3DSceneLoaded = signal(false);
export const setIs3DSceneLoaded = (isLoaded: boolean) => {
is3DSceneLoaded.value = isLoaded;
};
class Editor {
version: number;
activeScene: Scene;
@@ -660,10 +669,15 @@ class Editor {
// Attach freecam state controller
this.mouseOverEventHandler = this.mouseOverEventHandler.bind(this);
const onloadCallback = () => {
console.log("Setting Scene is loaded");
setIs3DSceneLoaded(true);
};
if (!this.utils.isEmpty(cacheJson)) {
this.loadCache(cacheJson);
this.loadCache(cacheJson).then(onloadCallback);
} else if (!this.utils.isEmpty(sceneToken)) {
this.loadScene(sceneToken);
this.loadScene(sceneToken).then(onloadCallback);
} else {
signalScene({
title: "Untitled New Scene",
@@ -671,6 +685,7 @@ class Editor {
ownerToken: authentication.userInfo.value?.user_token,
isModified: false,
});
onloadCallback();
}
this._configurePostProcessingRaw();
@@ -1484,6 +1499,7 @@ class Editor {
}
unmountEngine() {
setIs3DSceneLoaded(false);
this.stopRenderLoop();
this.sceneManager?.detachEventListeners();
this.disableFreeCamControls();
@@ -1496,6 +1512,7 @@ class Editor {
this.rawRenderer?.dispose();
this.isMounted = false;
setIs3DEditorInitialized(false);
console.log("3D Editor Engine unmounted");
}
@@ -1,7 +1,7 @@
import { ReactNode, useEffect, useRef, useState } from "react";
import { EngineContext } from "./EngineContext";
import Editor from "~/pages/PageEnigma/Editor/editor";
import Editor, { is3DSceneLoaded } from "~/pages/PageEnigma/Editor/editor";
import { useSignals } from "@preact/signals-react/runtime";
import { signal } from "@preact/signals-react";
@@ -59,16 +59,20 @@ export const EngineProvider = ({ sceneToken, children }: Props) => {
}
// If the tab is changed, cache state, unmount the editor and clear all input params
const sceneGenerationMetadata = getSceneGenerationMetaData(
activeEditorRef.current,
);
const cacheJson = activeEditorRef.current.cacheScene({
sceneTitle: "",
sceneToken: "",
sceneGenerationMetadata: sceneGenerationMetadata,
});
const cacheString = JSON.stringify(cacheJson);
tabStore.updateTabData("3D", cacheString);
// This condition makes sure the editor saves a fully loaded scene so it doesn't lose data
// If the load was incomplete, we'll preserve the last cache anyway.
if (is3DSceneLoaded.peek()) {
const sceneGenerationMetadata = getSceneGenerationMetaData(
activeEditorRef.current,
);
const cacheJson = activeEditorRef.current.cacheScene({
sceneTitle: "",
sceneToken: "",
sceneGenerationMetadata: sceneGenerationMetadata,
});
const cacheString = JSON.stringify(cacheJson);
tabStore.updateTabData("3D", cacheString);
}
// Unmount/Destructor flow
activeEditorRef.current?.unmountEngine();