@urso/core 0.9.4-dev → 0.9.6-dev

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.
@@ -2,7 +2,7 @@ class ExtraBrowserEvents {
2
2
  constructor() {
3
3
  this.singleton = true;
4
4
 
5
- this.RESIZE_DELAY = 250; //delay for resize event (browser will refresh his own params)
5
+ this.RESIZE_DELAY = 0; //delay for resize event (browser will refresh his own params)
6
6
 
7
7
  this._keyPressHandler = this._keyPressHandler.bind(this);
8
8
  this.resizeHandler = this.resizeHandler.bind(this);
@@ -42,7 +42,9 @@ class ExtraBrowserEvents {
42
42
  Urso.clearTimeout(this._resizeTimeoutId)
43
43
 
44
44
  this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_PRE_RESIZE);
45
- this._resizeTimeoutId = Urso.setTimeout(() => this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE), this.RESIZE_DELAY);
45
+ this._resizeTimeoutId = Urso.setTimeout(() =>
46
+ this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE)
47
+ , this.RESIZE_DELAY);
46
48
  }
47
49
 
48
50
  _pointerEventsHandler(event) {
@@ -1,11 +1,6 @@
1
1
  import * as PIXI from 'pixi.js';
2
2
  window.PIXI = PIXI;
3
3
 
4
- // import * as spine from '@esotericsoftware/spine-pixi-v8';
5
- // window.PIXI.spine = spine;
6
-
7
- // import * as particlesFx from 'revolt-fx';
8
- // window.PIXI.particlesFx = particlesFx;
9
4
 
10
5
  import { gsap } from 'gsap';
11
6
  window.gsap = gsap;
@@ -13,11 +8,40 @@ window.gsap = gsap;
13
8
  import { Howler, Howl } from 'howler';
14
9
 
15
10
  window.UrsoUtils = {
16
- Howler: Howler,
17
- Howl: Howl,
18
- gsap: gsap,
19
- PIXI: PIXI
11
+ Howler,
12
+ Howl,
13
+ gsap,
14
+ PIXI
15
+ };
16
+
17
+ const SoundAsset = {
18
+ extension: {
19
+ type: PIXI.ExtensionType.LoadParser,
20
+ name: 'sound-asset-loader',
21
+ priority: 100
22
+ },
23
+
24
+ test(url) {
25
+ return url.endsWith('.mp3') || url.endsWith('.ogg') || url.endsWith('.wav');
26
+ },
27
+
28
+
29
+ async load(url) {
30
+ return new Promise(async (resolve, reject) => {
31
+ try {
32
+ const response = await fetch(url);
33
+ if (!response.ok) {
34
+ throw new Error(`HTTP error! status: ${response.status}`);
35
+ }
36
+ const arrayBuffer = await response.arrayBuffer();
37
+ resolve(arrayBuffer);
38
+ } catch (error) {
39
+ reject(error);
40
+ }
41
+ });
42
+ }
20
43
  };
21
44
 
45
+ PIXI.extensions.add(SoundAsset);
22
46
 
23
47
  export default {}
@@ -37,36 +37,65 @@ class LibCache {
37
37
 
38
38
  for (const key in atlases) {
39
39
  const atlas = atlases[key];
40
-
41
40
  const page = new spine.TextureAtlasPage(key);
42
41
  const { w, h } = atlas.data.meta.size;
43
-
42
+
44
43
  const baseTexture = new spine.SpineTexture(atlas.textureSource);
45
44
 
46
- page.width = w;
47
- page.height = h;
45
+ // Use actual texture dimensions for page (may differ from meta.size due to resolution scaling)
46
+ const texW = atlas.textureSource.pixelWidth || atlas.textureSource.source?.pixelWidth || w;
47
+ const texH = atlas.textureSource.pixelHeight || atlas.textureSource.source?.pixelHeight || h;
48
+
49
+ page.width = texW;
50
+ page.height = texH;
48
51
  page.texture = baseTexture;
49
52
  page.minFilter = page.magFilter = 9729;
50
53
  page.uWrap = page.vWrap = 33071;
51
54
  textureAtlas.pages.push(page);
52
55
 
53
- for (const frameName in atlas._frames) {
54
- const nameSplit = frameName.split('.');
55
- const name = nameSplit.splice(0, nameSplit.length - 1).join('.')
56
- const frame = atlas._frames[frameName];
57
- const region = new spine.TextureAtlasRegion(page, name);
56
+ for (const frameName in atlas.data.frames) {
57
+ let normalizedName = frameName;
58
+ if (frameName.includes('.')) {
59
+ const nameSplit = frameName.split('.');
60
+ normalizedName = nameSplit.splice(0, nameSplit.length - 1).join('.');
61
+ }
62
+
63
+ const frame = atlas.data.frames[frameName];
64
+ const region = new spine.TextureAtlasRegion(page, normalizedName);
58
65
 
59
- region.width = frame.frame.w;
60
- region.height = frame.frame.h;
61
- region.u = frame.frame.x / baseTexture.texture.width;
62
- region.v = frame.frame.y / baseTexture.texture.height;
63
- region.u2 = (frame.frame.x + frame.frame.w) / baseTexture.texture.width;
64
- region.v2 = (frame.frame.y + frame.frame.h) / baseTexture.texture.height;
65
- region.rotate = false;
66
+ // Check if frame is rotated (TexturePacker boolean or 90 marker)
67
+ const isRotated = frame.rotated === true || frame.rotated === 90;
68
+
69
+ // Frame rect in the atlas (pixels)
70
+ const fx = frame.frame.x;
71
+ const fy = frame.frame.y;
72
+ const fw = frame.frame.w;
73
+ const fh = frame.frame.h;
74
+
75
+ // Region size (swap on rotation)
76
+ region.width = isRotated ? fh : fw;
77
+ region.height = isRotated ? fw : fh;
78
+
79
+ region.u = fx / texW;
80
+ region.v = fy / texH;
81
+ region.u2 = (fx + fw) / texW;
82
+ region.v2 = (fy + fh) / texH;
83
+ region.degrees = isRotated ? 90 : 0;
84
+
85
+ // Original (untrimmed) size - already at export scale in JSON
66
86
  region.originalWidth = frame.sourceSize.w;
67
87
  region.originalHeight = frame.sourceSize.h;
68
- region.texture = baseTexture;
69
88
 
89
+ // Offsets relative to original rect (bottom-left)
90
+ if (frame.spriteSourceSize) {
91
+ region.offsetX = frame.spriteSourceSize.x;
92
+ region.offsetY = frame.sourceSize.h - frame.spriteSourceSize.y - frame.spriteSourceSize.h;
93
+ } else {
94
+ region.offsetX = 0;
95
+ region.offsetY = 0;
96
+ }
97
+
98
+ region.texture = baseTexture;
70
99
  textureAtlas.regions.push(region);
71
100
  }
72
101
  }
@@ -130,6 +159,11 @@ class LibCache {
130
159
  };
131
160
 
132
161
  addTexture(key, someData) {
162
+ if(key.includes('.')) {
163
+ const keySplit = key.split('.');
164
+ key = keySplit.splice(0, keySplit.length - 1).join('.')
165
+ }
166
+
133
167
  this._setDataToAssetsList('texture', key, someData);
134
168
  };
135
169
 
@@ -1,153 +1,367 @@
1
- /**
2
- * @deprecated
3
- * tween interface over gsap timeline
4
- */
5
- class LibTween {
6
-
1
+ /* eslint-disable object-shorthand */
2
+ /* eslint-disable max-len */
3
+ /* eslint-disable no-setter-return */
4
+ /* eslint-disable guard-for-in */
5
+ /* eslint-disable no-restricted-syntax */
6
+ /* eslint-disable quote-props */
7
+ /* eslint-disable quotes */
8
+ /* eslint-disable func-names */
9
+ class Tween {
7
10
  constructor() {
8
11
  this.singleton = true;
9
12
 
10
- this._tweenIndex = 0;
11
13
  this._tweens = {};
14
+ this._currentTime = 0;
15
+ this._tweenIndex = 0;
16
+
17
+ Object.defineProperties(this, {
18
+ "globalTimeScale": {
19
+ "get": function () { return Urso.scenes.timeScale; },
20
+ "set": function () { Urso.logger.error('ComponentsSlotMachineTween: you cannot set globalTimeScale'); },
21
+ },
22
+ });
23
+
24
+ this.tweens = this._tweens;
25
+ this._subscibe();
26
+ }
27
+
28
+ // sys
29
+ update() {
30
+ this._update();
12
31
  }
13
32
 
14
33
  removeAll() {
15
- for (let k in this._tweens)
34
+ for (const k in this._tweens) {
16
35
  this._tweens[k].stop();
17
-
18
- this._tweens = {};
19
- };
36
+ }
37
+ }
20
38
 
21
39
  add(object) {
22
40
  const key = this._keyGenerate();
23
-
24
- const tl = gsap.timeline({
25
- repeat: 1,
26
- onComplete: () => { this._onCompleteHandler(key) },
27
- onUpdate: () => { this._onUpdateHandler(key) }
28
- });
29
-
41
+ const _this = this;
30
42
  const tween = {
31
43
  id: key,
32
44
  isRunning: false,
45
+ enableUpdate: false,
33
46
  target: object,
34
47
  to: this._to,
35
48
  start: this._start,
36
49
  pause: this._pause,
37
50
  resume: this._resume,
38
51
  stop: this._stop,
52
+ points: [],
53
+ manager: this,
39
54
 
40
55
  _timeScale: 1,
41
56
  get timeScale() {
42
57
  return this._timeScale;
43
- }, set timeScale(a) {
58
+ },
59
+ set timeScale(a) {
60
+ if (this._timeScale === a || !this.points[0]) {
61
+ return this._timeScale;
62
+ }
63
+
64
+ const timeDiff = ~~(_this._currentTime - this.points[0].timeStart) * (_this.globalTimeScale * this._timeScale);
65
+
66
+ if (this.points[0].duration - timeDiff <= 0) {
67
+ return this._timeScale;
68
+ }
69
+
70
+ this.points[0].duration -= timeDiff;
71
+ this.points[0].timeStart = _this._currentTime;
72
+
73
+ // update current point data
74
+ for (const k in this.points[0].propsTo) {
75
+ this.points[0].propsFrom[k] = this.target[k];
76
+ }
77
+
78
+ this._timeScale = a;
79
+
44
80
  return this._timeScale;
45
81
  },
46
- _timeline: tl,
82
+
83
+ _started: false,
84
+ _paused: false,
85
+ _pauseTime: false,
86
+ _timeBonus: 0,
47
87
  _complete: false,
48
- _paused: true,
88
+ _bkp: {
89
+ points: [],
90
+ obj: null,
91
+ },
49
92
  _functions: {
50
93
  onStart: [],
94
+ onStartOnce: [],
51
95
  onUpdate: [],
52
- onComplete: []
53
- }
96
+ onComplete: [],
97
+ onCompleteOnce: [],
98
+ },
54
99
  };
55
100
 
56
- //need to add some functions
101
+ // need to add some functions
57
102
  tween.onComplete = {
58
- add: (f) => {
103
+ addOnce: function (f) {
104
+ tween._functions.onCompleteOnce.push(f);
105
+ return tween;
106
+ },
107
+ add: function (f) {
59
108
  tween._functions.onComplete.push(f);
60
109
  return tween;
61
- }
110
+ },
62
111
  };
63
112
 
64
113
  tween.onStart = {
65
- add: (f) => {
114
+ addOnce: function (f) {
115
+ tween._functions.onStartOnce.push(f);
116
+ return tween;
117
+ },
118
+ add: function (f) {
66
119
  tween._functions.onStart.push(f);
67
120
  return tween;
68
- }
121
+ },
69
122
  };
70
123
 
71
- tween.onUpdate = {
72
- add: (f) => {
73
- tween._functions.onUpdate.push(f);
74
- return tween;
75
- }
124
+ tween.onUpdateCallback = function (f) {
125
+ tween._functions.onUpdate.push(f);
126
+ return tween;
76
127
  };
77
128
 
78
129
  this._tweens[key] = tween;
79
130
 
80
131
  return tween;
81
- };
132
+ }
82
133
 
83
- _keyGenerate() {
84
- this._tweenIndex++;
85
- return (new Date()).getTime() + '_' + this._tweenIndex;
86
- };
134
+ _to(propsTo, duration, easing, autostart, startDelay) {
135
+ const propsFrom = {};
87
136
 
88
- //todo easing
89
- _to(propsTo, duration, easing = undefined, autostart = false, startDelay = 0) {
90
- const params = Urso.helper.objectClone(propsTo, 10);
91
- params.duration = duration / 1000;
92
- params.easing = easing;
93
- params.delay = startDelay;
137
+ for (const k in propsTo) {
138
+ propsFrom[k] = this.target[k];
139
+ }
140
+
141
+ if (!startDelay) {
142
+ startDelay = 0;
143
+ }
144
+
145
+ const timeStart = this.manager._currentTime + startDelay;
146
+ const point = {
147
+ propsTo,
148
+ duration,
149
+ easing,
150
+ propsFrom,
151
+ timeStart,
152
+ startDelay,
153
+ };
94
154
 
95
- this._timeline.to(this.target, params);
96
- //this.pause();
155
+ this.points.push(point);
156
+ this._complete = false;
97
157
 
98
- if (autostart)
158
+ if (autostart) {
99
159
  this.start();
160
+ }
100
161
 
101
162
  return this;
102
- };
163
+ }
103
164
 
104
165
  _start() {
105
- for (let i = 0; i < this._functions.onStart.length; i++)
166
+ if (this.isRunning || !this.points || (this.points.length === 0 && this._bkp.points.length === 0)) {
167
+ return this;
168
+ }
169
+
170
+ if (this.points.length === 0 && this._bkp.points.length > 0) {
171
+ this.points = this._bkp.points;
172
+ const key = this.manager._keyGenerate();
173
+ this.manager._tweens[key] = this;
174
+ }
175
+
176
+ this.points[0].timeStart = this.manager._currentTime + this.points[0].startDelay;
177
+
178
+ this._bkp = {
179
+ points: Urso.helper.objectClone(this.points),
180
+ obj: null, // TODO save states for all points
181
+ };
182
+
183
+ this._started = true;
184
+ this.isRunning = true;
185
+ this._complete = false;
186
+
187
+ for (let i = 0; i < this._functions.onStartOnce.length; i++) {
188
+ this._functions.onStartOnce[i]();
189
+ }
190
+
191
+ for (let i = 0; i < this._functions.onStart.length; i++) {
106
192
  this._functions.onStart[i]();
193
+ }
194
+
195
+ if (this._timeBonus > 0) {
196
+ this.manager._calcStep(this, true);
197
+ }
107
198
 
108
- this.resume();
109
199
  return this;
110
- };
200
+ }
111
201
 
112
202
  _pause() {
113
203
  this._paused = true;
114
204
  this.isRunning = false;
115
- this._timeline.pause();
205
+ this._pauseTime = this.manager._currentTime;
116
206
 
117
207
  return this;
118
- };
208
+ }
119
209
 
120
210
  _resume() {
211
+ if (this.points && this.points[0]) {
212
+ this.points[0].timeStart += (this.manager._currentTime - this._pauseTime);
213
+ }
214
+
121
215
  this._paused = false;
122
216
  this.isRunning = true;
123
- this._timeline.resume();
217
+ this._pauseTime = 0;
124
218
 
125
219
  return this;
126
- };
220
+ }
127
221
 
