UNPKG

@awayfl/awayfl-player

Version:

Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript

346 lines (271 loc) 8.16 kB
import { AVMStage, registerDebugMethod } from "@awayfl/swf-loader"; import { DisplayObject } from '@awayjs/scene'; import { PickGroup } from "@awayjs/view"; import { SharedObjectDebug as SOavm2 } from "@awayfl/playerglobal"; import { SharedObjectDebug as SOavm1 } from "@awayfl/avm1"; function fullSerializer(obj: any) { const clone = Object.assign({}, obj); Object.keys(clone).forEach((key)=>{ if(typeof clone[key] === 'object') { clone[key] = fullSerializer(clone[key]); } else if(typeof clone[key] === 'function') { // replace func with it string representation clone[key] = clone[key].toString(); } }); return clone; } const OBJECT_FIELDS = ['id','visible', 'index', 'assetType:type', 'name']; export class AVMDebug { private _rafState: 'stop' | 'next' | 'play' = 'play'; private _defaultRaf: any = self.requestAnimationFrame; private _requestedCallbacks: FrameRequestCallback [] = []; constructor(public player: AVMStage) { registerDebugMethod(this._dirObjectByIds.bind(this), { name: "dirObjectByIds", description:"Export selected object to console", declaration: [{name: 'ids', type: "object"}] }); registerDebugMethod(this._applyPropsByIds.bind(this), { name: "applyPropsByIds", description:"Apply propertyes by node ids", declaration: [{name: 'ids', type: "object"}, {name:'object', type:'object'}] }); registerDebugMethod(this._removeObjectByIds.bind(this), { name: "removeObjectByIds", description:"Remove object from sceen tree", declaration: [{name: 'ids', type: "object"}] }); registerDebugMethod(this._getInfo.bind(this), { name: "getInfo", description:"Get file info for app", declaration: [{name:"return", type:"object"}] }); registerDebugMethod(this._getSceneTree.bind(this), { name: "getNodeTree", description:"Get sceen tree of app", declaration: [ {name:"return", type:"object"}, {name:"flat", type:"boolean"}, {name:"from", type:"number"}, {name:"rect", type:"object"} ] }); registerDebugMethod(this._getStageCanvas.bind(this), { name: "getStageCanvas", description:"Get canvas attahed to stage", declaration: [] }); registerDebugMethod(this._setRAFState.bind(this), { name: "setRAFState", description: "Changed RAF state", declaration: [ {name:'return', type: 'string'}, {name:'state', type: 'string'} ] }); registerDebugMethod(this._getRAFState.bind(this), { name: "getRAFState", description: "Changed RAF state", declaration: [ {name:'return', type: 'string'}, {name:'state', type: 'string'} ] }); this._mokedRaf = this._mokedRaf.bind(this); //@ts-ignore window._AWAY_DEBUG_PLAYER_ = this; } public onAvmInit(version: number) { //@ts-ignore window._AWAY_DEBUG_STORAGE = version === 1 ? SOavm1 : SOavm2; } private _mokedRaf(callback: FrameRequestCallback) { if (this._requestedCallbacks.indexOf(callback) !== -1) return; this._requestedCallbacks.push(callback); return 0; } private _setRAFState(state: 'stop' | 'next' | 'play'): 'stop' | 'next' | 'play' { if (!state) return this._rafState; if (state === this._rafState) return; if(state === 'next' && this._rafState === 'stop') { const time = performance.now(); const callbacks = this._requestedCallbacks.slice(); this._rafState = 'next'; this._requestedCallbacks.length = 0; callbacks.forEach((e) => e && e(time)); return this._rafState = 'stop'; } if (state === 'stop') { this._requestedCallbacks.length = 0; self.requestAnimationFrame = this._mokedRaf; return this._rafState = 'stop'; } if (state === 'play') { const time = performance.now(); const callbacks = this._requestedCallbacks.slice(); this._rafState = 'play'; this._requestedCallbacks.length = 0; self.requestAnimationFrame = this._defaultRaf; callbacks.forEach((e) => e && e(time)); } return this._rafState; } private _getRAFState(): 'stop' | 'next' | 'play' { return this._rafState; } private _selectNode(ids: number[]): DisplayObject { let node = this.player.root as any; for(let i of ids) { node = node._children.find((e) => e.id === i); if(!node) { break; } } if(!node){ throw new Error("Node not found"); } return node; } private _getStageCanvas() { return this.player.view.stage.container; } private _dirObjectByIds(ids: number[]) { const node = this._selectNode(ids); //@ts-ignore const exposeID = window._lastTempNode = window._lastTempNode || 1; //@ts-ignore window._lastTempNode++; window['tempNode' + exposeID] = node console.log('tempNode' + exposeID, '='); console.dir(node); } private _getNodeBounds(node: DisplayObject) { const view = this.player.view; let box; const pool = AVMStage.instance && (<any>AVMStage.instance()).pool if (pool) { //@ts-ignore const partition = pool.getNode(node).partition; const picker = PickGroup.getInstance().getBoundsPicker(partition); //@ts-ignore box = picker.getBoxBounds(pool.getNode(this.player.root), true, true); } else { //@ts-ignore box = PickGroup.getInstance().getBoundsPicker(node.partition).getBoxBounds(this.player.root); } if (!box) return null; const sx = view.width / this.player.stageWidth; const sy = view.height / this.player.stageHeight; //console.log("DisplayObject:getRect not yet implemented");FromBounds return { x: box.x * sx, y: box.y * sy, width: box.width * sx, height: box.height * sy }; } private _traverse(node: any, req = false, rect = false, visibleOnly = false) { const ret = { parentId: node.parent ? node.parent.id : -1, children: null, rect: null, } for(let name of OBJECT_FIELDS) { const sub = name.split(":"); if(sub.length > 1) { ret[sub[1]] = node[sub[0]]; } else{ ret[name] = node[name]; } } ret["globalVisible"] = node.parent ? (node.parent.visible && node.visible) : node.visible; if(rect) { ret.rect = this._getNodeBounds(node) } if(req) { ret.children = []; for(let c of node._children) { if(visibleOnly && c.visible || !visibleOnly){ ret.children.push(this._traverse(c, req, rect, visibleOnly)); } } } return ret; } private _removeObjectByIds(ids: number[]) { const node = this._selectNode(ids); node.parent.removeChild(node); } private _applyPropsByIds(ids: number[], object: any) { const node = this._selectNode(ids); Object.assign(node, object); } private _getSceneTree(params: {flat?: boolean, from?: number, rect?: boolean, visibleOnly?: boolean}) private _getSceneTree(flat?: boolean, from?: number, rect?: boolean) private _getSceneTree(params: any, fromArg?: number, rectArg?: boolean) { if(typeof params !== 'object') { params = { flat: params || false, from: fromArg || 0, rect: rectArg || false, visibleOnly: false } } const { flat = false, from = 0, rect = false, visibleOnly = false } = params; const tree = []; //@ts-ignore const q: any[] = this.player.root._children.slice(); while(true) { const node = q.pop(); if(!node) { break; } tree.push(this._traverse(node, !flat, rect, visibleOnly)); if(flat) { q.push.apply(q, node._children.reverse().filter(e => (e.visible && visibleOnly || !visibleOnly))); } } return tree; } private _getInfo() { const player = <any>this.player; const avm = player._avmHandler.avmVersion; const { swfVersion, fpVersion, frameCount, frameRate, compression, bytesTotal } = player._swfFile; let path: string = (<any>player._gameConfig).binary.filter(({resourceType}) => resourceType === 'GAME')[0]?.path; if(path && path.indexOf('?') > -1) { path = path.substring(0, path.indexOf('?')); } return { file: { name: (<any>player._gameConfig).title, path: path, size: bytesTotal }, runtime: { swfVersion, fpVersion, frameCount, frameRate, compression, avm }, config: fullSerializer(player._gameConfig) } } }