@makefully/platypus 4.1.5 → 4.1.6

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.
Files changed (136) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +3 -3
  3. package/lib/platypus.js +1 -1
  4. package/package.json +6 -5
  5. package/src/AABB.js +685 -0
  6. package/src/ActionState.js +121 -0
  7. package/src/AssetManager.js +206 -0
  8. package/src/CollisionData.js +96 -0
  9. package/src/CollisionDataContainer.js +127 -0
  10. package/src/CollisionShape.js +315 -0
  11. package/src/Component.js +231 -0
  12. package/src/Data.js +64 -0
  13. package/src/DataMap.js +204 -0
  14. package/src/Entity.js +404 -0
  15. package/src/EntityLinker.js +113 -0
  16. package/src/EventHandler.js +115 -0
  17. package/src/EventHandlerList.js +251 -0
  18. package/src/Game.js +840 -0
  19. package/src/Gamepad.js +175 -0
  20. package/src/ID3CaptionPlayer.js +61 -0
  21. package/src/Messenger.js +365 -0
  22. package/src/PIXIAnimation.js +622 -0
  23. package/src/RandomSet.js +140 -0
  24. package/src/SFXPlayer.js +120 -0
  25. package/src/StateMap.js +252 -0
  26. package/src/Storage.js +152 -0
  27. package/src/TickerClient.js +48 -0
  28. package/src/TickerServer.js +23 -0
  29. package/src/TimeEvent.js +50 -0
  30. package/src/TimeEventList.js +100 -0
  31. package/src/VOPlayer.js +684 -0
  32. package/src/Vector.js +702 -0
  33. package/src/components/AIChaser.js +161 -0
  34. package/src/components/AIPacer.js +107 -0
  35. package/src/components/AudioMusic.js +151 -0
  36. package/src/components/AudioSFX.js +673 -0
  37. package/src/components/AudioVO.js +301 -0
  38. package/src/components/CollisionBasic.js +826 -0
  39. package/src/components/CollisionFilter.js +74 -0
  40. package/src/components/CollisionGroup.js +448 -0
  41. package/src/components/CollisionTiles.js +608 -0
  42. package/src/components/ComponentSwitcher.js +173 -0
  43. package/src/components/ControllerInput.js +65 -0
  44. package/src/components/Counter.js +165 -0
  45. package/src/components/EntityCamera.js +215 -0
  46. package/src/components/EntityContainer.js +549 -0
  47. package/src/components/EntityController.js +541 -0
  48. package/src/components/HandlerCamera.js +1052 -0
  49. package/src/components/HandlerCollision.js +1318 -0
  50. package/src/components/HandlerController.js +291 -0
  51. package/src/components/HandlerLogic.js +394 -0
  52. package/src/components/HandlerRender.js +217 -0
  53. package/src/components/Interactive.js +502 -0
  54. package/src/components/LevelBuilder.js +524 -0
  55. package/src/components/LogicAngularMovement.js +154 -0
  56. package/src/components/LogicAttachment.js +265 -0
  57. package/src/components/LogicButton.js +466 -0
  58. package/src/components/LogicCarrier.js +39 -0
  59. package/src/components/LogicDestroyMe.js +58 -0
  60. package/src/components/LogicDirectionalMovement.js +325 -0
  61. package/src/components/LogicDragDrop.js +371 -0
  62. package/src/components/LogicImpactLaunch.js +144 -0
  63. package/src/components/LogicPacingPlatform.js +64 -0
  64. package/src/components/LogicPortable.js +112 -0
  65. package/src/components/LogicPortal.js +115 -0
  66. package/src/components/LogicPushable.js +98 -0
  67. package/src/components/LogicRebounder.js +136 -0
  68. package/src/components/LogicRegionSpawner.js +139 -0
  69. package/src/components/LogicRotationalMovement.js +205 -0
  70. package/src/components/LogicSpawner.js +159 -0
  71. package/src/components/LogicStateMachine.js +382 -0
  72. package/src/components/LogicSwitch.js +77 -0
  73. package/src/components/LogicTeleportee.js +68 -0
  74. package/src/components/LogicTeleporter.js +93 -0
  75. package/src/components/LogicTimer.js +178 -0
  76. package/src/components/LogicWindUpRacer.js +179 -0
  77. package/src/components/Motion.js +371 -0
  78. package/src/components/Mover.js +566 -0
  79. package/src/components/Node.js +289 -0
  80. package/src/components/NodeMap.js +295 -0
  81. package/src/components/NodeResident.js +636 -0
  82. package/src/components/Orientation.js +697 -0
  83. package/src/components/RandomEvents.js +73 -0
  84. package/src/components/RelativePosition.js +204 -0
  85. package/src/components/RelayFamily.js +106 -0
  86. package/src/components/RelayGame.js +53 -0
  87. package/src/components/RelayLinker.js +94 -0
  88. package/src/components/RelayParent.js +57 -0
  89. package/src/components/RelaySelf.js +55 -0
  90. package/src/components/Render.js +178 -0
  91. package/src/components/RenderAnimator.js +275 -0
  92. package/src/components/RenderContainer.js +646 -0
  93. package/src/components/RenderDebug.js +319 -0
  94. package/src/components/RenderDestroyMe.js +59 -0
  95. package/src/components/RenderLottie.js +149 -0
  96. package/src/components/RenderProgress.js +120 -0
  97. package/src/components/RenderSpine.js +833 -0
  98. package/src/components/RenderSprite.js +527 -0
  99. package/src/components/RenderText.js +147 -0
  100. package/src/components/RenderTiles.js +1391 -0
  101. package/src/components/SceneChanger.js +128 -0
  102. package/src/components/TiledLoader.js +1451 -0
  103. package/src/components/Timeline.js +314 -0
  104. package/src/components/Tutorial.js +267 -0
  105. package/src/components/Tween.js +296 -0
  106. package/src/components/VoiceOver.js +373 -0
  107. package/src/components/XHR.js +129 -0
  108. package/src/components/index.js +79 -0
  109. package/src/factory.js +305 -0
  110. package/src/index.js +159 -0
  111. package/src/mixins/PIXI.Graphics.js +41 -0
  112. package/src/platypus.css +68 -0
  113. package/src/sayHello.js +50 -0
  114. package/src/shapes/Capsule.js +74 -0
  115. package/src/shapes/Circle.js +43 -0
  116. package/src/shapes/Ellipse.js +117 -0
  117. package/src/shapes/Point.js +191 -0
  118. package/src/shapes/Polygon.js +112 -0
  119. package/src/shapes/Polyline.js +97 -0
  120. package/src/shapes/Rectangle.js +78 -0
  121. package/src/shapes/RoundedRectangle.js +33 -0
  122. package/src/shapes/Segment.js +346 -0
  123. package/src/shapes/adjustedXY.js +19 -0
  124. package/src/shapes/castFromBox2D.js +92 -0
  125. package/src/shapes/castFromObject.js +53 -0
  126. package/src/shapes/castFromPixiGraphics.js +6 -0
  127. package/src/shapes/castFromPixiShape.js +89 -0
  128. package/src/shapes/castToBox2D.js +190 -0
  129. package/src/shapes/castToPixiGraphics.js +100 -0
  130. package/src/shapes/castToPixiShape.js +61 -0
  131. package/src/shapes/checkPointsMap.js +313 -0
  132. package/src/shapes/index.js +35 -0
  133. package/src/utils/array.js +73 -0
  134. package/src/utils/string.js +39 -0
  135. package/lib/243.platypus.mjs +0 -1
  136. package/lib/platypus.mjs +0 -1
