@swf2es/player-hosts 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/thread/player/avm1/avm1.js +19 -1
- package/dist/thread/player/avm1/loads.js +2 -2
- package/dist/thread/player/player.js +10 -0
- package/dist/thread/player/playerglobal/flash/net/SharedObject.js +3 -2
- package/dist/thread/player/scripting/loads.js +6 -0
- package/dist/thread/runtime/avm1/functions.js +21 -1
- package/package.json +2 -2
|
@@ -65,7 +65,7 @@ import { xmlClass } from "./globals/XML.js";
|
|
|
65
65
|
import { xmlNodeClass, serialize as xmlString } from "./globals/XMLNode.js";
|
|
66
66
|
import { xmlSocketClass } from "./globals/XMLSocket.js";
|
|
67
67
|
import { Avm1Input } from "./input.js";
|
|
68
|
-
import { MovieLoads } from "./loads.js";
|
|
68
|
+
import { MovieLoads, queryVariables } from "./loads.js";
|
|
69
69
|
import { Avm1Net, textFor } from "./net.js";
|
|
70
70
|
import { asciiLower, atPath, childByName, pathOf, under } from "./paths.js";
|
|
71
71
|
import { ActionQueue, BLOCK, CONSTRUCT, CONSTRUCTION, FRAME, HALT, INIT, INITIALIZE, METHOD, NORMAL, Queued, } from "./queue.js";
|
|
@@ -209,6 +209,8 @@ export class Avm1 {
|
|
|
209
209
|
/** The focus, what Tab moves it through and Selection's listeners. */
|
|
210
210
|
focusTracker = new FocusTracker(this);
|
|
211
211
|
url;
|
|
212
|
+
/** The page's flashvars for the main SWF's root. */
|
|
213
|
+
parameters;
|
|
212
214
|
storage;
|
|
213
215
|
/** SharedObject's writes of what its scripts changed, as the player goes: none before attach. */
|
|
214
216
|
sharedObjects = null;
|
|
@@ -231,6 +233,7 @@ export class Avm1 {
|
|
|
231
233
|
this.onUncaught = options.onUncaught ?? ((error) => console.error(error));
|
|
232
234
|
this.fileHost = options.fileHost === undefined ? browserFileHost() : options.fileHost;
|
|
233
235
|
this.url = options.url ?? "";
|
|
236
|
+
this.parameters = options.parameters ?? {};
|
|
234
237
|
this.localConnections = options.localConnections ?? new LocalConnections();
|
|
235
238
|
this.storage = options.storage ?? defaultStorage();
|
|
236
239
|
this.net = new Avm1Net(options.fetch ?? null, options.socket ?? null, options.base ?? this.url, options.sendToUrl ?? true);
|
|
@@ -399,6 +402,17 @@ export class Avm1 {
|
|
|
399
402
|
realm.global.define("TextSnapshot", textSnapshotClass(realm), avm1.DONT_ENUM);
|
|
400
403
|
this.adopt(main);
|
|
401
404
|
this.made(root);
|
|
405
|
+
// Its parameters, as Flash defines them on the root before the first frame's actions run.
|
|
406
|
+
const face = root.avm1;
|
|
407
|
+
if (face !== null) {
|
|
408
|
+
const parameters = new Map(queryVariables(this.url));
|
|
409
|
+
for (const [name, value] of Object.entries(this.parameters)) {
|
|
410
|
+
parameters.set(name, String(value));
|
|
411
|
+
}
|
|
412
|
+
for (const [name, value] of parameters) {
|
|
413
|
+
face.define(name, textFor(value, this.swfVersion), 0);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
402
416
|
}
|
|
403
417
|
/** A SWF's timelines told to this: their clips are made and play through it from now on. */
|
|
404
418
|
adopt(swf) {
|
|
@@ -841,6 +855,10 @@ export class Avm1 {
|
|
|
841
855
|
registeredName(constr) {
|
|
842
856
|
return this.classes.registeredName(constr);
|
|
843
857
|
}
|
|
858
|
+
/** SharedObject writes what its scripts changed, as Flash did as a SWF closed: the page may be going. */
|
|
859
|
+
saveSharedObjects() {
|
|
860
|
+
this.sharedObjects?.flush(this.swfVersion);
|
|
861
|
+
}
|
|
844
862
|
/** The player gone: SharedObject writes what its scripts changed, as Flash did as a SWF closed. */
|
|
845
863
|
destroy(closeAudio = true) {
|
|
846
864
|
for (const bytes of this.codeLive) {
|
|
@@ -53,11 +53,11 @@ async function arrive(result, decode) {
|
|
|
53
53
|
return { type: "swf", swf, library, size: bytes.length, status };
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* A URL's query as a
|
|
56
|
+
* A URL's query as a SWF's root gets it, each name a variable, as
|
|
57
57
|
* Ruffle's movie_loader_complete defines a movie's parameters: decoded,
|
|
58
58
|
* `+` a space, a name without `=` an empty value.
|
|
59
59
|
*/
|
|
60
|
-
function queryVariables(url) {
|
|
60
|
+
export function queryVariables(url) {
|
|
61
61
|
const path = url.split("#", 1)[0];
|
|
62
62
|
const at = path.indexOf("?");
|
|
63
63
|
if (at < 0) {
|
|
@@ -240,6 +240,16 @@ export class Player {
|
|
|
240
240
|
* for the player, its renderer, its input bindings and its loop, is the
|
|
241
241
|
* host's to let go.
|
|
242
242
|
*/
|
|
243
|
+
/**
|
|
244
|
+
* Write what scripts changed in their SharedObjects, as Flash did as a
|
|
245
|
+
* SWF closed, without stopping anything: a host calls it as its page goes
|
|
246
|
+
* away, where destroy() may never run.
|
|
247
|
+
*/
|
|
248
|
+
saveSharedObjects() {
|
|
249
|
+
this.scripting?.flushSharedObjects?.();
|
|
250
|
+
this.scripting?.loads.saveAvm1SharedObjects();
|
|
251
|
+
this.avm1?.saveSharedObjects();
|
|
252
|
+
}
|
|
243
253
|
destroy() {
|
|
244
254
|
if (!this.stopped) {
|
|
245
255
|
drawKernelLetGo();
|
|
@@ -247,8 +247,8 @@ export function sharedObjectNatives(s) {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
// Flash wrote each open object as its SWF went: a
|
|
251
|
-
// writes those a script changed since they were read or written. Never
|
|
250
|
+
// Flash wrote each open object as its SWF went: a player hidden or
|
|
251
|
+
// destroyed writes those a script changed since they were read or written. Never
|
|
252
252
|
// a removal: an object whose stored file it could not read starts empty,
|
|
253
253
|
// and an unchanged one would take the file away.
|
|
254
254
|
s.flushSharedObjects = () => {
|
|
@@ -257,6 +257,7 @@ export function sharedObjectNatives(s) {
|
|
|
257
257
|
const file = serialize(o);
|
|
258
258
|
if (file.length && !sameBytes(file, o.$saved)) {
|
|
259
259
|
s.storage.set(o.$key, file);
|
|
260
|
+
o.$saved = file;
|
|
260
261
|
}
|
|
261
262
|
}
|
|
262
263
|
catch {
|
|
@@ -65,6 +65,12 @@ export class Loads {
|
|
|
65
65
|
}
|
|
66
66
|
return frames;
|
|
67
67
|
}
|
|
68
|
+
/** The AVM1 movies' SharedObjects written, as the page may be going. */
|
|
69
|
+
saveAvm1SharedObjects() {
|
|
70
|
+
for (const movie of this.avm1Movies.values()) {
|
|
71
|
+
movie.vm.saveSharedObjects();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
68
74
|
destroyAvm1() {
|
|
69
75
|
for (const movie of this.avm1Movies.values()) {
|
|
70
76
|
movie.vm.destroy(false);
|
|
@@ -73,6 +73,10 @@ export class ScriptFunction extends Avm1Function {
|
|
|
73
73
|
this.clip = clip;
|
|
74
74
|
this.definer = definer;
|
|
75
75
|
}
|
|
76
|
+
/** The realm's count of removals as it last asked whether `target` was removed, -1 before. */
|
|
77
|
+
looked = -1;
|
|
78
|
+
/** Whether `target` was removed as it last asked. */
|
|
79
|
+
gone = false;
|
|
76
80
|
/**
|
|
77
81
|
* Run its body with `self` as `this`, `depth` how far up `this`'s
|
|
78
82
|
* prototypes it was found (which `super` starts from), in an activation
|
|
@@ -98,7 +102,23 @@ export class ScriptFunction extends Avm1Function {
|
|
|
98
102
|
let scope = this.scope;
|
|
99
103
|
let target = this.target;
|
|
100
104
|
let clip = this.clip;
|
|
101
|
-
if (this.version
|
|
105
|
+
if (this.version >= 6 && caller.host.removed !== undefined) {
|
|
106
|
+
// A clip whose code defined it may since be gone, a loaded SWF's
|
|
107
|
+
// classes after it was unloaded among them: it runs on `this` where
|
|
108
|
+
// that is a clip, else on the caller's target, rather than returning
|
|
109
|
+
// at its first call, as code returns whose clip a call removes
|
|
110
|
+
// (Ruffle's resolve_reference of its base clip, then this_do).
|
|
111
|
+
if (this.looked !== realm.removals) {
|
|
112
|
+
this.looked = realm.removals;
|
|
113
|
+
this.gone = caller.host.removed(target);
|
|
114
|
+
}
|
|
115
|
+
if (this.gone) {
|
|
116
|
+
const own = self instanceof Avm1Object ? caller.host.clipOf?.(self) : undefined;
|
|
117
|
+
target = own ?? targetOrRoot(caller);
|
|
118
|
+
clip = own !== undefined ? self : caller.clip;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (this.version < 6) {
|
|
102
122
|
const own = self instanceof Avm1Object ? caller.host.clipOf?.(self) : undefined;
|
|
103
123
|
if (own !== undefined) {
|
|
104
124
|
target = own;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swf2es/player-hosts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Optional Node and WebSocket transports, worker threads, an IndexedDB module cache and precompiled modules for the swf2es player",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"swf",
|
|
@@ -60,6 +60,6 @@
|
|
|
60
60
|
"LICENSE.third-party"
|
|
61
61
|
],
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@swf2es/player": "0.1.
|
|
63
|
+
"@swf2es/player": "0.1.3"
|
|
64
64
|
}
|
|
65
65
|
}
|