Skip to content

Commit f1d46b9

Browse files
committed
StateView.remove(): do not remove item if parent field is not @view() https://github.com/orgs/colyseus/discussions/852
1 parent 0d01806 commit f1d46b9

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@colyseus/schema",
3-
"version": "3.0.34",
3+
"version": "3.0.35",
44
"description": "Binary state serializer with delta encoding for games",
55
"bin": {
66
"schema-codegen": "bin/schema-codegen",

src/encoder/StateView.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export class StateView {
227227
if (tag === DEFAULT_VIEW_TAG) {
228228
// parent is collection (Map/Array)
229229
const parent = changeTree.parent;
230-
if (!Metadata.isValidInstance(parent)) {
230+
if (!Metadata.isValidInstance(parent) && changeTree.isFiltered) {
231231
const parentChangeTree = parent[$changes];
232232
let changes = this.changes.get(parentChangeTree.refId);
233233
if (changes === undefined) {
@@ -239,11 +239,10 @@ export class StateView {
239239

240240
} else {
241241
// delete all "tagged" properties.
242-
metadata?.[$viewFieldIndexes].forEach((index) =>
242+
metadata?.[$viewFieldIndexes]?.forEach((index) =>
243243
changes[index] = OPERATION.DELETE);
244244
}
245245

246-
247246
} else {
248247
// delete only tagged properties
249248
metadata?.[$fieldIndexesByViewTag][tag].forEach((index) =>

test/StateView.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,54 @@ describe("StateView", () => {
10421042
assert.strictEqual(3, client2.state.entities.get("two").components.length);
10431043

10441044
});
1045+
1046+
it("view.remove() should only remove tagged field and not the whole structure", () => {
1047+
class Card extends Schema {
1048+
@view() @type("string") cardId: string;
1049+
@type("string") zone: string;
1050+
@type("number") index: number;
1051+
}
1052+
class State extends Schema {
1053+
@type({ map: Card }) cards = new MapSchema();
1054+
}
1055+
const state = new State();
1056+
const encoder = getEncoder(state);
1057+
1058+
const client1 = createClientWithView(state);
1059+
1060+
const card1 = new Card().assign({ cardId: "card1", zone: "zone1", index: 0 });
1061+
const card2 = new Card().assign({ cardId: "card2", zone: "zone2", index: 0 })
1062+
const card3 = new Card().assign({ cardId: "card3", zone: "zone3", index: 0 });
1063+
state.cards.set("1", card1);
1064+
state.cards.set("2", card2);
1065+
state.cards.set("3", card3);
1066+
1067+
client1.view.add(card1);
1068+
encodeMultiple(encoder, state, [client1]);
1069+
1070+
assert.strictEqual(3, client1.state.cards.size);
1071+
assert.strictEqual("card1", client1.state.cards.get("1").cardId);
1072+
assert.strictEqual(undefined, client1.state.cards.get("2").cardId);
1073+
assert.strictEqual(undefined, client1.state.cards.get("3").cardId);
1074+
1075+
// remove from view
1076+
client1.view.remove(card1);
1077+
encodeMultiple(encoder, state, [client1]);
1078+
1079+
// mutate removed item
1080+
card1.zone = "zone2";
1081+
card1.index = 1;
1082+
encodeMultiple(encoder, state, [client1]);
1083+
1084+
assert.strictEqual(undefined, client1.state.cards.get("1").cardId);
1085+
assert.strictEqual("zone2", client1.state.cards.get("1").zone);
1086+
assert.strictEqual(1, client1.state.cards.get("1").index);
1087+
1088+
assert.strictEqual(undefined, client1.state.cards.get("2").cardId);
1089+
assert.strictEqual(undefined, client1.state.cards.get("3").cardId);
1090+
1091+
assertEncodeAllMultiple(encoder, state, [client1]);
1092+
});
10451093
});
10461094

10471095
describe("ArraySchema", () => {

0 commit comments

Comments
 (0)