@@ -0,0 +1,140 @@
1
+ import recycle from 'recycle';
2
+
3
+ export default (function () {
4
+
5
+ /**
6
+ * This class defines a set that is populated and then pulled from at random. When pulled from, the set will return copies of the contents
7
+ * such that all the contents in the set are used once before there are repeats. Repeats may still occur when the set has been used
8
+ * up or when the number of items requested is greater than the size of the set.
9
+ *
10
+ * @memberof platypus
11
+ * @class RandomSet
12
+ * @param contents {array} The contents that will populate the set.
13
+ * @return {platypus.RandomSet} Returns the new RandomSet object.
14
+ */
15
+ const RandomSet = function (contents) {
16
+ let x = 0;
17
+
18
+ if (contents) {
19
+ this.contents = [];
20
+ for (x = 0; x < contents.length; x++) {
21
+ this.contents.push(contents[x]);
22
+ }
23
+ } else {
24
+ this.contents = [];
25
+ }
26
+ this.availableIndexes = [];
27
+
28
+ this.refill();
29
+ },
30
+ proto = RandomSet.prototype;
31
+
32
+
33
+ proto.refill = function () {
34
+ let x = 0;
35
+
36
+ for (x = 0; x < this.contents.length; x++) {
37
+ this.availableIndexes.push(x);
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Add single element to the content set. Includes the new content in the current set, which means it be returned quickly depending on the remaining set size.
43
+ *
44
+ * @method platypus.RandomSet#add
45
+ * @param toAdd {primitive|Object} Content to add to the set.
46
+ */
47
+ proto.add = function (toAdd) {
48
+ this.contents.push(toAdd);
49
+ this.availableIndexes.push(this.contents.length - 1);
50
+ };
51
+
52
+ /**
53
+ * Remove from the content set. Use removeAll if you want to remove all instances, otherwise only removes the first instance found.
54
+ *
55
+ * @method platypus.RandomSet#remove
56
+ * @param toRemove {primitive|Object} Content to remove from the set.
57
+ * @param removeAll {boolean} Remove all instances of the primitive/object.
58
+ */
59
+ proto.remove = function (toRemove, removeAll) {
60
+ let index = -1,
61
+ indexesIndex = -1;
62
+
63
+ do {
64
+ index = this.contents.indexOf(toRemove);
65
+ if (index !== -1) {
66
+ this.contents.splice(index, 1);
67
+
68
+ indexesIndex = this.availableIndexes.indexOf(index);
69
+ this.availableIndexes.splice(indexesIndex, 1);
70
+
71
+ // Now we need to re-index entries above index...
72
+ for (let i = 0; i < this.availableIndexes; i++) {
73
+ if (this.availableIndexes[i] > index) {
74
+ this.availableIndexes[i] -= 1;
75
+ }
76
+ }
77
+ }
78
+ } while (index !== -1 && removeAll);
79
+
80
+ };
81
+
82
+ /**
83
+ * Get a random member of the set.
84
+ *
85
+ * @method platypus.RandomSet#get
86
+ * @return {primitive|Object} A random member of the set
87
+ */
88
+ proto.get = function () {
89
+ let index = 0;
90
+
91
+ if (this.availableIndexes.length === 0) {
92
+ this.refill();
93
+ }
94
+
95
+ index = this.availableIndexes.splice(Math.floor(Math.random() * this.availableIndexes.length), 1)[0];
96
+
97
+ return this.contents[index];
98
+ };
99
+
100
+ /**
101
+ * Get an array of random set members. There may be multiple of the same member in the set if the quantity requested is greater
102
+ * than the set size, or the set is exhausted and replenished while retrieving members.
103
+ *
104
+ * @method platypus.RandomSet#getMultiple
105
+ * @param numberToGet {integer} Number of set members to retrieve
106
+ * @return {primitive|Object} A random member of the set
107
+ */
108
+ proto.getMultiple = function (numberToGet) {
109
+ const toReturn = [];
110
+ let x = 0;
111
+
112
+ for (x = 0; x < numberToGet; x++) {
113
+ toReturn.push(this.get());
114
+ }
115
+
116
+ return toReturn;
117
+ };
118
+
119
+
120
+ /**
121
+ * Returns an RandomSet from cache or creates a new one if none are available.
122
+ *
123
+ * @method platypus.RandomSet.setUp
124
+ * @return {platypus.RandomSet} The instantiated RandomSet.
125
+ */
126
+ /**
127
+ * Returns a RandomSet back to the cache.
128
+ *
129
+ * @method platypus.RandomSet.recycle
130
+ * @param {platypus.RandomSet} randomSet The RandomSet to be recycled.
131
+ */
132
+ /**
133
+ * Relinquishes properties of the RandomSet and recycles it.
134
+ *
135
+ * @method platypus.RandomSet#recycle
136
+ */
137
+ recycle.add(RandomSet, 'RandomSet', RandomSet, null, true);
138
+
139
+ return RandomSet;
140
+ }());
@@ -0,0 +1,120 @@
1
+ /* global platypus */
2
+ import {arrayCache, greenSplice} from './utils/array.js';
3
+ import TweenJS from '@tweenjs/tween.js';
4
+
5
+ const
6
+ {Tween} = TweenJS;
7
+
8
+ /**
9
+ * This class plays sfx audio and manages Springroll volume changes.
10
+ *
11
+ * @memberof platypus
12
+ * @class SFXPlayer
13
+ */
14
+ export default class SFXPlayer {
15
+ constructor () {
16
+ this.masterVolume = 1;
17
+ this.volume = 1;
18
+ this.playingAudio = arrayCache.setUp();
19
+ }
20
+
21
+ /**
22
+ * Plays a sound.
23
+ *
24
+ * @method platypus.SFXPlayer#play
25
+ * @param {String} sound Sound Id to play.
26
+ * @param {Object} data PixiSound data to inform sound playback.
27
+ * @return {pixiSound.MediaInstance} The media instance of the playing sound.
28
+ * @public
29
+ */
30
+ play (sound, data) {
31
+ const
32
+ sfx = typeof sound === 'string' ? platypus.assetCache.get(platypus.assetCache.getFileId(sound)) : sound,
33
+ audio = sfx.play(data);
34
+
35
+ audio.initialVolume = (typeof data.initialVolume === 'number' ? data.initialVolume : audio.volume);
36
+ audio.set('volume', audio.volume * this.volume * this.masterVolume);
37
+ this.playingAudio.push(audio);
38
+ audio.on('end', () => {
39
+ const index = this.playingAudio.indexOf(audio);
40
+
41
+ greenSplice(this.playingAudio, index);
42
+ });
43
+
44
+ return audio;
45
+ }
46
+
47
+ /**
48
+ * Plays a sound.
49
+ *
50
+ * @method platypus.SFXPlayer#stop
51
+ * @param {pixiSound.MediaInstance} audio Audio to stop.
52
+ * @public
53
+ */
54
+ stop (audio) {
55
+ const index = this.playingAudio.indexOf(audio);
56
+
57
+ audio.stop();
58
+ if (index >= 0) {
59
+ greenSplice(this.playingAudio, index);
60
+ } else {
61
+ platypus.debug.warn('SFXPlayer: Did not find "' + audio.soundId + '"');
62
+ }
63
+ }
64
+
65
+ fade (audio, volume, time, onComplete = () => {}) {
66
+ const
67
+ tween = new Tween(audio);
68
+
69
+ tween.to({
70
+ initialVolume: volume
71
+ }, time);
72
+ tween.onUpdate(() => {
73
+ audio.set('volume', audio.initialVolume * this.volume * this.masterVolume);
74
+ });
75
+ tween.onComplete(onComplete);
76
+ tween.start();
77
+ }
78
+
79
+ /**
80
+ * Sets volume on all playing sound effects.
81
+ *
82
+ * @method platypus.SFXPlayer#setVolume
83
+ * @param {Number} volume A value between 0-1 to set volume on all playing sound effects.
84
+ * @public
85
+ */
86
+ setVolume (volume) {
87
+ const
88
+ playingAudio = this.playingAudio;
89
+
90
+ this.volume = volume;
91
+ for (let i = 0; i < playingAudio.length; i++) {
92
+ const
93
+ audio = playingAudio[i];
94
+
95
+ audio.set('volume', audio.initialVolume * this.volume * this.masterVolume);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Sets master volume on all playing sound effects.
101
+ *
102
+ * @method platypus.SFXPlayer#setMasterVolume
103
+ * @param {Number} volume A value between 0-1 to set volume on all playing sound effects.
104
+ * @public
105
+ */
106
+ setMasterVolume (volume) {
107
+ this.masterVolume = volume;
108
+ this.setVolume(this.volume);
109
+ }
110
+
111
+ /**
112
+ * Cleans up this SFXPlayer.
113
+ * @method platypus.SFXPlayer#destroy
114
+ * @public
115
+ */
116
+ destroy () {
117
+ arrayCache.recycle(this.playingAudio);
118
+ this.playingAudio = null;
119
+ }
120
+ };
@@ -0,0 +1,252 @@
1
+ import DataMap from './DataMap.js';
2
+ import {arrayCache} from './utils/array.js';
3
+ import {greenSplit} from './utils/string.js';
4
+ import recycle from 'recycle';
5
+
6
+ /**
7
+ * This class defines a state object to use for entity states with helper methods. It includes recycle methods to encourage reuse.
8
+ *
9
+ * @memberof platypus
10
+ * @class StateMap
11
+ * @extends platypus.DataMap
12
+ * @return stateMap {platypus.StateMap} Returns the new StateMap object.
13
+ */
14
+ const
15
+ clean = function (arr) {
16
+ const
17
+ cleaned = arrayCache.setUp();
18
+
19
+ if (typeof arr[0] === 'string') {
20
+ for (let i = 0; i < arr.length; i++) {
21
+ cleaned.push((i % 2) ? !!arr[i] : arr[i]);
22
+ }
23
+ } else if (typeof arr[0] === 'object') {
24
+ const
25
+ obj = arr[0];
26
+
27
+ if (obj.keys && obj.get) {
28
+ const
29
+ {keys} = obj;
30
+ let i = keys.length;
31
+
32
+ while (i--) {
33
+ cleaned.push(keys[i], !!obj.get(keys[i]));
34
+ }
35
+ } else {
36
+ const
37
+ keys = Object.keys(obj);
38
+ let i = keys.length;
39
+
40
+ while (i--) {
41
+ cleaned.push(keys[i], !!obj[keys[i]]);
42
+ }
43
+ }
44
+ }
45
+
46
+ return cleaned;
47
+ },
48
+ StateMap = function (first) {
49
+ const
50
+ l = arguments.length;
51
+
52
+ if (l) {
53
+ if ((l === 1) && (typeof first === 'string')) {
54
+ DataMap.call(this);
55
+ this.updateFromString(first);
56
+ } else {
57
+ const
58
+ cleanedArgs = clean(arguments);
59
+
60
+ DataMap.apply(this, cleanedArgs);
61
+ arrayCache.recycle(cleanedArgs);
62
+ }
63
+ } else {
64
+ DataMap.call(this);
65
+ }
66
+ },
67
+ parent = DataMap.prototype,
68
+ proto = StateMap.prototype = Object.create(parent);
69
+
70
+ Object.defineProperty(proto, 'constructor', {
71
+ configurable: true,
72
+ writable: true,
73
+ value: StateMap
74
+ });
75
+
76
+ /**
77
+ * Returns a JSON object of state keys and boolean values.
78
+ *
79
+ * @method platypus.StateMap#toJSON
80
+ * @return {Object} State keys mapped to `true` or `false`.
81
+ */
82
+
83
+ /**
84
+ * Returns a comma-delimited list of state keys compatible with `updateFromString`. False values are prefixed with `"!"`.
85
+ *
86
+ * @method platypus.StateMap#toString
87
+ * @return {String} The serialized state string.
88
+ */
89
+ Object.defineProperty(proto, 'toString', {
90
+ value: function () {
91
+ const
92
+ {keys} = this;
93
+ let i = keys.length,
94
+ parts = arrayCache.setUp();
95
+
96
+ while (i--) {
97
+ const
98
+ key = keys[i];
99
+
100
+ parts.push(this.get(key) ? key : `!${key}`);
101
+ }
102
+
103
+ const
104
+ string = parts.join(',');
105
+
106
+ arrayCache.recycle(parts);
107
+
108
+ return string;
109
+ }
110
+ });
111
+
112
+ /**
113
+ * Sets the state using the provided string value which is a comma-delimited list such that `"blue,red,!green"` sets the following state values:
114
+ *
115
+ * {
116
+ * red: true,
117
+ * blue: true,
118
+ * green: false
119
+ * }
120
+ *
121
+ * @method platypus.StateMap#updateFromString
122
+ * @param states {String} A comma-delimited list of true/false state values.
123
+ * @chainable
124
+ */
125
+ Object.defineProperty(proto, 'updateFromString', {
126
+ value: function (states) {
127
+ const
128
+ arr = greenSplit(states, ',');
129
+ let i = arr.length;
130
+
131
+ while (i--) {
132
+ const
133
+ str = arr[i];
134
+
135
+ if (str) {
136
+ if (str.substr(0, 1) === '!') {
137
+ this.set(str.substr(1), false);
138
+ } else {
139
+ this.set(str, true);
140
+ }
141
+ }
142
+ }
143
+
144
+ arrayCache.recycle(arr);
145
+
146
+ return this;
147
+ }
148
+ });
149
+
150
+ /**
151
+ * Checks whether the provided state matches this state and updates this state to match.
152
+ *
153
+ * @method platypus.StateMap#update
154
+ * @param state {platypus.StateMap} The state that this state should match.
155
+ * @return {Boolean} Whether this state already matches the provided state.
156
+ */
157
+ Object.defineProperty(proto, 'update', {
158
+ value: function (newState) {
159
+ const
160
+ {keys} = newState;
161
+ let i = keys.length,
162
+ changed = false;
163
+
164
+ while (i--) {
165
+ const
166
+ state = keys[i],
167
+ value = newState.get(state);
168
+
169
+ if (this.get(state) !== value) {
170
+ this.set(state, value);
171
+ changed = true;
172
+ }
173
+ }
174
+
175
+ return changed;
176
+ }
177
+ });
178
+
179
+ /**
180
+ * Checks whether the provided state matches all equivalent keys on this state.
181
+ *
182
+ * @method platypus.StateMap#includes
183
+ * @param state {platypus.StateMap} The state that this state should match.
184
+ * @return {Boolean} Whether this state matches the provided state.
185
+ */
186
+ Object.defineProperty(proto, 'includes', {
187
+ value: function (otherState) {
188
+ const
189
+ {keys} = otherState;
190
+ let i = keys.length;
191
+
192
+ while (i--) {
193
+ const
194
+ state = keys[i];
195
+
196
+ if (this.get(state) !== otherState.get(state)) {
197
+ return false;
198
+ }
199
+ }
200
+
201
+ return true;
202
+ }
203
+ });
204
+
205
+ /**
206
+ * Checks whether the provided state matches any equivalent keys on this state.
207
+ *
208
+ * @method platypus.StateMap#intersects
209
+ * @param state {platypus.StateMap} The state that this state should intersect.
210
+ * @return {Boolean} Whether this state intersects the provided state.
211
+ */
212
+ Object.defineProperty(proto, 'intersects', {
213
+ value: function (otherState) {
214
+ const
215
+ {keys} = otherState;
216
+ let i = keys.length;
217
+
218
+ while (i--) {
219
+ const
220
+ state = keys[i];
221
+
222
+ if (this.get(state) === otherState.get(state)) {
223
+ return true;
224
+ }
225
+ }
226
+
227
+ return false;
228
+ }
229
+ });
230
+
231
+ /**
232
+ * Returns StateMap from cache or creates a new one if none are available.
233
+ *
234
+ * @method platypus.StateMap.setUp
235
+ * @return {platypus.StateMap} The instantiated StateMap.
236
+ */
237
+ /**
238
+ * Returns StateMap back to the cache. Prefer the StateMap's recycle method since it recycles property objects as well.
239
+ *
240
+ * @method platypus.StateMap.recycle
241
+ * @param {platypus.StateMap} stateMap The StateMap to be recycled.
242
+ */
243
+ /**
244
+ * Relinquishes StateMap properties and recycles it.
245
+ *
246
+ * @method platypus.StateMap#recycle
247
+ */
248
+ recycle.add(StateMap, 'StateMap', StateMap, function () {
249
+ this.clear();
250
+ }, true);
251
+
252
+ export default StateMap;
package/src/Storage.js ADDED
@@ -0,0 +1,152 @@
1
+ /* global platypus, window */
2
+ import DataMap from './DataMap.js';
3
+ import {UserData} from 'springroll';
4
+
5
+ /**
6
+ * This class is used to create the Platypus storage system accessible at `platypus.storage`. It uses Springroll UserData if available, with a fallback to local storage if not.
7
+ *
8
+ * @memberof platypus
9
+ * @class Storage
10
+ * @param {*} springroll
11
+ * @param {*} options
12
+ * @return {Data} Returns the new Storage object.
13
+ */
14
+ class Storage {
15
+ constructor (springroll, {name: gameId, storageKeys: keys = null}) {
16
+ const
17
+ storageKey = `${gameId}-data`,
18
+ unconnectedData = window.localStorage.getItem(storageKey),
19
+ handleData = (resp) => {
20
+ const
21
+ data = resp?.data ?? resp;
22
+
23
+ if (data) {
24
+ const
25
+ keys = Object.keys(data),
26
+ {length} = keys;
27
+
28
+ for (let i = 0; i < length; i++) {
29
+ const
30
+ key = keys[i];
31
+
32
+ if (this.map.has(key)) {
33
+ this.map.set(key, data[key]);
34
+ } else {
35
+ this.addKey(key, data[key]);
36
+ }
37
+ }
38
+ }
39
+ };
40
+
41
+ this.map = DataMap.setUp();
42
+
43
+ /**
44
+ * The storage key being used to store data.
45
+ *
46
+ * @property storageKey
47
+ * @type String
48
+ * @default options.name+'-data'
49
+ */
50
+ this.storageKey = storageKey;
51
+
52
+ /**
53
+ * Whether Springroll is connected to a hosting page.
54
+ *
55
+ * @property connected
56
+ * @type Boolean
57
+ * @default false
58
+ */
59
+ this.connected = false;
60
+
61
+ if (keys) {
62
+ for (let i = 0; i < keys.length; i++) {
63
+ this.addKey(keys[i], null);
64
+ }
65
+ }
66
+
67
+ try { // May throw if data is not parseable. If so, we'll just ignore it.
68
+ handleData(JSON.parse(unconnectedData));
69
+ } catch (e) {}
70
+
71
+ // Using Bellhop's "connected" event because springroll.state.ready doesn't ensure that Bellhop is also ready.
72
+ springroll.container.on('connected', async () => {
73
+ this.connected = true;
74
+ try {
75
+ handleData(await UserData.read(this.storageKey));
76
+ } catch (e) {
77
+ platypus.debug.warn('Storage: connected but received an error', e);
78
+ }
79
+ });
80
+ }
81
+
82
+ /**
83
+ * Adds a storage key to the game's storage.
84
+ *
85
+ * @param {String} key The key to add.
86
+ * @param {*} value The data to store at this defined key.
87
+ */
88
+ addKey (key, value) {
89
+ this.map.set(key, value);
90
+ Object.defineProperty(this, key, {
91
+ get: function () {
92
+ return this.map.get(key);
93
+ },
94
+ set: function (value) {
95
+ this.map.set(key, value);
96
+
97
+ this.save();
98
+ },
99
+ configurable: true,
100
+ enumerable: true
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Gets a value from storage for the provided storage key.
106
+ *
107
+ * @param {String} key The key for the data to return
108
+ * @return {*}
109
+ */
110
+ get (key) {
111
+ if (!this.map.has(key)) {
112
+ this.addKey(key, null);
113
+ }
114
+
115
+ return this[key];
116
+ }
117
+
118
+ /**
119
+ * Takes the current game storage and saves it to local storage or Springroll UserData
120
+ *
121
+ */
122
+ async save () {
123
+ const save = this.map.toJSON();
124
+
125
+ if (this.connected) {
126
+ try {
127
+ await UserData.write(this.storageKey, save);
128
+ } catch (e) {
129
+ platypus.debug.warn('Storage: tried to save but received an error', e);
130
+ }
131
+ } else {
132
+ window.localStorage.setItem(this.storageKey, JSON.stringify(save));
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Updates a storage key's data. Creates the key if it does not exist.
138
+ *
139
+ * @param {String} key The key to update.
140
+ * @param {*} value The data to store at this key.
141
+ */
142
+ set (key, value) {
143
+ if (!this.map.has(key)) {
144
+ this.addKey(key, value);
145
+ this.save();
146
+ } else {
147
+ this[key] = value;
148
+ }
149
+ }
150
+ };
151
+
152
+ export default Storage;
@@ -0,0 +1,48 @@
1
+ export default class {
2
+ constructor (targetFPS = 60) {
3
+ const
4
+ listeners = this.listeners = [],
5
+ worker = this.worker = new Worker(new URL('./TickerServer.js', import.meta.url));
6
+
7
+ this.deltaMS = 1000 / targetFPS;
8
+ this.elapsedMS = this.deltaMS;
9
+
10
+ worker.onmessage = ({data}) => {
11
+ this.elapsedMS = data.deltaTime;
12
+ listeners.forEach((listener) => listener(data));
13
+ };
14
+
15
+ this.start();
16
+ }
17
+
18
+ add (listener) {
19
+ this.listeners.push(listener);
20
+ }
21
+
22
+ remove (listener) {
23
+ const
24
+ i = this.listeners.indexOf(listener);
25
+
26
+ if (i >= 0) {
27
+ this.listeners.splice(i, 1);
28
+ }
29
+ }
30
+
31
+ start () {
32
+ this.worker.postMessage({
33
+ begin: {
34
+ delta: this.deltaMS
35
+ }
36
+ });
37
+ }
38
+
39
+ stop () {
40
+ this.worker.postMessage({
41
+ stop: true
42
+ });
43
+ }
44
+
45
+ get FPS () {
46
+ return 1000 / this.elapsedMS;
47
+ }
48
+ }