128
222
  _stop() {
129
- this.pause();
130
- this._timeline.kill();
131
223
  this._complete = true;
224
+ this.isRunning = false;
225
+ delete this.manager._tweens[this.id];
132
226
 
133
227
  return this;
134
- };
228
+ }
229
+
230
+ _update() {
231
+ const curTime = (new Date()).getTime();
232
+
233
+ // pause ?
234
+ if (this.gamePaused) {
235
+ const delta = curTime - this._currentTime;
236
+
237
+ for (const k in this._tweens) {
238
+ if (this._tweens[k].points && this._tweens[k].points[0]) {
239
+ this._tweens[k].points[0].timeStart += delta;
240
+ }
241
+ }
242
+
243
+ return true;
244
+ }
245
+
246
+ this._currentTime = curTime;
247
+
248
+ for (const k in this._tweens) {
249
+ if (this._tweens[k]._complete) {
250
+ delete this._tweens[k]
251
+ continue; // todo remove old Tweens to garbage collect them (delete this._tweens[k];) if tween dont using in 1-5 min ?
252
+ } else if (this._tweens[k]._started && !this._tweens[k]._paused) {
253
+ this._calcStep(this._tweens[k]);
254
+ }
255
+ }
256
+ return true;
257
+ }
258
+
259
+ _keyGenerate() {
260
+ this._tweenIndex++;
261
+ return `${this._currentTime}_${this._tweenIndex}`;
262
+ }
263
+
264
+ _calcStep(tween, onStartCall) {
265
+ const point = tween.points[0]; // {propsTo: propsTo, duration: duration, easing: easing, propsFrom: propsFrom, timeStart: this._currentTime}
266
+
267
+ if (this._currentTime < point.timeStart) {
268
+ return false;
269
+ }
270
+
271
+ const progress = this._applyDelta(tween, point, onStartCall);
272
+
273
+ const tweenData = {
274
+ percent: +progress.toFixed(3),
275
+ vEnd: point.propsTo,
276
+ };
277
+
278
+ for (let i = 0; i < tween._functions.onUpdate.length; i++) {
279
+ tween._functions.onUpdate[i](tween, progress, tweenData);
280
+ }
281
+
282
+ // complete
283
+ if (progress === 1) {
284
+ tween.points.shift();
285
+
286
+ if (tween.points.length === 0) {
287
+ // no points
288
+ tween._complete = true;
289
+ tween.isRunning = false;
290
+ const { onComplete } = tween._functions;
291
+ const { onCompleteOnce } = tween._functions;
292
+
293
+ tween._functions.onStartOnce = [];
294
+ tween._functions.onCompleteOnce = [];
295
+
296
+ if (!tween.enableUpdate) {
297
+ tween._functions.onStart = [];
298
+ tween._functions.onUpdate = [];
299
+ tween._functions.onComplete = [];
300
+ }
301
+
302
+ for (let i = 0; i < onCompleteOnce.length; i++) {
303
+ onCompleteOnce[i]();
304
+ }
135
305
 
136
- _onUpdateHandler(tweenKey) {
137
- const tween = this._tweens[tweenKey];
138
- const percentage = ~~(tween._timeline.progress() * 100);
306
+ for (let i = 0; i < onComplete.length; i++) {
307
+ onComplete[i]();
308
+ }
309
+ } else {
310
+ // next point
311
+ const { startDelay } = tween.points[0];
139
312
 
140
- for (let i = 0; i < tween._functions.onUpdate.length; i++)
141
- tween._functions.onUpdate[i](tween, percentage);
313
+ // calc step for new point
314
+ tween.points[0].timeStart = this._currentTime + startDelay;
315
+
316
+ // update start data
317
+ for (const k in tween.points[0].propsTo) {
318
+ tween.points[0].propsFrom[k] = tween.target[k];
319
+ }
320
+
321
+ if (startDelay) {
322
+ setTimeout(function () {
323
+ this._calcStep(tween);
324
+ }, startDelay);
325
+ } else {
326
+ this._calcStep(tween);
327
+ }
328
+ }
329
+ }
330
+
331
+ return true;
142
332
  }
143
333
 
144
- _onCompleteHandler(tweenKey) {
145
- const tween = this._tweens[tweenKey];
146
- const onComplete = tween._functions.onComplete;
334
+ _applyDelta(tween, point, onStartCall) {
335
+ if (tween._timeBonus > 0) {
336
+ point.timeStart -= tween._timeBonus;
337
+ tween._timeBonus = 0;
338
+ }
339
+
340
+ const time = this._currentTime;
341
+ let progress = (time - point.timeStart) * tween.timeScale * (this.globalTimeScale / point.duration); // 0-1
342
+
343
+ // cannot finish tween onstart in one tick (callbacks magic)
344
+ if (progress >= 1 && onStartCall) {
345
+ progress = 0.99;
346
+ }
347
+
348
+ if (progress > 1) {
349
+ progress = 1;
350
+
351
+ tween._timeBonus = ~~((time - point.timeStart) - point.duration / (tween.timeScale * this.globalTimeScale));
352
+ }
353
+
354
+ // apply objects props
355
+ for (const k in point.propsTo) {
356
+ tween.target[k] = point.propsFrom[k] + (point.propsTo[k] - point.propsFrom[k]) * progress;
357
+ }
358
+
359
+ return progress;
360
+ }
147
361
 
148
- for (let i = 0; i < onComplete.length; i++)
149
- onComplete[i]();
362
+ _subscibe() {
363
+ this.addListener(Urso.events.MODULES_SCENES_UPDATE, this._update.bind(this), true);
150
364
  }
151
365
  }
152
366
 
153
- export default LibTween;
367
+ export default Tween;
@@ -541,9 +541,15 @@ class ModulesAssetsService {
541
541
 
542
542
  const widthFactor = width / resCfg.width;
543
543
 
544
- return Object
544
+ const quality = Object
545
545
  .keys(qualityFactors)
546
546
  .reduce(...this._qualityReducer(qualityFactors, widthFactor));
547
+
548
+ if(isMobile && quality === 'high') {
549
+ return 'hd';
550
+ }
551
+
552
+ return quality;
547
553
  }
548
554
 
549
555
  /**
@@ -27,7 +27,7 @@ class ModulesI18nController {
27
27
  if (!jsonResource)
28
28
  return Urso.logger.error('ModulesI18nController setLocale error, no loaded json:' + localeKey + '. Check assets please');
29
29
 
30
- this.#vocabulary = jsonResource.data;
30
+ this.#vocabulary = jsonResource;
31
31
  this.emit(Urso.events.MODULES_I18N_NEW_LOCALE_WAS_SET, localeKey);
32
32
  }
33
33
 
@@ -71,7 +71,7 @@ class ModulesLogicSounds {
71
71
  if (!json)
72
72
  continue;
73
73
 
74
- audiospriteData[audiospriteKey] = { json: json.data, audiosprite: audiosprite.data };
74
+ audiospriteData[audiospriteKey] = { json, audiosprite };
75
75
  }
76
76
 
77
77
  return audiospriteData;
@@ -58,6 +58,10 @@ export default class ModulesObjectsBaseModel {
58
58
  this.custom = Urso.helper.recursiveGet('custom', params, {}); //custom params
59
59
  }
60
60
 
61
+ modifyValue(key, val) {
62
+ return val;
63
+ }
64
+
61
65
  getAbsoluteSize() {
62
66
  return { width: this._baseObject.width, height: this._baseObject.height };
63
67
  }
@@ -1,5 +1,5 @@
1
1
  import ModulesObjectsBaseModel from './../baseModel';
2
- // import * as particlesFx from 'revolt-fx';
2
+ import * as particlesFx from '@urso/revolt-fx';
3
3
 
4
4
  class ModulesObjectsModelsEmitterFx extends ModulesObjectsBaseModel {
5
5
  constructor(params) {
@@ -76,16 +76,16 @@ class ModulesObjectsModelsEmitterFx extends ModulesObjectsBaseModel {
76
76
  };
77
77
 
78
78
  _createBundle() {
79
- // this._bundle = new particlesFx.FX();
80
- // let fx_settings_data = Urso.cache.getJson(this.cfg);
79
+ this._bundle = new particlesFx.FX();
80
+ let fx_settings_data = Urso.cache.getJson(this.cfg);
81
81
 
82
- // if (this.spritesheetFilter)
83
- // fx_settings_data.spritesheetFilter = this.spritesheetFilter;
82
+ if (this.spritesheetFilter)
83
+ fx_settings_data.spritesheetFilter = this.spritesheetFilter;
84
84
 
85
- // this._defaultEmitterName = fx_settings_data.emitters[0].name;
85
+ this._defaultEmitterName = fx_settings_data.emitters[0].name;
86
86
 
87
- // this._bundle.initBundle(fx_settings_data);
88
- // this.autostart && this.play();
87
+ this._bundle.initBundle(fx_settings_data);
88
+ this.autostart && this.play();
89
89
  }
90
90
 
91
91
  _subscribeOnce() {