{"version":3,"file":"87e501d328279d7565a3.chunk.js","mappings":"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","sources":["webpack://ch.enlightware.gamecreator/./src/blocks/actions/sound/sound.ts","webpack://ch.enlightware.gamecreator/./src/game/constants.ts","webpack://ch.enlightware.gamecreator/./src/game/game-saver.ts","webpack://ch.enlightware.gamecreator/./src/screen/screen-manager.ts","webpack://ch.enlightware.gamecreator/./src/screen/screen.ts","webpack://ch.enlightware.gamecreator/./src/storage/asset-loader.ts","webpack://ch.enlightware.gamecreator/./src/storage/asset-manager.ts","webpack://ch.enlightware.gamecreator/./src/storage/asset-saver.ts","webpack://ch.enlightware.gamecreator/./src/storage/asset-serializer.ts","webpack://ch.enlightware.gamecreator/./src/storage/db.ts","webpack://ch.enlightware.gamecreator/./src/storage/http-db.ts","webpack://ch.enlightware.gamecreator/./src/storage/rust-db.ts","webpack://ch.enlightware.gamecreator/./src/utils/uri.ts"],"sourcesContent":["/**\n * @module block-sound\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { decodeAudioData, getAudioContext } from 'runtime/runtime-audio';\nimport { Sound, SoundInterface } from './sound-interface';\n\nexport function createFallbackSound() {\n\tconst buffer = new AudioBuffer({\n\t\tlength: 24000,\n\t\tsampleRate: 48000\n\t});\n\tconst data = buffer.getChannelData(0);\n\t// fill the buffer with a sinus at 440 Hz\n\tfor (let i = 0; i < data.length; i++) {\n\t\tdata[i] = Math.sin(2 * Math.PI * 440 * i / buffer.sampleRate);\n\t}\n\treturn new WebAudioSound(buffer);\n}\n\nexport function packWav(samples: Float32Array, sampleRate: number) {\n\t// create wav file buffer\n\tconst fileSize = samples.length * 2 + 44;\n\tconst wavData = new Uint8Array(fileSize);\n\t// helpers to fill wavData buffer\n\tconst fillText = (offset: number, text: string) => {\n\t\tfor (let i = 0; i < text.length; i++) {\n\t\t\twavData[offset + i] = text.charCodeAt(i);\n\t\t}\n\t};\n\tconst fillUint32 = (offset: number, value: number) => {\n\t\twavData[offset + 0] = (value >> 0) & 0xff;\n\t\twavData[offset + 1] = (value >> 8) & 0xff;\n\t\twavData[offset + 2] = (value >> 16) & 0xff;\n\t\twavData[offset + 3] = (value >> 24) & 0xff;\n\t};\n\tconst fillUint16 = (offset: number, value: number) => {\n\t\twavData[offset + 0] = (value >> 0) & 0xff;\n\t\twavData[offset + 1] = (value >> 8) & 0xff;\n\t};\n\t// RIFF header\n\tfillText(0, 'RIFF');\n\tfillUint32(4, fileSize - 8);\n\tfillText(8, 'WAVE');\n\t// format chunk\n\tfillText(12, 'fmt ');\n\tfillUint32(16, 16); // Size of format chunk\n\tfillUint16(20, 1); // Type of format (1 is PCM)\n\tfillUint16(22, 1); // Number of Channels\n\tfillUint32(24, sampleRate); // Sample Rate\n\tfillUint32(28, sampleRate * 2); // Byte Rate\n\tfillUint16(32, 2); // Block Align\n\tfillUint16(34, 16); // Bits per sample\n\t// data chunk\n\tfillText(36, 'data');\n\tfillUint32(40, samples.length * 2); // Size of data chunk\n\tlet maxValue = 0.25;\n\tsamples.forEach(sample => {\n\t\tmaxValue = Math.max(Math.max(sample, maxValue), -sample);\n\t});\n\tconst destArray = new Int16Array(wavData.buffer, 44);\n\tsamples.forEach((sample, i) => {\n\t\tdestArray[i] = (sample / maxValue) * 0x7fff;\n\t});\n\treturn wavData;\n}\n\nexport class WebAudioSound implements Sound {\n\tconstructor(private readonly buffer: AudioBuffer) {}\n\n\tconnectToAudioNodeAndPlay(ctx: AudioContext, node: AudioNode) {\n\t\tconst source = ctx.createBufferSource();\n\t\tsource.buffer = this.buffer;\n\t\tsource.connect(node);\n\t\tsource.start();\n\t}\n\n\tgetSamplesAndRate(): [Float32Array, number] {\n\t\tconst output = new Float32Array(this.buffer.length);\n\t\tthis.buffer.copyFromChannel(output, 0);\n\t\treturn [output, this.buffer.sampleRate];\n\t}\n\n\tclone() {\n\t\treturn new WebAudioSound(this.buffer);\n\t}\n}\n\nexport class WebAudioSoundSystem implements SoundInterface {\n\tconstructor(private audioCtx: AudioContext) {}\n\n\tasync decodeSound(data: ArrayBuffer): Promise {\n\t\tconst buffer = await decodeAudioData(this.audioCtx, data);\n\t\treturn new WebAudioSound(buffer);\n\t}\n\n\tplaySound(sound: Sound, gain: number, pan: number): void {\n\t\tconst gainNode = this.audioCtx.createGain();\n\t\tgainNode.gain.value = gain;\n\t\tconst panNode = this.audioCtx.createStereoPanner();\n\t\tpanNode.pan.value = pan;\n\t\tgainNode.connect(panNode).connect(this.audioCtx.destination);\n\t\tsound.connectToAudioNodeAndPlay(this.audioCtx, gainNode);\n\t}\n}\n\nexport class FakeSound implements Sound {\n\tconnectToAudioNodeAndPlay(_ctx: AudioContext, _node: AudioNode): void {\n\t\tconsole.debug('Fake sound requested to play');\n\t}\n\n\tgetSamplesAndRate(): [Float32Array, number] {\n\t\treturn [new Float32Array(), 48000];\n\t}\n}\n\nclass FakeSoundSystem implements SoundInterface {\n\tconstructor() {\n\t\tconsole.info('Creating fake sound system object');\n\t}\n\n\tdecodeSound(data: ArrayBuffer): Promise {\n\t\tconsole.log(`Fake decoding sound from ${data.byteLength} bytes`);\n\t\treturn Promise.resolve(new FakeSound());\n\t}\n\n\tplaySound(_sound: Sound, gain: number, pan: number): void {\n\t\tconsole.log(`Fake playing sound with gain ${gain} and pan ${pan}`);\n\t}\n}\n\nlet soundSystem: SoundInterface | null = null;\n\nexport function getSoundSystem(forceFake = false) {\n\tif (soundSystem === null) {\n\t\tconst audioCtx = getAudioContext();\n\t\tsoundSystem = (audioCtx !== null && !forceFake) ?\n\t\t\tnew WebAudioSoundSystem(audioCtx) :\n\t\t\tnew FakeSoundSystem();\n\t}\n\treturn soundSystem;\n}","/**\n * @module game\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\n/** Default scale of the editor */\nexport const EditorDefaultScale = 1e2;\n/** Default extent of the runtime camera */\nexport const CameraDefaultExtent = 4.0;\n/** Default background color */\nexport const CameraDefaultBackgroundColor = '#bde3ff';\n/** Default intensity of gravity */\nexport const LevelDefaultGravity = 10;\n/** Default air friction */\nexport const LevelDefaultAirFriction = 0.02;\n/** Default stickiness of object types */\nexport const ObjectTypeDefaultStickiness = 0.2;\n/** Default bounciness of object types */\nexport const ObjectTypeDefaultBounciness = 0;\n/** Default density of object types */\nexport const ObjectTypeDefaultDensity = 1;\n\n/** Margin to existing objects after which an object will be deleted, additive constant component */\nexport const WorldWindowMarginConstant = 10.0;\n/** Margin to existing objects after which an object will be deleted, additive component proportional to largest object size */\nexport const WorldWindowMarginProportional = 3.0;\n\n/** The size of the game miniature preview */\nexport const MiniatureSize = 192;\n","/**\n * @module game\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { downcast } from 'utils/types';\nimport { MiniatureSize } from './constants';\nimport { Game, CanvasWithKey, SoundWithKey, generateGameStringId } from './game';\nimport { createOffscreenCanvasAnd2DContext } from 'utils/canvas';\nimport { AnyCanvas } from 'imgui/imgui-types';\nimport { Storage, GameSaveResult } from 'storage/storage';\nimport { canvasTextFont } from 'vpl/vpl-typography';\n\nexport class GameMetaDataCanvas {\n\tconstructor(public readonly id: string, public miniature: AnyCanvas, public name: string | null) {\n\t}\n\n\tstatic create(game: Game) {\n\t\tconst miniature = game.getMiniature(MiniatureSize);\n\t\tconst metadata = new GameMetaDataCanvas(game.id, miniature, game.name);\n\t\t// logCanvas(`Created miniature for game ${game.id} with id ${StableObjectId.get(metadata.miniature)}`, miniature);\n\t\treturn metadata;\n\t}\n\n\tstatic createWithUnknownMiniature(gameKey: string) {\n\t\tconst size = MiniatureSize;\n\t\tconst { canvas, ctx } = createOffscreenCanvasAnd2DContext(size, size);\n\t\tctx.fillStyle = 'gray';\n\t\tctx.fillRect(0, 0, size, size);\n\t\tctx.font = canvasTextFont(160);\n\t\tctx.fillStyle = 'white';\n\t\tctx.fillText('?', 60, 160);\n\t\tconst metadata = new GameMetaDataCanvas(gameKey, canvas, null);\n\t\treturn metadata;\n\t}\n}\n\nexport type GameStorer = (serialisedGame: Uint8Array, metaData: GameMetaDataCanvas) => GameSaveResult;\n\nexport function saveGameWithStorer(\n\tgame: Game,\n\tstorage: Storage,\n\tstorer: GameStorer\n): GameSaveResult {\n\t// Generate serializable versions of the two things to store: Game, GameMetaData\n\tconst gameKey = game.id;\n\tconsole.info(`Saving game \"${game.name ?? 'unnamed'}\" as ${gameKey}`);\n\tconst [serialisedGame, imageIndices] = game.asUint8ArrayWithAssetUUID();\n\tstorage.imageAssets.registerAssets(\n\t\t[...imageIndices.keys()].map(\n\t\t\tdrawable => downcast(CanvasWithKey, drawable)\n\t\t)\n\t);\n\tstorage.soundAssets.registerAssets(\n\t\tgame.sounds.map(\n\t\t\tsound => downcast(SoundWithKey, sound)\n\t\t)\n\t);\n\tconst gameMetaData = GameMetaDataCanvas.create(game);\n\treturn storer(serialisedGame, gameMetaData);\n}\n\nexport function saveNewBinaryGameWithStorer(\n\tserialisedGame: Uint8Array,\n\tstorer: GameStorer\n): GameSaveResult {\n\tconst gameKey = generateGameStringId();\n\tconst gameMetaData = GameMetaDataCanvas.createWithUnknownMiniature(gameKey);\n\treturn storer(serialisedGame, gameMetaData);\n}\n","/**\n * @module screen\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { reportLog } from 'apps/common/analytics';\nimport { defined } from 'utils/types';\nimport { Screen, ScreenDescription } from './screen';\n\nclass ScreenManager {\n\tscreenChangedCallback = (_before: Screen | null, _after: Screen | null) => {};\n\tprivate stack: Screen[] = [];\n\tprivate reportUnload: () => void;\n\n\tconstructor() {\n\t\tthis.reportUnload = () =>reportLog('unload', this.peek()?.name ?? null);\n\t\twindow.addEventListener('unload', this.reportUnload);\n\t}\n\n\tcancelReportUnload() {\n\t\twindow.removeEventListener('unload', this.reportUnload);\n\t}\n\n\tpublic peek() {\n\t\treturn this.stack[this.stack.length - 1];\n\t}\n\n\t/**\n\t * Push a screen on the screen stack.\n\t * @param s The screen to push\n\t * @param show If true, switch to the new screen, if false, keep current screen. That is useful when more than one screens are pushed one after the other. Default: true\n\t */\n\tpublic push(s: Screen, show = true) {\n\t\tconst before = this.peek() ?? null;\n\t\tthis.pushAndNotify(s);\n\t\tif (show) {\n\t\t\tthis.doTransitionAndRetNewTop(before, s);\n\t\t}\n\t}\n\n\tprotected pushAndNotify(s: Screen) {\n\t\tthis.stack.push(s);\n\t\tthis.updateCliObject();\n\t\ts.pushed();\n\t}\n\n\tprotected popAndNotify() {\n\t\tconst s = defined(this.peek());\n\t\tthis.stack.pop();\n\t\tthis.updateCliObject();\n\t\ts.popped();\n\t}\n\n\tpublic popEvenIfLast(): Screen | null {\n\t\tif (this.stack.length > 1) {\n\t\t\tconst before = this.peek()!;\n\t\t\tthis.popAndNotify();\n\t\t\tconst after = this.peek()!;\n\t\t\treturn this.doTransitionAndRetNewTop(before, after);\n\t\t} else if (this.stack.length === 1) {\n\t\t\tconst last = this.stack[0]!;\n\t\t\tconsole.debug('ScreenManager: Popping last screen from', last.name);\n\t\t\tlast.hide(null);\n\t\t\tthis.screenChangedCallback(last, null);\n\t\t\treturn null;\n\t\t} else {\n\t\t\tthrow new Error('ScreenManager: No element in stack!');\n\t\t}\n\t}\n\n\tpublic pop(): Screen {\n\t\tconst newScreen = this.popEvenIfLast();\n\t\tif (newScreen !== null) {\n\t\t\treturn newScreen;\n\t\t}\n\t\tthrow new Error('ScreenManager: Popping last element of the screen stack is an error!');\n\t}\n\n\tpublic replaceWith(s: Screen) {\n\t\tconst before = this.peek() ?? null;\n\t\tif (before !== null) {\n\t\t\tthis.popAndNotify();\n\t\t}\n\t\tthis.pushAndNotify(s);\n\t\tthis.doTransitionAndRetNewTop(before, s);\n\t}\n\n\tpublic get screens(): ScreenDescription[] {\n\t\treturn this.stack.map((screen) => screen.description);\n\t}\n\n\tprivate doTransitionAndRetNewTop(before: Screen | null, after: Screen) {\n\t\tif (before) {\n\t\t\tconsole.debug('ScreenManager: Transition from', before.name, 'to', after.name);\n\t\t\tbefore.hide(after);\n\t\t} else {\n\t\t\tconsole.debug('ScreenManager: Transition to', after.name);\n\t\t}\n\t\tafter.show(before);\n\t\tthis.screenChangedCallback(before, after);\n\t\treturn after;\n\t}\n\n\tprivate updateCliObject() {\n\t\t(window as any).cli = this.peek()?.cli ?? null;\n\t}\n}\n\nexport const screenManager = new ScreenManager();\n","/**\n * A stack-based screen system.\n * @module screen\n * @preferred\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { JSONValue } from 'utils/json-value';\n\n/**\n * Description of a screen, for app state restoration later on.\n */\nexport interface ScreenDescription {\n\tname: string,\n\tparameters: JSONValue\n}\n\n/**\n * A Screen can be shown and hidden, and stacked using the ScreenManager.\n */\nexport class Screen {\n\tprivate resizeEventListener: () => void;\n\tprivate keyDownEventListener: (event: KeyboardEvent) => void;\n\tprivate keyUpEventListener: (event: KeyboardEvent) => void;\n\tprivate visibilityChangedListener: () => void;\n\n\t/**\n\t * Builds a new screen using an HTML element as root.\n\t */\n\tconstructor(protected element: HTMLElement) {\n\t\tthis.resizeEventListener = this.resized.bind(this);\n\t\tthis.keyDownEventListener = this.keyDown.bind(this);\n\t\tthis.keyUpEventListener = this.keyUp.bind(this);\n\t\tthis.visibilityChangedListener = this.visibilityChanged.bind(this);\n\t}\n\n\t/**\n\t * Name of the screen, by default, the HTML element id\n\t */\n\tget name(): string { return this.element.id; }\n\n\t/**\n\t * Whether this screen is currently visible (i.e. on top of the stack)\n\t */\n\tget visible(): boolean { return this.element.style.display !== 'none'; }\n\n\t/**\n\t * The Command Line Interface (in browser console) associated with this screen\n\t */\n\tget cli(): object | null { return null };\n\n\t/**\n\t * Parameters of a screen, for restoration\n\t */\n\tprotected get parameters(): JSONValue { return {}; }\n\n\t/**\n\t * Description of a screen, for restoration\n\t */\n\tget description(): ScreenDescription {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tparameters: this.parameters\n\t\t};\n\t}\n\n\t/**\n\t * Hides this screen.\n\t * Sets the underlying HTML element's display property to \"none\", and removes key, resize and visibility listeners.\n\t */\n\tpublic hide(to: Screen | null) {\n\t\tthis.element.style.display = 'none';\n\t\twindow.removeEventListener('resize', this.resizeEventListener);\n\t\tdocument.removeEventListener('keydown', this.keyDownEventListener);\n\t\tdocument.removeEventListener('keyup', this.keyUpEventListener);\n\t\tdocument.removeEventListener('visibilitychange', this.visibilityChangedListener);\n\t}\n\n\t/**\n\t * Shows this screen.\n\t * Sets the underlying HTML element's display property to \"\", and adds key, resize and visibility listeners.\n\t */\n\tpublic show(from: Screen | null) {\n\t\tthis.element.style.display = '';\n\t\tthis.resized();\n\t\twindow.addEventListener('resize', this.resizeEventListener);\n\t\tdocument.addEventListener('keydown', this.keyDownEventListener);\n\t\tdocument.addEventListener('keyup', this.keyUpEventListener);\n\t\tdocument.addEventListener('visibilitychange', this.visibilityChangedListener);\n\t}\n\n\t/**\n\t * Callback when screen is removed from the screen stack\n\t */\n\tpopped() {}\n\n\t/**\n\t * Callback when screen is added to the screen stack\n\t */\n\tpushed() {}\n\n\t/**\n\t * Callback upon resize events.\n\t */\n\tprotected resized(): void {}\n\n\t/**\n\t * Callback upon keydown events.\n\t */\n\tprotected keyDown(event: KeyboardEvent): void {}\n\n\t/**\n\t * Callback upon keyup events.\n\t */\n\tprotected keyUp(event: KeyboardEvent): void {}\n\n\t/**\n\t * Callback when page has just become hidden\n\t */\n\tprotected appHidden() {}\n\n\t/**\n\t * Callback when page has just become visible\n\t */\n\tprotected appVisible() {}\n\n\tprivate visibilityChanged() {\n\t\tif (document.hidden) {\n\t\t\tthis.appHidden();\n\t\t} else {\n\t\t\tthis.appVisible();\n\t\t}\n\t}\n}\n","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { AssetManager, keyToRaw, keyToText } from './asset-manager';\nimport { Asset, AssetKey } from 'game/game';\nimport { ApiError, BlobWithContentType } from 'network/api-types';\nimport { reportError } from 'apps/common/analytics';\nimport { assert, assertFalse, AssertionError, assertNonNull } from 'utils/assert';\nimport { KeyValueMap } from 'storage/db';\nimport { BacklogInterface } from 'storage/backlog';\n\nfunction reportAssetError(key: string, contentType: string, e: any) {\n\tif (e instanceof ApiError && e.statusCode === 404) {\n\t\treportError('assetLost', `Lost asset ${key} of type ${contentType}`, e);\n\t} else if (e instanceof AssertionError) {\n\t\treportError('assetTypeError', `Loaded wrong asset type ${key}, expected type ${contentType}`, e);\n\t} else if (typeof(e) === 'string') { // Rust decoder sends a simple string as error\n\t\treportError('assetDecodeFailed', `Failed to decode asset ${key} of type ${contentType}`, new Error(e));\n\t} else {\n\t\treportError('assetLoadFailed', `Failed to load or decode asset ${key} of type ${contentType}`, e);\n\t\t// We assume temporary error (e.g. 5xx status code) and fail the game load. This give the user the opportunity to try a reload.\n\t\tthrow e;\n\t}\n\tconsole.warn(`Replacing broken asset ${key} of type ${contentType} with fallback, due to this error:`, e);\n}\n\n/// An asset manager that only supports loading assets.\nexport class AssetLoader implements AssetManager {\n\tprotected keyToAsset = new Map();\n\n\tconstructor(\n\t\tprotected readonly assetDb: KeyValueMap,\n\t\t_assetsBacklog: BacklogInterface,\n\t\tprotected readonly contentType: string,\n\t\tprotected decodeFunction: (rawAsset: ArrayBuffer, rawKey: AssetKey, contentType: string) => Promise,\n\t\tprotected loadFallbackFunction: (key: string) => T\n\t)\n\t{}\n\n\t/// Load asset from cache or user-load function, but do not *not* check backlog.\n\tasync loadAsset(key: string | ArrayBuffer): Promise {\n\t\tconst textKey = keyToText(key);\n\t\tconst cachedAsset = this.keyToAsset.get(textKey);\n\t\tif (cachedAsset !== undefined) {\n\t\t\treturn cachedAsset;\n\t\t}\n\t\tlet asset;\n\t\ttry {\n\t\t\tconst assetData = await this.assetDb.get(textKey);\n\t\t\tassertNonNull(assetData.contentType, 'Asset content type must be defined');\n\t\t\tconst rawKey = keyToRaw(key);\n\t\t\tasset = await this.decodeFunction(assetData.value, rawKey, assetData.contentType);\n\t\t} catch (e: any) {\n\t\t\treportAssetError(textKey, this.contentType, e);\n\t\t\tasset = this.loadFallbackFunction(textKey);\n\t\t}\n\t\tthis.memorizeAsset(asset);\n\t\treturn asset;\n\t}\n\n\tloadAssetWithBacklog(key: string | ArrayBuffer): Promise {\n\t\treturn this.loadAsset(key);\n\t}\n\n\tregisterAssets(_assets: T[]) {\n\t\tthis.notSupportedInPureLoader();\n\t}\n\n\tstorePending(): Promise {\n\t\tthis.notSupportedInPureLoader();\n\t}\n\n\tstoreCompleted(): Promise {\n\t\tthis.notSupportedInPureLoader();\n\t}\n\n\tasync deleteAssets(keys: (string| ArrayBuffer)[]) {\n\t\tawait Promise.all(keys.map(\n\t\t\t(key) => this.deleteAsset(key)\n\t\t));\n\t}\n\n\tasync deleteAsset(key: string | ArrayBuffer) {\n\t\tconst textKey = keyToText(key);\n\t\tconst asset = this.keyToAsset.get(textKey);\n\t\tif (asset !== undefined) {\n\t\t\tthis.keyToAsset.delete(textKey);\n\t\t}\n\t\tawait this.assetDb.remove(textKey);\n\t}\n\n\tforgetAllBut(keys: (string| ArrayBuffer)[]) {\n\t\tconst textKeys = keys.map(keyToText);\n\t\tconst initialSize = this.keyToAsset.size;\n\t\tconst toKeepSet = new Set([...textKeys]);\n\t\tfor (const [textKey, _asset] of this.keyToAsset) {\n\t\t\tif (!toKeepSet.has(textKey)) {\n\t\t\t\tthis.keyToAsset.delete(textKey);\n\t\t\t}\n\t\t}\n\t\tconst trimmedSize = this.keyToAsset.size;\n\t\tconsole.debug(`Forgotten ${initialSize - trimmedSize} ${this.contentType} using ${textKeys.length} keys, ${trimmedSize} left.`);\n\t}\n\n\tlistAssets() {\n\t\tconsole.debug(`Asset map ${this.contentType} contains ${[...this.keyToAsset.keys()].join(', ')}`);\n\t}\n\n\tprotected memorizeAsset(asset: T) {\n\t\tthis.keyToAsset.set(asset.textKey, asset);\n\t}\n\n\tprotected cacheAsset(asset: T) {\n\t\tconst textKey = asset.textKey;\n\t\tif (this.keyToAsset.has(textKey)) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.memorizeAsset(asset);\n\t\treturn true;\n\t}\n\n\tprivate notSupportedInPureLoader(): never {\n\t\tassertFalse('This method is not supported in a pure loader');\n\t}\n}","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { Asset } from 'game/game';\nimport { bufferToHex, hexToBuffer } from 'utils/buffers';\n\nexport function keyToText(key: string | ArrayBuffer): string {\n\tif (typeof key === 'string') {\n\t\treturn key;\n\t} else {\n\t\treturn bufferToHex(key);\n\t}\n}\n\nexport function keyToRaw(key: string | ArrayBuffer): ArrayBuffer {\n\tif (typeof key === 'string') {\n\t\treturn hexToBuffer(key);\n\t} else {\n\t\treturn key;\n\t}\n}\n\n/// A class to manage assets of a given user type, all stored in the assets database\n/// with the corresponding content type.\n///\n/// When not specified otherwise, key is any of the text and binary key.\n/// When specified, the text key is called textKey and the binary key is called rawKey.\nexport interface AssetManager {\n\tloadAsset(key: string | ArrayBuffer): Promise;\n\tloadAssetWithBacklog(key: string | ArrayBuffer): Promise;\n\tregisterAssets(assets: T[]): void;\n\tstorePending(): Promise;\n\tstoreCompleted(): Promise;\n\tdeleteAssets(keys: (string| ArrayBuffer)[]): Promise;\n\tdeleteAsset(key: string | ArrayBuffer): Promise;\n\tforgetAllBut(keys: (string| ArrayBuffer)[]): void;\n\tlistAssets(): void;\n}","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { keyToRaw, keyToText } from './asset-manager';\nimport { AssetLoader } from './asset-loader';\nimport { Asset, AssetKey } from 'game/game';\nimport { BlobWithContentType } from 'network/api-types';\nimport { KeyValueMap } from 'storage/db';\nimport { storeWithBacklog } from 'apps/full/backlog-executor';\nimport { BacklogInterface } from 'storage/backlog';\n\n/// An asset manager that supports storing assets using the \"assets\" backlog.\nexport class AssetLoaderAndSaver extends AssetLoader {\n\tprotected toStore: T[] = [];\n\n\tconstructor(\n\t\tassetDb: KeyValueMap,\n\t\tprivate backlog: BacklogInterface,\n\t\tcontentType: string,\n\t\tdecodeFunction: (rawAsset: ArrayBuffer, rawKey: AssetKey, contentType: string) => Promise,\n\t\tloadFallbackFunction: (key: string) => T\n\t)\n\t{\n\t\tsuper(assetDb, backlog, contentType, decodeFunction, loadFallbackFunction);\n\t}\n\n\t/// Load asset from backlog, cache or user-load function.\n\tasync loadAssetWithBacklog(key: string | ArrayBuffer): Promise {\n\t\tconst textKey = keyToText(key);\n\t\tconst rawAssetFromBacklog = await this.backlog.get(textKey);\n\t\tif (rawAssetFromBacklog !== undefined) {\n\t\t\tconsole.debug(`Loading asset ${textKey} from backlog as ${this.contentType}`);\n\t\t\tlet asset;\n\t\t\ttry {\n\t\t\t\tconst rawKey = keyToRaw(key);\n\t\t\t\tasset = await this.decodeFunction(rawAssetFromBacklog, rawKey, this.contentType);\n\t\t\t} catch (e: any) {\n\t\t\t\tasset = this.loadFallbackFunction(textKey);\n\t\t\t}\n\t\t\tthis.memorizeAsset(asset);\n\t\t\treturn asset;\n\t\t}\n\t\treturn this.loadAsset(key);\n\t}\n\n\tregisterAssets(assets: T[]) {\n\t\tfor (const asset of assets) {\n\t\t\tif (this.cacheAsset(asset)) {\n\t\t\t\tthis.toStore.push(asset);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync storePending(): Promise {\n\t\tconst toStore = this.toStore;\n\t\tthis.toStore = []; // after this they are either stored to the db or in the backlog (taking over from here)\n\t\tawait Promise.all(toStore.map(async (asset) => {\n\t\t\tconst compressed = asset.toStored;\n\t\t\treturn storeWithBacklog(\n\t\t\t\tasset.textKey,\n\t\t\t\tcompressed,\n\t\t\t\t(textKey, data) => {\n\t\t\t\t\tconsole.debug(`Storing asset with key ${textKey} as ${this.contentType}`);\n\t\t\t\t\treturn this.assetDb.set(textKey, { value: data, contentType: this.contentType });\n\t\t\t\t},\n\t\t\t\tthis.backlog\n\t\t\t);\n\t\t}));\n\t}\n\n\tasync storeCompleted(): Promise {\n\t\treturn await this.backlog.empty();\n\t}\n}","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { KeyValueMap } from 'storage/db';\nimport { Asset, AssetKey, CanvasWithKey, SoundWithKey } from 'game/game';\nimport { decodeImageBrowser, ImageContentTypes } from 'utils/image';\nimport { ContentTypes, BlobWithContentType } from 'network/api-types';\nimport { AssetManager } from './asset-manager';\nimport { createFallbackSound, getSoundSystem } from 'blocks/actions/sound/sound';\nimport { createFallbackCanvas } from 'utils/render';\nimport { BacklogInterface, audioWavAssetsBacklog, imagePngAssetsBacklog } from 'storage/backlog';\nimport { stringUnionCast } from 'utils/union-types';\n\ntype AssetManagerT = new (\n\tassetDb: KeyValueMap,\n\tbacklog: BacklogInterface,\n\tcontentType: string,\n\tdecodeFunction: (rawAsset: ArrayBuffer, rawKey: AssetKey, contentType: string) => Promise,\n\tloadFallbackFunction: (key: string) => T\n) => AssetManager;\n\nexport class AssetSerializer {\n\tpublic readonly imageManager: AssetManager;\n\tpublic readonly soundManager: AssetManager;\n\n\tconstructor(\n\t\tpublic readonly assetDb: KeyValueMap,\n\t\timageManagerCreator: AssetManagerT,\n\t\tsoundManagerCreator: AssetManagerT\n\t) {\n\t\tthis.imageManager = new imageManagerCreator(\n\t\t\tassetDb,\n\t\t\timagePngAssetsBacklog,\n\t\t\tContentTypes.ImagePng,\n\t\t\tasync (rawAsset, rawKey, contentType) => {\n\t\t\t\tconst imageType = stringUnionCast(ImageContentTypes, contentType)\n\t\t\t\tconst imageData = await decodeImageBrowser(new Uint8Array(rawAsset), imageType);\n\t\t\t\treturn Promise.resolve(new CanvasWithKey(imageData, rawKey));\n\t\t\t},\n\t\t\t(key) => {\n\t\t\t\treturn new CanvasWithKey(createFallbackCanvas(key));\n\t\t\t}\n\t\t);\n\t\tthis.soundManager = new soundManagerCreator(\n\t\t\tassetDb,\n\t\t\taudioWavAssetsBacklog,\n\t\t\tContentTypes.AudioWav,\n\t\t\tasync (rawAsset, rawKey) => {\n\t\t\t\tconst safeRawAsset = rawAsset instanceof Uint8Array ? rawAsset.buffer : rawAsset;\n\t\t\t\tconst sound = await getSoundSystem().decodeSound(safeRawAsset);\n\t\t\t\treturn new SoundWithKey(sound, rawKey);\n\t\t\t},\n\t\t\t(_key) => {\n\t\t\t\treturn new SoundWithKey(createFallbackSound());\n\t\t\t}\n\t\t);\n\t}\n\n\tasync storePendingAssetsAndReturnSuccess() {\n\t\tawait Promise.all([\n\t\t\tthis.imageManager.storePending(),\n\t\t\tthis.soundManager.storePending()\n\t\t])\n\t\tconst [canvasStored, soundStored] = await Promise.all([\n\t\t\tthis.imageManager.storeCompleted(),\n\t\t\tthis.soundManager.storeCompleted()\n\t\t]);\n\t\treturn canvasStored && soundStored;\n\t}\n\n\tlistAssets() {\n\t\tthis.imageManager.listAssets();\n\t\tthis.soundManager.listAssets();\n\t}\n}\n","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { BlobWithContentType, BinaryContentType } from 'network/api-types';\n\nexport interface KeyValueMap {\n\ttoString(): string;\n\tget(key: string): Promise;\n\tset(key: string, value: T): Promise;\n\tremove(key: string): Promise;\n}\n\nexport interface Counter {\n\tget(): Promise;\n\tinc(): Promise;\n\tremove(): Promise;\n}\n\nexport interface GameWithMetadata {\n\tkey: string;\n\tname: string | null;\n\twriteable: boolean;\n}\n\nexport function validateGameWithPermissions(value: any) {\n\treturn value instanceof Object && typeof value.key === 'string' && typeof value.writeable === 'boolean';\n}\n\nexport interface Workspace {\n\tgetGames(): Promise;\n\taddFront(item: string): Promise;\n\tremove(item: string): Promise;\n\treadonly key: string;\n\treadonly insecure: boolean;\n}\n\nexport interface Db {\n\tgetMap(name: string): KeyValueMap;\n\tgetBinaryMap(name: string, contentType: BinaryContentType): KeyValueMap;\n\tgetBinaryWithContentTypeMap(name: string): KeyValueMap;\n\tgetCounter(name: string): Counter;\n\tgetWorkspace(name: string, insecure: boolean): Workspace;\n}\n","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { assert } from 'utils/assert';\nimport { castArrayWithTypeChecker } from 'utils/types';\nimport { BlobWithContentType } from 'network/api-types';\nimport * as Api from 'network/api';\nimport { Counter, KeyValueMap, Workspace, GameWithMetadata, validateGameWithPermissions } from 'storage/db';\nimport { isWebPSupported } from 'apps/common/browser-check';\nimport { retryFetchIfForbidden } from 'network/api';\n\ninterface ResponseWithStatus {\n\tstatus: string\n}\n\nexport class HttpTextKeyValueMap implements KeyValueMap {\n\tconstructor(\n\t\tpublic readonly readUrl: string,\n\t\tpublic readonly writeUrl: string,\n\t\tprivate readonly version: number | null = null,\n\t\tprivate readonly writeNullAsEmptyString: boolean\n\t) { }\n\n\ttoString() {\n\t\treturn `HTTPKeyValueMap(${this.writeUrl}, ${this.version})`;\n\t}\n\n\tasync get(key: string): Promise {\n\t\tconsole.debug(`Getting ${key} from ${this.readUrl}.`);\n\t\tif (this.version === null) {\n\t\t\tconst json: { value: T } = await Api.fetchJson(this.readUrl + '/' + key, 'GET');\n\t\t\treturn json.value;\n\t\t} else {\n\t\t\t// Why type assertion: we rely on that the selected API (url) behaves as\n\t\t\t// expected regarding the potential `null` value(status 204).\n\t\t\t// Since we don't know the type of T at runtime there no better way without changing much more.\n\t\t\treturn await Api.fetchOptionalString(this.readUrl + '/' + key, 'GET') as T;\n\t\t}\n\t}\n\n\tasync set(key: string, value: T) {\n\t\tconsole.debug(`Setting ${key} on ${this.writeUrl} to: `, value?.substring(0, 64) ?? null);\n\t\tconst json: ResponseWithStatus = this.version === null ?\n\t\t\tawait Api.fetchJson(this.writeUrl, 'POST', { key, value })\n\t\t\t:\n\t\t\tawait Api.fetchString(this.writeUrl + '/' + key, 'PUT', (this.writeNullAsEmptyString && value === null) ? '' : value)\n\t\t;\n\t\tconsole.debug(`Successfully stored ${key}: ${json.status}.`);\n\t}\n\n\tasync remove(key: string): Promise {\n\t\tconsole.debug(`Deleting ${key}`);\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.writeUrl + '/' + key, 'DELETE');\n\t\tconsole.debug(`Successfully deleted ${key}: ${json.status}.`);\n\t}\n}\n\nclass AbstractHTTPBinaryKeyValueMap {\n\tconstructor(\n\t\tpublic readonly readUrl: string,\n\t\tpublic readonly writeUrl: string\n\t) {}\n\n\tasync remove(key: string): Promise {\n\t\tconsole.debug(`Deleting binary ${key}`);\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.writeUrl + '/' + key, 'DELETE');\n\t\tconsole.debug(`Successfully deleted binary ${key}: ${json.status}.`);\n\t}\n}\n\nexport class HTTPBinaryKeyValueMap extends AbstractHTTPBinaryKeyValueMap implements KeyValueMap {\n\tconstructor(\n\t\treadUrl: string,\n\t\tpublic readonly readRetryUrl: string | null,\n\t\twriteUrl: string,\n\t\tpublic readonly contentType: string\n\t) {\n\t\tsuper(readUrl, writeUrl);\n\t}\n\n\ttoString() {\n\t\treturn `HTTPKeyValueMap(${this.writeUrl}, ${this.contentType})`;\n\t}\n\n\tasync get(key: string): Promise {\n\t\tconsole.debug(`Getting binary ${key} from ${this.readUrl}.`);\n\t\tconst path = '/' + key;\n\t\tconst buffer = await retryFetchIfForbidden(Api.fetchBinary, this.readUrl + path, this.readRetryUrl && this.readRetryUrl + path, 'GET' as const, undefined, await acceptWebPHeader());\n\t\tassert(this.contentType === buffer.contentType, `Received content type ${buffer.contentType} matches expectation ${this.contentType}.`);\n\t\treturn buffer.value;\n\t}\n\n\tasync set(key: string, value: ArrayBuffer) {\n\t\tconsole.debug(`Setting binary ${key} on ${this.writeUrl} to binary blob of size ${value.byteLength}.`);\n\t\tawait Api.fetchBinary(this.writeUrl + '/' + key, 'PUT', { contentType: this.contentType, value });\n\t\tconsole.debug(`Successfully stored ${key}.`);\n\t}\n}\n\nexport class HTTPBinaryKeyValueMapWithContentType extends AbstractHTTPBinaryKeyValueMap implements KeyValueMap {\n\ttoString() {\n\t\treturn `HTTPKeyValueMap(${this.writeUrl})`;\n\t}\n\n\tasync get(key: string): Promise {\n\t\tconsole.debug(`Getting binary ${key} from ${this.readUrl}.`);\n\t\treturn await Api.fetchBinary(this.readUrl + '/' + key, 'GET', undefined, await acceptWebPHeader());\n\t}\n\n\tasync set(key: string, value: BlobWithContentType) {\n\t\tconsole.debug(`Setting binary ${key} on ${this.writeUrl} to binary blob of size ${value.value.byteLength} and content type ${value.contentType}.`);\n\t\tawait Api.fetchBinary(this.writeUrl + '/' + key, 'PUT', value);\n\t\tconsole.debug(`Successfully stored binary ${key}.`);\n\t}\n}\n\nexport class HTTPCounter implements Counter {\n\tconstructor(\n\t\tpublic readonly readUrl: string,\n\t\tpublic readonly incrementUrl: string,\n\t\tpublic readonly deleteUrl: string,\n\t\tpublic name: string\n\t) {}\n\n\ttoString() {\n\t\treturn `HTTPCounter(${this.name})`;\n\t}\n\n\tasync get() {\n\t\tconsole.debug(`Getting counter ${this.name}.`);\n\t\tconst json: { value: string } = await Api.fetchJson(this.readUrl, 'GET');\n\t\treturn parseInt(json.value, 10);\n\t}\n\n\tasync inc() {\n\t\tconsole.debug(`Incrementing counter ${this.name}`);\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.incrementUrl, 'PATCH');\n\t\tconsole.debug(`Successfully incremented counter ${this.name}: ${json.status}.`);\n\t}\n\n\tasync remove() {\n\t\tconsole.debug(`Deleting counter ${this.name}`);\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.deleteUrl, 'DELETE');\n\t\tconsole.debug(`Successfully deleted counter ${this.name}: ${json.status}.`);\n\t}\n}\n\nexport class HTTPWorkspace implements Workspace {\n\tconstructor(\n\t\tpublic readonly url: string,\n\t\tpublic readonly name: string,\n\t\tpublic insecure: boolean\n\t) {}\n\n\tget key() {\n\t\treturn this.name;\n\t}\n\n\ttoString() {\n\t\treturn `HTTPWorkspace(${this.name})`;\n\t}\n\n\tasync getGames() {\n\t\treturn await Api.fetchJson(this.url, 'GET').then((json) => {\n\t\t\t// TODO validate format\n\t\t\tconsole.debug(`Successfully got workspace ${this.name}: ${(json as any[]).length} elements.`);\n\t\t\treturn castArrayWithTypeChecker(validateGameWithPermissions, 'GameWithPermissions', json);\n\t\t});\n\t}\n\n\tasync addFront(item: string) {\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.getItemsUrl(item), 'PUT', { insecure: this.insecure });\n\t\tconsole.debug(`Successfully added ${item} to ${this.name}: ${json.status}.`);\n\t}\n\n\tasync remove(item: string) {\n\t\tconst json: ResponseWithStatus = await Api.fetchJson(this.getItemsUrl(item), 'DELETE');\n\t\tconsole.debug(`Successfully deleted ${item} from ${this.name}: ${json.status}.`);\n\t}\n\n\tprivate getItemsUrl(item: string) {\n\t\treturn this.url + '/' + encodeURIComponent(item);\n\t}\n}\n\nasync function acceptWebPHeader() {\n\treturn await isWebPSupported() ? { Accept: 'image/webp,image/png,image/jpeg,*/*;q=0.8' } : undefined;\n}\n","/**\n * @module storage\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { BinaryContentType } from 'network/api-types';\nimport * as Api from 'network/api';\nimport { Db } from 'storage/db';\nimport { HTTPBinaryKeyValueMap, HTTPBinaryKeyValueMapWithContentType, HTTPCounter, HttpTextKeyValueMap, HTTPWorkspace } from './http-db';\n\nfunction computeReadUrl(url: string, ncRead: boolean) {\n\treturn ncRead ? url.replace('/api/', '/nc_api/') : url;\n}\n\nexport class RustServerDb implements Db {\n\treadonly baseUrl = Api.getApiBaseUrl();\n\n\tgetMap(name: string) {\n\t\tconst isGameNames = name === 'gameNames';\n\t\tconst [version, versionInfix] = isGameNames ? [0, 'v0/'] as const : [null, ''] as const;\n\t\tconst writeUrl = this.baseUrl + '/' + versionInfix + encodeURIComponent(name);\n\t\tconst readUrl = computeReadUrl(writeUrl, true);\n\t\treturn new HttpTextKeyValueMap(readUrl, writeUrl, version, isGameNames);\n\t}\n\tgetBinaryMap(name: string, contentType: BinaryContentType) {\n\t\tconst writeUrl = this.baseUrl + '/v0/' + encodeURIComponent(name);\n\t\tconst readUrl = computeReadUrl(writeUrl, true);\n\t\tconst readRetryUrl = writeUrl;\n\t\treturn new HTTPBinaryKeyValueMap(readUrl, readRetryUrl, writeUrl, contentType);\n\t}\n\tgetBinaryWithContentTypeMap(name: string) {\n\t\tconst writeUrl = this.baseUrl + '/v0/' + encodeURIComponent(name);\n\t\tconst readUrl = computeReadUrl(writeUrl, true);\n\t\treturn new HTTPBinaryKeyValueMapWithContentType(readUrl, writeUrl);\n\t}\n\tgetCounter(name: string) {\n\t\tconst writeUrl = this.baseUrl + '/counters/' + encodeURIComponent(name);\n\t\tconst readUrl = computeReadUrl(writeUrl, true);\n\t\treturn new HTTPCounter(readUrl, readUrl, writeUrl, name);\n\t}\n\tgetWorkspace(name: string, insecure = false) {\n\t\treturn new HTTPWorkspace(this.baseUrl + '/workspaces/' + encodeURIComponent(name), name, insecure);\n\t}\n\n\tgetMiniatureReadURI(gameKey: string) {\n\t\treturn computeReadUrl(`${this.baseUrl}/v0/miniatures/${encodeURIComponent(gameKey)}`, true);\n\t}\n}\n","/**\n * @module utils\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nexport function dataURI(media: string, data: string) {\n\treturn `data:${media};base64,${data}`;\n}"],"names":["createFallbackSound","buffer","AudioBuffer","length","sampleRate","data","getChannelData","i","Math","sin","PI","WebAudioSound","packWav","samples","fileSize","wavData","Uint8Array","fillText","offset","text","charCodeAt","fillUint32","value","fillUint16","maxValue","forEach","sample","max","destArray","Int16Array","constructor","connectToAudioNodeAndPlay","ctx","node","source","createBufferSource","this","connect","start","getSamplesAndRate","output","Float32Array","copyFromChannel","clone","WebAudioSoundSystem","audioCtx","decodeSound","playSound","sound","gain","pan","gainNode","createGain","panNode","createStereoPanner","destination","FakeSound","_ctx","_node","console","debug","FakeSoundSystem","info","log","byteLength","Promise","resolve","_sound","soundSystem","getSoundSystem","forceFake","EditorDefaultScale","CameraDefaultExtent","CameraDefaultBackgroundColor","LevelDefaultGravity","LevelDefaultAirFriction","ObjectTypeDefaultStickiness","ObjectTypeDefaultBounciness","ObjectTypeDefaultDensity","WorldWindowMarginConstant","WorldWindowMarginProportional","MiniatureSize","GameMetaDataCanvas","id","miniature","name","create","game","getMiniature","createWithUnknownMiniature","gameKey","size","canvas","fillStyle","fillRect","font","saveGameWithStorer","storage","storer","serialisedGame","imageIndices","asUint8ArrayWithAssetUUID","imageAssets","registerAssets","keys","map","drawable","soundAssets","sounds","saveNewBinaryGameWithStorer","screenManager","screenChangedCallback","_before","_after","stack","reportUnload","peek","window","addEventListener","cancelReportUnload","removeEventListener","push","s","show","before","pushAndNotify","doTransitionAndRetNewTop","updateCliObject","pushed","popAndNotify","pop","popped","popEvenIfLast","after","last","hide","Error","newScreen","replaceWith","screens","screen","description","cli","Screen","element","resizeEventListener","keyDownEventListener","keyUpEventListener","visibilityChangedListener","resized","bind","keyDown","keyUp","visibilityChanged","visible","style","display","parameters","to","document","from","event","appHidden","appVisible","hidden","AssetLoader","assetDb","contentType","decodeFunction","loadFallbackFunction","keyToAsset","Map","_assetsBacklog","loadAsset","key","textKey","cachedAsset","get","undefined","asset","assetData","rawKey","e","statusCode","warn","reportAssetError","memorizeAsset","loadAssetWithBacklog","_assets","notSupportedInPureLoader","storePending","storeCompleted","deleteAssets","all","deleteAsset","delete","remove","forgetAllBut","textKeys","initialSize","toKeepSet","Set","_asset","has","trimmedSize","listAssets","join","set","cacheAsset","keyToText","keyToRaw","AssetLoaderAndSaver","backlog","toStore","super","rawAssetFromBacklog","assets","async","compressed","toStored","empty","AssetSerializer","imageManager","soundManager","imageManagerCreator","soundManagerCreator","ImagePng","rawAsset","imageType","imageData","AudioWav","safeRawAsset","_key","storePendingAssetsAndReturnSuccess","canvasStored","soundStored","validateGameWithPermissions","Object","writeable","HttpTextKeyValueMap","readUrl","writeUrl","version","writeNullAsEmptyString","toString","substring","json","status","AbstractHTTPBinaryKeyValueMap","HTTPBinaryKeyValueMap","readRetryUrl","path","acceptWebPHeader","assert","HTTPBinaryKeyValueMapWithContentType","HTTPCounter","incrementUrl","deleteUrl","parseInt","inc","HTTPWorkspace","url","insecure","getGames","then","addFront","item","getItemsUrl","encodeURIComponent","Accept","computeReadUrl","ncRead","replace","RustServerDb","baseUrl","getMap","isGameNames","versionInfix","getBinaryMap","getBinaryWithContentTypeMap","getCounter","getWorkspace","getMiniatureReadURI","dataURI","media"],"sourceRoot":""}