prendy
Version:
Make games with prerendered backdrops using babylonjs and repond
229 lines (215 loc) • 8.39 kB
text/typescript
import { getState, setState } from "repond";
import { MyTypes } from "../declarations";
import { PrendySaveState } from "../stores/global/global";
import { point3dToVector3 } from "./babylonjs/vectors";
import { setDollPosition, springDollRotationY } from "./prendyHelpers/dolls";
import { goToNewPlace, showStoryView } from "./prendyHelpers/scene";
import { getGlobalState, setGlobalState } from "./prendyUtils/global";
import { waitForNextTick, waitForNowCamToChange, waitForPlaceFullyLoaded } from "./prendyUtils/scene";
import { CameraNameByPlace, PlaceName, SegmentNameByPlace } from "../types";
export function savePrendyState() {
const storeState = getState();
const newSaveState: PrendySaveState = {
global: {
nowCamName: storeState.global.main.nowCamName,
nowPlaceName: storeState.global.main.nowPlaceName,
nowSegmentName: storeState.global.main.nowSegmentName,
heldPickups: storeState.global.main.heldPickups,
storyOverlayToggled: storeState.global.main.storyOverlayToggled,
alarmTextIsVisible: storeState.global.main.alarmTextIsVisible,
alarmText: storeState.global.main.alarmText,
aSpeechBubbleIsShowing: storeState.global.main.aSpeechBubbleIsShowing,
aConvoIsHappening: storeState.global.main.aConvoIsHappening,
},
dolls: Object.fromEntries(
Object.entries(storeState.dolls).map(([dollName, doll]) => [
dollName,
{
position: doll.position,
rotationY: doll.rotationY,
isVisible: doll.isVisible,
// collisionsEnabled: doll.collisionsEnabled,
toggledMeshes: doll.toggledMeshes,
inRange: doll.inRange,
nowAnimation: doll.nowAnimation,
// animWeightsGoal: doll.animWeightsGoal,
},
])
),
places: Object.fromEntries(
Object.entries(storeState.places).map(([placeName, place]) => [
placeName,
{
toggledWalls: place.toggledWalls,
},
])
),
characters: Object.fromEntries(
Object.entries(storeState.characters).map(([characterName, character]) => [
characterName,
{
hasLeftFirstTrigger: character.hasLeftFirstTrigger,
},
])
),
player: {
animationNames: {
walking: storeState.players.main.animationNames.walking,
idle: storeState.players.main.animationNames.idle,
},
},
miniBubbles: Object.fromEntries(
Object.entries(storeState.miniBubbles).map(([miniBubbleName, miniBubble]) => [
miniBubbleName,
{
isVisible: miniBubble.isVisible,
text: miniBubble.text,
},
])
),
speechBubbles: Object.fromEntries(
Object.entries(storeState.speechBubbles).map(([speechBubbleName, speechBubble]) => [
speechBubbleName,
{
isVisible: speechBubble.isVisible,
goalText: speechBubble.goalText,
nowVideoName: speechBubble.nowVideoName,
font: speechBubble.font,
stylesBySpecialText: speechBubble.stylesBySpecialText,
forCharacter: speechBubble.forCharacter,
typingFinished: speechBubble.typingFinished,
},
])
),
storyState: { ...storeState.story.main }, // need to copy a new object, otherwise the reference is the same and the storyState is not saved
};
console.log("newSaveState", newSaveState);
setGlobalState({ latestSave: newSaveState });
// save newSaveState to localStorage
localStorage.setItem("prendySaveState", JSON.stringify(newSaveState));
}
export async function loadPrendyState() {
// const savedState: PrendySaveState = getGlobalState().latestSave;
// get latest save state from localStorage
const savedStateString = localStorage.getItem("prendySaveState");
if (!savedStateString) {
console.log("no saved state found in localStorage");
return;
}
const savedState: PrendySaveState = JSON.parse(savedStateString);
console.log("savedState", savedState);
await waitForNextTick();
await showStoryView(false);
const camWillChange = savedState.global.nowCamName !== getGlobalState().nowCamName;
// if the savedState.global.nowPlaceName is different from the current place, use the helepr to set the place
const placeWillChange = savedState.global.nowPlaceName !== getGlobalState().nowPlaceName;
if (placeWillChange) {
goToNewPlace({
toPlace: savedState.global.nowPlaceName as PlaceName,
toSegment: savedState.global.nowSegmentName as SegmentNameByPlace[PlaceName],
toCam: savedState.global.nowCamName as CameraNameByPlace[PlaceName],
});
await waitForPlaceFullyLoaded(savedState.global.nowPlaceName);
} else {
if (camWillChange && !placeWillChange) {
setState({
global: { main: { goalCamName: savedState.global.nowCamName } },
});
await waitForNowCamToChange(savedState.global.nowCamName);
}
}
// Set the doll positions manually, since setting the state will check for collisions
Object.entries(savedState.dolls).forEach(([dollName, doll]) => {
setDollPosition(dollName, point3dToVector3(doll.position));
springDollRotationY(dollName, doll.rotationY);
});
// Set the store state to the saved state
setState(
(state) => {
return {
global: {
main: {
goalCamName: savedState.global.nowCamName,
goalPlaceName: savedState.global.nowPlaceName,
goalSegmentName: savedState.global.nowSegmentName,
heldPickups: savedState.global.heldPickups,
storyOverlayToggled: savedState.global.storyOverlayToggled,
alarmTextIsVisible: savedState.global.alarmTextIsVisible,
alarmText: savedState.global.alarmText,
aSpeechBubbleIsShowing: savedState.global.aSpeechBubbleIsShowing,
aConvoIsHappening: savedState.global.aConvoIsHappening,
},
},
dolls: Object.fromEntries(
Object.entries(savedState.dolls).map(([dollName, doll]) => [
dollName,
{
toggledMeshes: doll.toggledMeshes,
isVisible: doll.isVisible,
// collisionsEnabled: doll.collisionsEnabled,
inRange: doll.inRange,
nowAnimation: doll.nowAnimation,
// animWeightsGoal: doll.animWeightsGoal,
},
])
),
places: Object.fromEntries(
Object.entries(savedState.places).map(([placeName, place]) => [
placeName,
{
toggledWalls: place.toggledWalls,
},
])
),
characters: Object.fromEntries(
Object.entries(savedState.characters).map(([characterName, character]) => [
characterName,
{
hasLeftFirstTrigger: character.hasLeftFirstTrigger,
},
])
),
players: {
main: {
animationNames: {
...state.players.main.animationNames,
walking: savedState.player.animationNames.walking,
idle: savedState.player.animationNames.idle,
},
},
},
miniBubbles: Object.fromEntries(
Object.entries(savedState.miniBubbles).map(([miniBubbleName, miniBubble]) => [
miniBubbleName,
{
// ...state.miniBubbles[miniBubbleName],
isVisible: miniBubble.isVisible,
text: miniBubble.text,
},
])
),
speechBubbles: Object.fromEntries(
Object.entries(savedState.speechBubbles).map(([speechBubbleName, speechBubble]) => [
speechBubbleName,
{
// ...state.speechBubbles[speechBubbleName],
isVisible: speechBubble.isVisible,
goalText: speechBubble.goalText,
nowVideoName: speechBubble.nowVideoName,
font: speechBubble.font,
stylesBySpecialText: speechBubble.stylesBySpecialText,
forCharacter: speechBubble.forCharacter,
typingFinished: speechBubble.typingFinished,
},
])
),
story: { main: savedState.storyState },
};
},
() => {
// setState({ global: { main: { latestLoadTime: Date.now() } } }, () => {
showStoryView(true);
// });
}
);
}