@lzpenguin/server 1.0.2 → 1.0.4
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/index.js +117 -3
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -177,9 +177,39 @@ export class RiffleServer {
|
|
|
177
177
|
console.log('[RiffleServer] Initialized');
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
// 合并服务器数据与当前缓存,避免丢失乐观更新的数据
|
|
181
|
+
// 策略:对于 world 数据,优先保留乐观更新(当前缓存),然后合并服务器数据
|
|
182
|
+
// 这样可以确保刚画的笔画不会因为服务器推送旧数据而丢失
|
|
183
|
+
if (this.currentData) {
|
|
184
|
+
const mergedData = {
|
|
185
|
+
// world 数据:先使用当前缓存(包含乐观更新),再合并服务器数据
|
|
186
|
+
// _deepMerge 会先保留 target(当前缓存)的所有数据,然后添加 source(服务器数据)中不存在的项
|
|
187
|
+
// 对于数组(如 strokes),会合并去重,确保不会丢失任何笔画
|
|
188
|
+
world: this._deepMerge(this.currentData.world || {}, message.world || {}),
|
|
189
|
+
// self 数据:服务器数据优先(因为服务器会合并所有玩家的更新)
|
|
190
|
+
// 但也要合并当前缓存,确保不丢失字段
|
|
191
|
+
self: {
|
|
192
|
+
public: this._deepMerge(
|
|
193
|
+
message.self?.public || {},
|
|
194
|
+
this.currentData.self?.public || {}
|
|
195
|
+
),
|
|
196
|
+
private: this._deepMerge(
|
|
197
|
+
message.self?.private || {},
|
|
198
|
+
this.currentData.self?.private || {}
|
|
199
|
+
)
|
|
200
|
+
},
|
|
201
|
+
// players 列表使用服务器数据(其他玩家的数据)
|
|
202
|
+
players: message.players
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// 使用合并后的数据
|
|
206
|
+
this.currentData = mergedData;
|
|
207
|
+
this.dataCallbacks.forEach(cb => cb(mergedData));
|
|
208
|
+
} else {
|
|
209
|
+
// 如果没有缓存数据,直接使用服务器数据
|
|
210
|
+
this.currentData = message;
|
|
211
|
+
this.dataCallbacks.forEach(cb => cb(message));
|
|
212
|
+
}
|
|
183
213
|
}
|
|
184
214
|
} catch (error) {
|
|
185
215
|
console.error('[RiffleServer] Failed to parse message:', error);
|
|
@@ -240,6 +270,58 @@ export class RiffleServer {
|
|
|
240
270
|
this.isConnected = false;
|
|
241
271
|
}
|
|
242
272
|
|
|
273
|
+
/**
|
|
274
|
+
* 深度合并对象
|
|
275
|
+
* @private
|
|
276
|
+
* @param {Object} target - 目标对象(基础数据)
|
|
277
|
+
* @param {Object} source - 源对象(新数据,优先使用)
|
|
278
|
+
* @returns {Object} 合并后的对象
|
|
279
|
+
*/
|
|
280
|
+
_deepMerge(target, source) {
|
|
281
|
+
if (!target) return source ? (Array.isArray(source) ? [...source] : { ...source }) : {};
|
|
282
|
+
if (!source) return target;
|
|
283
|
+
|
|
284
|
+
// 处理数组:如果都是数组,合并去重(基于 JSON 字符串比较)
|
|
285
|
+
// 先保留 target 的所有项,然后添加 source 中不存在的项
|
|
286
|
+
// 这样可以确保不会丢失任何数据
|
|
287
|
+
if (Array.isArray(target) && Array.isArray(source)) {
|
|
288
|
+
const merged = [...target];
|
|
289
|
+
const targetStrings = new Set(target.map(item => JSON.stringify(item)));
|
|
290
|
+
for (const item of source) {
|
|
291
|
+
const itemStr = JSON.stringify(item);
|
|
292
|
+
if (!targetStrings.has(itemStr)) {
|
|
293
|
+
merged.push(item);
|
|
294
|
+
targetStrings.add(itemStr);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return merged;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// 如果类型不匹配,使用源数据
|
|
301
|
+
if (Array.isArray(target) || Array.isArray(source)) {
|
|
302
|
+
return Array.isArray(source) ? [...source] : source;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 处理对象:递归合并
|
|
306
|
+
// 先复制 target,然后用 source 的值覆盖(但递归合并子对象)
|
|
307
|
+
const result = { ...target };
|
|
308
|
+
for (const key in source) {
|
|
309
|
+
if (source.hasOwnProperty(key)) {
|
|
310
|
+
const sourceValue = source[key];
|
|
311
|
+
const targetValue = target[key];
|
|
312
|
+
|
|
313
|
+
// 如果源值是对象且不是数组,递归合并
|
|
314
|
+
if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
|
|
315
|
+
result[key] = this._deepMerge(targetValue, sourceValue);
|
|
316
|
+
} else {
|
|
317
|
+
// 否则使用源值(优先使用新数据)
|
|
318
|
+
result[key] = sourceValue;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
|
|
243
325
|
/**
|
|
244
326
|
* 发送更新请求
|
|
245
327
|
* @private
|
|
@@ -256,6 +338,38 @@ export class RiffleServer {
|
|
|
256
338
|
return;
|
|
257
339
|
}
|
|
258
340
|
|
|
341
|
+
// 乐观更新:立即更新本地缓存并触发回调
|
|
342
|
+
if (this.currentData) {
|
|
343
|
+
const optimisticData = { ...this.currentData };
|
|
344
|
+
|
|
345
|
+
// 合并 world 数据
|
|
346
|
+
if (updateData.world) {
|
|
347
|
+
optimisticData.world = this._deepMerge(this.currentData.world || {}, updateData.world);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// 合并 self 数据
|
|
351
|
+
if (updateData.self) {
|
|
352
|
+
optimisticData.self = { ...this.currentData.self };
|
|
353
|
+
if (updateData.self.public) {
|
|
354
|
+
optimisticData.self.public = this._deepMerge(
|
|
355
|
+
this.currentData.self?.public || {},
|
|
356
|
+
updateData.self.public
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
if (updateData.self.private) {
|
|
360
|
+
optimisticData.self.private = this._deepMerge(
|
|
361
|
+
this.currentData.self?.private || {},
|
|
362
|
+
updateData.self.private
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// 更新缓存并立即触发回调(乐观更新)
|
|
368
|
+
this.currentData = optimisticData;
|
|
369
|
+
this.dataCallbacks.forEach(cb => cb(optimisticData));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 发送更新请求到服务器
|
|
259
373
|
try {
|
|
260
374
|
this.ws.send(JSON.stringify(updateData));
|
|
261
375
|
} catch (error) {
|