@lzpenguin/server 1.0.2 → 1.0.3

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