@awayfl/awayfl-player 0.2.38 → 0.2.40

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.
@@ -0,0 +1,538 @@
1
+ const supportDecoderApi = ('DecompressionStream' in self);
2
+ const isSWC = (head) => (head[0] === 0x43 && head[1] === 0x57 && head[2] === 0x53);
3
+ const outputSize = (head) => new DataView(head.buffer).getUint32(4, true);
4
+
5
+ function Decoder(size, offset = 8) {
6
+ if(!supportDecoderApi) {
7
+ throw 'Your browser not support DecompressionStream =(';
8
+ }
9
+
10
+ const decoder = new self.DecompressionStream('deflate');
11
+ const decoderW = decoder.writable.getWriter();
12
+ const decoderR = decoder.readable.getReader();
13
+ const buffer = new Uint8Array(size);
14
+
15
+ let isRunned = false;
16
+ let isDone = false;
17
+
18
+ let donableCallback;
19
+
20
+ function run() {
21
+ decoderR.read().then(function next(state) {
22
+ const done = state.done;
23
+ const value = state.value;
24
+
25
+ if (value) {
26
+ buffer.set(value, offset);
27
+ //console.debug("[Loader] Decoded chunk:", offset);
28
+
29
+ offset += value.length;
30
+ }
31
+
32
+ if (done || offset >= size) {
33
+ isDone = true;
34
+
35
+ if(donableCallback) {
36
+ donableCallback();
37
+ }
38
+
39
+ console.debug("[Loader] Decoder closed:", offset);
40
+ return;
41
+ }
42
+
43
+ return decoderR.read().then(next);
44
+ });
45
+ }
46
+
47
+ return {
48
+ get buffer() {
49
+ return buffer;
50
+ },
51
+
52
+ write(buffer) {
53
+ decoderW.ready.then(()=>{
54
+ decoderW.write(buffer);
55
+
56
+ if(!isRunned) {
57
+ isRunned = true;
58
+ run();
59
+ }
60
+ });
61
+ },
62
+
63
+ readAll() {
64
+ if(isDone) {
65
+ return Promise.resolve(buffer);
66
+ }
67
+
68
+ return new Promise((res)=>{
69
+ donableCallback = () => {
70
+ res(buffer);
71
+ }
72
+ })
73
+ }
74
+ }
75
+ }
76
+
77
+ function Fetcher(url = '', progress = f => f) {
78
+ let total = 0;
79
+ let reader;
80
+ let chunks = [];
81
+
82
+ progress && progress(0);
83
+
84
+ return fetch(url)
85
+ .then((request) => {
86
+ total = +request.headers.get('Content-Length');
87
+ reader = request.body.getReader();
88
+
89
+ return reader.read();
90
+ })
91
+ .then( (data) => {
92
+ const firstChunk = data.value;
93
+
94
+ console.debug("[Loader] Header:", String.fromCharCode.apply(null,firstChunk.slice(0, 3).reverse()));
95
+
96
+ let loaded = 0;
97
+ let decoder;
98
+
99
+ if (supportDecoderApi && isSWC(firstChunk)) {
100
+ const totalDecodedSize = outputSize(firstChunk);
101
+ const swcHeader = firstChunk.slice(0, 8);
102
+
103
+ swcHeader[0] = 70; // SWC => SWF
104
+
105
+ console.debug("[Loader] SWC size:", outputSize(firstChunk));
106
+
107
+ decoder = Decoder(totalDecodedSize, 8);
108
+ decoder.buffer.set(swcHeader);
109
+
110
+ // push witout header
111
+ decoder.write(firstChunk.slice(8));
112
+
113
+ } else {
114
+ chunks.push(firstChunk);
115
+ }
116
+
117
+ loaded += firstChunk.length;
118
+
119
+ progress && progress( Math.min(1, loaded / total));
120
+
121
+ // update all other chunks reqursive while !done
122
+ return reader.read().then( function moveNext(state) {
123
+
124
+ if (state.done) {
125
+ if(!decoder) {
126
+ let buffer = new Uint8Array(loaded);
127
+ let offset = 0;
128
+
129
+ chunks.forEach((e) => {
130
+ buffer.set(e, offset);
131
+ offset += e.length;
132
+ });
133
+
134
+ return buffer;
135
+ }else {
136
+ return decoder.readAll();
137
+ }
138
+ }
139
+
140
+ const value = state.value;
141
+
142
+ loaded += value.length;
143
+ progress && progress( Math.min(1, loaded / total));
144
+
145
+ if (!decoder) {
146
+ chunks.push(value);
147
+ } else {
148
+ decoder.write(value);
149
+ }
150
+
151
+ return reader.read().then(moveNext);
152
+ });
153
+ })
154
+ }
155
+
156
+ var Loader = (function () {
157
+ function loadBinary(file, progressEvent = f => f) {
158
+ const isScript = file.path.indexOf(".js") > -1;
159
+
160
+ if (!isScript && supportDecoderApi ) {
161
+ return Fetcher(file.path, progressEvent)
162
+ .then((buffer)=>({
163
+ meta: file.meta || {},
164
+ name: file.name,
165
+ path: file.path,
166
+ resourceType: file.resourceType,
167
+ data: buffer.buffer,
168
+ type: "swf",
169
+ }));
170
+ }
171
+
172
+ const req = new XMLHttpRequest();
173
+
174
+ req.addEventListener("progress", e => {
175
+ const gzip = req.getAllResponseHeaders('content-encoding') === 'gzip';
176
+
177
+ // get from progress, then from request, and if not valid - from file
178
+ const total = e.total || (+req.getAllResponseHeaders('content-length')) || (file.size * (gzip ? 0.25 : 1));
179
+
180
+ if(!total) {
181
+ progressEvent(1);
182
+ return;
183
+ }
184
+
185
+ progressEvent(Math.min(1, e.loaded / total) );
186
+ });
187
+
188
+ req.open("GET", file.path, true);
189
+ req.responseType = isScript ? "text" : "arraybuffer";
190
+
191
+ return new Promise((res, rej) => {
192
+ req.addEventListener("error", rej);
193
+ req.addEventListener("load", () => {
194
+ progressEvent(1);
195
+
196
+ if (isScript) {
197
+ // unsafe
198
+ //eval(req.response);
199
+
200
+ const b = new Blob([req.response], { type: "text/javascript" });
201
+ // use blob
202
+ loadScript(URL.createObjectURL(b)).then(() => res(undefined));
203
+
204
+ return;
205
+ }
206
+ res({
207
+ meta: file.meta || {},
208
+ name: file.name,
209
+ path: file.path,
210
+ resourceType: file.resourceType,
211
+ data: req.response,
212
+ type: isScript ? "js" : "swf",
213
+ });
214
+ });
215
+
216
+ req.send();
217
+ });
218
+ }
219
+
220
+ function loadScript(file, progress) {
221
+ const head = document.querySelector("head");
222
+ const script = document.createElement("script");
223
+
224
+ return new Promise((res, rej) => {
225
+ Object.assign(script, {
226
+ type: "text/javascript",
227
+ async: true,
228
+ src: file.path || file,
229
+ onload: () => {
230
+ progress && progress(1);
231
+ res(script);
232
+ },
233
+ onerror: rej,
234
+ onreadystatechange: s => {
235
+ if (script.readyState == "complete") { }
236
+ },
237
+ });
238
+
239
+ head.appendChild(script);
240
+ });
241
+ }
242
+
243
+ function createReporter(callback, childs, weight) {
244
+ const reporter = {
245
+ callback: callback,
246
+ childs: childs ? childs.slice() : undefined,
247
+ value: 0,
248
+ weight: weight || 1,
249
+
250
+ get report() {
251
+ return function (v) {
252
+ if (!this.childs) {
253
+ this.value = v * this.weight;
254
+ } else {
255
+ let summ = 0;
256
+ let v = 0;
257
+
258
+ this.childs.forEach((e) => {
259
+ summ += e.weight || 1;
260
+ v += (e.value || 0);
261
+ });
262
+
263
+ this.value = v / summ;
264
+ }
265
+
266
+ this.callback && this.callback(this.value);
267
+ }.bind(this);
268
+ },
269
+ };
270
+
271
+ if (childs) {
272
+ childs.forEach(e => {
273
+ e.callback = reporter.report;
274
+ });
275
+ }
276
+
277
+ return reporter;
278
+ }
279
+
280
+ function runLoadingProcess(jsFiles, binaryFiles, progressEvent = f => f, _debugScripts) {
281
+ const jsCount = jsFiles.length;
282
+ const binCount = binaryFiles.length;
283
+
284
+ const all = jsFiles.concat(binaryFiles);
285
+
286
+ const reporters = Array.from({ length: jsCount + binCount }, () => createReporter());
287
+ createReporter(progressEvent, reporters);
288
+
289
+ let pendings;
290
+
291
+ if (!_debugScripts) {
292
+ pendings = all.map((e, i) => loadBinary(e, reporters[i].report));
293
+ } else {
294
+ pendings = binaryFiles.map((e, i) => loadBinary(e, reporters[i].report))
295
+ pendings = pendings.concat(jsFiles.map((e, i) => loadScript(e, reporters[i + binCount].report)))
296
+ }
297
+
298
+ return Promise.all(pendings).then(data => {
299
+ return data.filter(e => e && e.type === 'swf');
300
+ });
301
+ }
302
+
303
+ let fillLine = undefined;
304
+ let __config = undefined;
305
+ let __splash = undefined;
306
+ let __loading = undefined;
307
+ let __pr__root = undefined;
308
+ let __pr__line = undefined;
309
+ let handleResize = undefined;
310
+
311
+ window["setStageDimensions"]=function(x, y, w, h){
312
+ __config.x=x;
313
+ __config.y=y;
314
+ __config.w=w;
315
+ __config.h=h;
316
+ if(window["AVMPlayer"]){
317
+ window["AVMPlayer"].setStageDimensions(x, y, w, h);
318
+ }
319
+ if(handleResize){
320
+ handleResize();
321
+ }
322
+ }
323
+
324
+ function runPlayer(progressEvent = f => f, completeEvent = f => f) {
325
+
326
+ if (!__config) {
327
+ init();
328
+ }
329
+
330
+ let jss = Array.isArray(__config.runtime) ? jss : [__config.runtime];
331
+ jss = jss.map(e => ({ path: e.path || e, size: e.size || 0 }));
332
+
333
+ const bins = __config.binary;
334
+
335
+ const loadReporter = createReporter(null, null, 4);
336
+ const avmReporter = createReporter((f) => {
337
+ console.log('AVM Load', f);
338
+ }, null, __config.progressParserWeigth ? __config.progressParserWeigth : 0.001);
339
+
340
+ createReporter(function (fill) {
341
+ fillLine(fill);
342
+ // rereport
343
+ progressEvent(fill);
344
+ }, [loadReporter, avmReporter])
345
+
346
+ const complete = f => {
347
+ // rereport
348
+ completeEvent(f);
349
+
350
+ const st_conf = __config.start;
351
+ if (st_conf) {
352
+
353
+ // start image exists.
354
+ // hide progressbar, show startimage and wait for user-input to start the game
355
+ Object.assign(__pr__line.style, {
356
+ height: "100%",
357
+ width: "100%",
358
+ });
359
+ Object.assign(__loading.style, {
360
+ backgroundImage: `url(${st_conf.image})`,
361
+ left: `${100 * st_conf.rect[0]}%`,
362
+ top: `${100 * st_conf.rect[1]}%`,
363
+ width: `${100 * st_conf.rect[2]}%`,
364
+ height: `${100 * st_conf.rect[3]}%`,
365
+ cursor: "pointer",
366
+ });
367
+ let onClick = (e) => {
368
+ __loading.removeEventListener("click", onClick);
369
+ __loading.removeEventListener("touchend", onClick);
370
+ Object.assign(__splash.style, {
371
+ visibility: "hidden",
372
+ opacity: 0,
373
+ });
374
+ if (!f)
375
+ throw ("AVMPlayer did not send a callback for starting game");
376
+ f();
377
+ window.setTimeout(()=>{
378
+ window.removeEventListener("resize", handleResize);
379
+ handleResize=null;
380
+ }, 500)
381
+ };
382
+ __loading.addEventListener("click", onClick);
383
+ __loading.addEventListener('touchend', onClick);
384
+ }
385
+ else {
386
+ // no start image.
387
+ // game will be started automatically
388
+ Object.assign(__splash.style, {
389
+ visibility: "hidden",
390
+ opacity: 0,
391
+ });
392
+ // use Timeout, so css transition can complete first
393
+ window.setTimeout(()=>{
394
+ window.removeEventListener("resize", handleResize);
395
+ handleResize=null;
396
+ }, 500)
397
+ }
398
+ };
399
+
400
+ runLoadingProcess(jss, bins, loadReporter.report, __config.debug).then(data => {
401
+ const AVMPlayerClass = window["AVMPlayerClass"];
402
+ if (!AVMPlayerClass) {
403
+ throw "Could not find a 'AVMPlayerClass' definition";
404
+ }
405
+
406
+ __config.files = data;
407
+
408
+ const avmPlayer = new AVMPlayerClass(__config);
409
+
410
+ avmPlayer.addEventListener('loaderComplete', (event) => {
411
+ if (!__config.start) {
412
+ complete();
413
+ avmPlayer.play(__config.skipFramesOfScene);
414
+ return;
415
+ }
416
+ complete(() => avmPlayer.play(__config.skipFramesOfScene));
417
+ });
418
+
419
+ avmPlayer.load();
420
+
421
+
422
+ window["AVMPlayer"] = avmPlayer
423
+ // now awayfl player is available at window["AVMPlayer"]
424
+ // can be used to update the stageDimensions:
425
+ // window["AVMPlayer"].setStageDimensions(x, y, w, h);
426
+ // values can be
427
+ // numbers (absolute pixel values)
428
+ // strings (percentage of window.innerHeight/innerWidth in 0-100)
429
+ });
430
+ }
431
+
432
+ function init(config) {
433
+ if (!config) {
434
+ throw new Error("Config is required");
435
+ }
436
+
437
+ __config = config;
438
+
439
+ const splash = document.querySelector("#splash__image");
440
+ const loading = document.querySelector("#loading__image");
441
+ const pr__root = document.querySelector("#progress__root");
442
+ const pr__line = document.querySelector("#progress__line");
443
+
444
+ __splash = splash;
445
+ __loading = loading;
446
+ __pr__root = pr__root;
447
+ __pr__line = pr__line;
448
+
449
+ const pr_conf = config.progress;
450
+ pr_conf.rect = pr_conf.rect || [0, 0.9, 1, 0.2];
451
+
452
+ Object.assign(splash.style, {
453
+ backgroundImage: `url(${config.splash})`,
454
+ visibility: "visible",
455
+ });
456
+
457
+ const ldg_conf = config.loading;
458
+
459
+ if (ldg_conf) {
460
+ Object.assign(loading.style, {
461
+ backgroundImage: `url(${ldg_conf.image})`,
462
+ left: `${100 * ldg_conf.rect[0]}%`,
463
+ top: `${100 * ldg_conf.rect[1]}%`,
464
+ width: `${100 * ldg_conf.rect[2]}%`,
465
+ height: `${100 * ldg_conf.rect[3]}%`,
466
+ });
467
+ }
468
+
469
+ Object.assign(pr__root.style, {
470
+ background: pr_conf.back,
471
+ left: `${100 * pr_conf.rect[0]}%`,
472
+ top: `${100 * pr_conf.rect[1]}%`,
473
+ width: `${100 * pr_conf.rect[2]}%`,
474
+ height: `${100 * pr_conf.rect[3]}%`,
475
+ });
476
+
477
+ Object.assign(pr__line.style, {
478
+ background: pr_conf.line,
479
+ });
480
+
481
+ fillLine = fill => {
482
+ switch (pr_conf.direction) {
483
+ case "tb": {
484
+ Object.assign(pr__line.style, {
485
+ height: `${fill * 100}%`,
486
+ width: "100%",
487
+ });
488
+ break;
489
+ }
490
+ case "lr":
491
+ default: {
492
+ Object.assign(pr__line.style, {
493
+ height: "100%",
494
+ width: `${fill * 100}%`,
495
+ });
496
+ }
497
+ }
498
+ };
499
+
500
+ handleResize = () => {
501
+ let x=(typeof config.x==="string")?parseFloat(config.x.replace("%", ""))/100*window.innerWidth:config.x;
502
+ let y=(typeof config.y==="string")?parseFloat(config.y.replace("%", ""))/100*window.innerHeight:config.y;
503
+ let w=(typeof config.w==="string")?parseFloat(config.w.replace("%", ""))/100*window.innerWidth:config.w;
504
+ let h=(typeof config.h==="string")?parseFloat(config.h.replace("%", ""))/100*window.innerHeight:config.h;
505
+
506
+ if(!x) x=0;
507
+ if(!y) y=0;
508
+ if(!w) w=window.innerWidth;
509
+ if(!h) h=window.innerHeight;
510
+
511
+ if (config.stageScaleMode == "noBorder") {
512
+
513
+ }
514
+ const minMax = (config.stageScaleMode == "noBorder")
515
+ ? Math.max(h / config.height, w / config.width)
516
+ : Math.min(h / config.height, w / config.width);
517
+ const rw = Math.ceil(config.width * minMax);
518
+ const rh = Math.ceil(config.height * minMax);
519
+ const rx = x+(w - rw) / 2;
520
+ const ry = y+(h - rh) / 2;
521
+
522
+ Object.assign(splash.style, {
523
+ width: `${rw}px`,
524
+ height: `${rh}px`,
525
+ left: `${rx}px`,
526
+ top: `${ry}px`,
527
+ });
528
+ };
529
+
530
+ window.addEventListener("resize", handleResize);
531
+ handleResize();
532
+ }
533
+
534
+ return {
535
+ init,
536
+ runPlayer,
537
+ };
538
+ })();
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "lib": ["es2015.symbol", "dom", "scripthost", "es2015", "es2015.iterable"],
3
+ "lib": ["DOM","ScriptHost", "ESNext"],
4
4
  "target": "es5",
5
5
  "module": "es2015",
6
6
  "moduleResolution": "node",