frontispiece / packages / ink-processor / src / binding / ink-binding.ts
ink-binding.ts
Raw
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

import { createEmptyVisualInkState } from '../data/visible-state'
import { InkStorySaveState, VisualInkState } from '../types'
import { InkStory } from '../inkTypes'

type InkStoryBinding = {
	inkStory: InkStory
	visualInkState: VisualInkState
}

export class InkBindingManager {
	protected story: InkStoryBinding
	protected listeners: InkBindingListenerInterface[] = []
	constructor(story: InkStory) {
		this.setInkStory(story)
	}

	addListener(listener: InkBindingListenerInterface) {
		this.listeners.push(listener)
	}

	removeListener(listener: InkBindingListenerInterface) {
		const index = this.listeners.indexOf(listener)
		if (index > -1) {
			this.listeners.splice(index, 1)
		}
	}

	setInkStory(story: InkStory) {
		this.story = {
			visualInkState: createEmptyVisualInkState(),
			inkStory: story,
		}

		for (let listener of this.listeners) {
			if (listener.setInkStory) {
				listener.setInkStory(story, this.story.visualInkState)
			}
		}
	}

	getInkStory() {
		return this.story.inkStory
	}

	getVisualInkState() {
		return this.story.visualInkState
	}

	/**
	 * Saves the new visualInkState into the binding and updates all listeners.
	 * @param visualInkState
	 */
	updateStoryVisualInkState(visualInkState: VisualInkState) {
		if (this.story.visualInkState === visualInkState) {
			return
		}
		this.story.visualInkState = visualInkState
		for (let listener of this.listeners) {
			if (listener.updateStoryVisualInkState) {
				listener.updateStoryVisualInkState(this.story.inkStory, visualInkState)
			}
		}
	}

	/**
	 * Exports the current story to a save state JSON object.
	 * @returns
	 */
	exportStory(): InkStorySaveState {
		const binding = this.story
		return {
			storyState: JSON.parse(binding.inkStory.state.ToJson()),
			visualInkState: { ...binding.visualInkState },
		}
	}

	/**
	 * Imports a save state JSON object and applies it to the current story.
	 * @param saveState
	 */
	importStory(saveState: InkStorySaveState) {
		const binding = this.story
		binding.inkStory.state.LoadJsonObj(saveState.storyState)
		this.updateStoryVisualInkState(saveState.visualInkState)
	}
}

export type InkBindingListenerCallback = (story: InkStory, visualInkState: VisualInkState) => void

export interface InkBindingListenerInterface {
	setInkStory?: InkBindingListenerCallback
	updateStoryVisualInkState?: InkBindingListenerCallback
}