squishjs 1.4.1 → 1.4.2
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/package.json +1 -1
- package/src/Squisher.js +21 -13
- package/test/Squisher.test.js +30 -0
package/package.json
CHANGED
package/src/Squisher.js
CHANGED
|
@@ -67,30 +67,34 @@ class Squisher {
|
|
|
67
67
|
let toSquish = [];
|
|
68
68
|
|
|
69
69
|
const playerMap = {};
|
|
70
|
+
// Shared (visible-to-everyone) nodes in traversal order, kept so a
|
|
71
|
+
// player frame created mid-traversal can be seeded with everything
|
|
72
|
+
// shared that was squished before that player's first scoped node.
|
|
73
|
+
const sharedNodes = [];
|
|
70
74
|
|
|
71
75
|
if (this.customBottomLayer) {
|
|
72
76
|
const squishedLayer = [];
|
|
73
|
-
this.squishHelper(this.customBottomLayer.root, squishedLayer, this.customBottomLayer.scale, playerMap);
|
|
77
|
+
this.squishHelper(this.customBottomLayer.root, squishedLayer, this.customBottomLayer.scale, playerMap, new Set(), sharedNodes);
|
|
74
78
|
toSquish.push(squishedLayer);
|
|
75
79
|
}
|
|
76
|
-
|
|
80
|
+
|
|
77
81
|
for (const layerIndex in layers) {
|
|
78
82
|
const squishedLayer = [];
|
|
79
83
|
const layerInfo = layers[layerIndex];
|
|
80
|
-
|
|
84
|
+
|
|
81
85
|
const layerScale = layerInfo.scale ? {
|
|
82
86
|
x: this.scale.x * layerInfo.scale.x,
|
|
83
87
|
y: this.scale.y * layerInfo.scale.y
|
|
84
88
|
} : this.scale;
|
|
85
89
|
|
|
86
|
-
this.squishHelper(layerInfo.root, squishedLayer, scale || layerScale, playerMap);
|
|
90
|
+
this.squishHelper(layerInfo.root, squishedLayer, scale || layerScale, playerMap, new Set(), sharedNodes);
|
|
87
91
|
toSquish.push(squishedLayer);
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
|
|
91
|
-
if (this.customTopLayer) {
|
|
95
|
+
if (this.customTopLayer) {
|
|
92
96
|
const squishedLayer = [];
|
|
93
|
-
this.squishHelper(this.customTopLayer.root, squishedLayer, this.customTopLayer.scale, playerMap);
|
|
97
|
+
this.squishHelper(this.customTopLayer.root, squishedLayer, this.customTopLayer.scale, playerMap, new Set(), sharedNodes);
|
|
94
98
|
toSquish.push(squishedLayer);
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -123,7 +127,7 @@ class Squisher {
|
|
|
123
127
|
return !!(sound && sound.enabled === false);
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
squishHelper(node, squishedNodes, scale = {x: 1, y: 1}, playerMap = {}, playerIdFilter = new Set()) {
|
|
130
|
+
squishHelper(node, squishedNodes, scale = {x: 1, y: 1}, playerMap = {}, playerIdFilter = new Set(), sharedNodes = []) {
|
|
127
131
|
if (!node.node.listeners.has(this)) {
|
|
128
132
|
node.addListener(this);
|
|
129
133
|
}
|
|
@@ -139,7 +143,13 @@ class Squisher {
|
|
|
139
143
|
let playerIdsToRemove = new Set();
|
|
140
144
|
for (let playerId of playerIdFilter) {
|
|
141
145
|
if (!playerMap[playerId]) {
|
|
142
|
-
|
|
146
|
+
// First scoped node seen for this player. Seed their frame
|
|
147
|
+
// with every shared node squished so far — otherwise the
|
|
148
|
+
// frame would be missing everything shared (root
|
|
149
|
+
// background included) that preceded it in traversal.
|
|
150
|
+
playerMap[Number(playerId)] = sharedNodes
|
|
151
|
+
.filter(shared => !this._isAudioMutedFor(shared.node, playerId))
|
|
152
|
+
.map(shared => shared.squished);
|
|
143
153
|
}
|
|
144
154
|
|
|
145
155
|
if (node.node.playerIds.length === 0 || node.node.playerIds.findIndex(i => Number(i) === Number(playerId)) >= 0) {
|
|
@@ -154,10 +164,8 @@ class Squisher {
|
|
|
154
164
|
playerIdFilter.delete(id);
|
|
155
165
|
}
|
|
156
166
|
} else {
|
|
167
|
+
sharedNodes.push({ node, squished });
|
|
157
168
|
Object.keys(playerMap).forEach(playerId => {
|
|
158
|
-
if (!playerMap[playerId]) {
|
|
159
|
-
playerMap[Number(playerId)] = [];
|
|
160
|
-
}
|
|
161
169
|
if (!this._isAudioMutedFor(node, playerId)) {
|
|
162
170
|
playerMap[playerId].push(squished);
|
|
163
171
|
}
|
|
@@ -166,10 +174,10 @@ class Squisher {
|
|
|
166
174
|
|
|
167
175
|
for (let i = 0; i < node.node.children.length; i++) {
|
|
168
176
|
// if (node.node.children[i].node.playerIds
|
|
169
|
-
// make a new set so child calls within a single generation arent
|
|
177
|
+
// make a new set so child calls within a single generation arent
|
|
170
178
|
// modifying the same filter set
|
|
171
179
|
const pathFilter = new Set(playerIdFilter);
|
|
172
|
-
this.squishHelper(node.node.children[i], squishedNodes, scale, playerMap, pathFilter);
|
|
180
|
+
this.squishHelper(node.node.children[i], squishedNodes, scale, playerMap, pathFilter, sharedNodes);
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
}
|
package/test/Squisher.test.js
CHANGED
|
@@ -82,6 +82,36 @@ test("squisher does not crash on an asset node with an unregistered key", () =>
|
|
|
82
82
|
assert(frame && frame.length >= 1);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
test("player frame includes shared nodes squished before the player's first scoped node", () => {
|
|
86
|
+
// The root background and an early shared sibling precede the scoped
|
|
87
|
+
// node in traversal order. The player's frame must still contain them
|
|
88
|
+
// (seeded on frame creation), in draw order.
|
|
89
|
+
const root = rectNode({ x: 0, y: 0, width: 100, height: 100, fill: COLORS.WHITE });
|
|
90
|
+
const earlyShared = rectNode({ x: 1, y: 1, width: 5, height: 5, fill: COLORS.GREEN });
|
|
91
|
+
const scoped = new GameNode.Shape({
|
|
92
|
+
shapeType: Shapes.POLYGON,
|
|
93
|
+
coordinates2d: ShapeUtils.rectangle(2, 2, 5, 5),
|
|
94
|
+
fill: COLORS.BLUE,
|
|
95
|
+
playerIds: [7]
|
|
96
|
+
});
|
|
97
|
+
const lateShared = rectNode({ x: 3, y: 3, width: 5, height: 5, fill: COLORS.RED });
|
|
98
|
+
|
|
99
|
+
root.addChild(earlyShared);
|
|
100
|
+
root.addChild(scoped);
|
|
101
|
+
root.addChild(lateShared);
|
|
102
|
+
|
|
103
|
+
const game = new FakeGame([{ root, scale: { x: 1, y: 1 } }]);
|
|
104
|
+
const squisher = new Squisher({ game });
|
|
105
|
+
|
|
106
|
+
const frame = squisher.getPlayerFrame(7);
|
|
107
|
+
assert(frame.length === 4);
|
|
108
|
+
const fills = frame.map(squished => unsquish(squished).node.fill);
|
|
109
|
+
verifyArrayEquality(fills[0], COLORS.WHITE);
|
|
110
|
+
verifyArrayEquality(fills[1], COLORS.GREEN);
|
|
111
|
+
verifyArrayEquality(fills[2], COLORS.BLUE);
|
|
112
|
+
verifyArrayEquality(fills[3], COLORS.RED);
|
|
113
|
+
});
|
|
114
|
+
|
|
85
115
|
test("squisher withholds muted audio from a player-scoped subtree", () => {
|
|
86
116
|
const root = new GameNode.Shape({
|
|
87
117
|
shapeType: Shapes.POLYGON,
|