@lzpenguin/server 1.0.10 → 1.1.1
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/README.md +56 -92
- package/index.d.ts +8 -73
- package/index.js +60 -125
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,10 +13,11 @@ npm install @lzpenguin/server
|
|
|
13
13
|
```javascript
|
|
14
14
|
import { RiffleServer } from '@lzpenguin/server';
|
|
15
15
|
|
|
16
|
+
// post_id 和 token 会自动从浏览器 URL 参数中读取
|
|
17
|
+
// 例如:https://example.com/game.html?post_id=123456&token=your-token-here
|
|
16
18
|
const server = new RiffleServer({
|
|
17
19
|
url: 'wss://api.riffle.app',
|
|
18
|
-
|
|
19
|
-
token: 'your-token-here'
|
|
20
|
+
timestamp: 'timestamp given in the context' // 游戏时间戳,用于判断是否需要重新初始化
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
// 监听数据更新
|
|
@@ -28,7 +29,6 @@ server.onData((data) => {
|
|
|
28
29
|
|
|
29
30
|
// 初始化服务器
|
|
30
31
|
server.init({
|
|
31
|
-
hash: 'game-version-hash-123',
|
|
32
32
|
world: { score: 0, level: 1 },
|
|
33
33
|
self: {
|
|
34
34
|
public: { name: 'Player1', x: 100, y: 100 }
|
|
@@ -42,97 +42,23 @@ server.init({
|
|
|
42
42
|
|
|
43
43
|
```javascript
|
|
44
44
|
new RiffleServer({
|
|
45
|
-
url: 'wss://api.riffle.app',
|
|
46
|
-
|
|
47
|
-
token: 'your-token-here', // 必需:认证 token
|
|
45
|
+
url: 'wss://api.riffle.app', // 必需:WebSocket 服务器 URL
|
|
46
|
+
timestamp: 'timestamp given in the context', // 必需:游戏时间戳(用于判断是否需要重新初始化,新 timestamp 必须大于旧的才会重置)
|
|
48
47
|
autoReconnect: true, // 可选:是否自动重连,默认 true
|
|
49
48
|
reconnectInterval: 3000 // 可选:重连间隔(毫秒),默认 3000
|
|
50
49
|
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
## API 方法
|
|
54
|
-
|
|
55
|
-
### 细粒度操作 API(推荐)
|
|
56
|
-
|
|
57
|
-
#### World 数据操作
|
|
58
|
-
|
|
59
|
-
```javascript
|
|
60
|
-
// 添加/设置单个键值对
|
|
61
|
-
server.world.add('score', 100);
|
|
62
|
-
server.world.update('level', 2);
|
|
63
|
-
|
|
64
|
-
// 删除键(设置为 null)
|
|
65
|
-
server.world.delete('oldKey');
|
|
66
|
-
|
|
67
|
-
// 批量设置
|
|
68
|
-
server.world.set({
|
|
69
|
-
score: 100,
|
|
70
|
-
level: 2,
|
|
71
|
-
players: 10
|
|
72
|
-
});
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
#### Self 数据操作
|
|
76
|
-
|
|
77
|
-
```javascript
|
|
78
|
-
// 添加/设置单个键值对
|
|
79
|
-
server.self.add('x', 150);
|
|
80
|
-
server.self.update('y', 250);
|
|
81
|
-
|
|
82
|
-
// 删除键(设置为 null)
|
|
83
|
-
server.self.delete('oldProp');
|
|
84
|
-
|
|
85
|
-
// 批量设置
|
|
86
|
-
server.self.set({
|
|
87
|
-
x: 150,
|
|
88
|
-
y: 250,
|
|
89
|
-
rotation: 90
|
|
90
|
-
});
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
#### 完整示例
|
|
94
|
-
|
|
95
|
-
```javascript
|
|
96
|
-
import { RiffleServer } from '@lzpenguin/server';
|
|
97
|
-
|
|
98
|
-
const server = new RiffleServer({
|
|
99
|
-
url: 'wss://api.riffle.app',
|
|
100
|
-
postId: 123456,
|
|
101
|
-
token: 'your-token-here'
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// 监听数据更新
|
|
105
|
-
server.onData((data) => {
|
|
106
|
-
console.log('World:', data.world);
|
|
107
|
-
console.log('Self:', data.self);
|
|
108
|
-
console.log('Players:', data.players);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// 初始化
|
|
112
|
-
server.init({
|
|
113
|
-
hash: 'v1.0.0',
|
|
114
|
-
world: { score: 0, level: 1 },
|
|
115
|
-
self: { public: { name: 'Player1', x: 0, y: 0 } }
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// 使用细粒度 API 更新数据
|
|
119
|
-
server.world.update('score', 100); // 更新分数
|
|
120
|
-
server.self.update('x', 150); // 更新 X 坐标
|
|
121
|
-
server.self.update('y', 250); // 更新 Y 坐标
|
|
122
|
-
|
|
123
|
-
// 批量更新
|
|
124
|
-
server.self.set({ x: 200, y: 300, rotation: 45 });
|
|
50
|
+
// 注意:post_id 和 token 会自动从浏览器 URL 参数中读取
|
|
51
|
+
// 页面 URL 格式:https://example.com/game.html?post_id=123456&token=your-token-here
|
|
125
52
|
```
|
|
126
53
|
|
|
127
54
|
## 三种消息类型
|
|
128
55
|
|
|
129
56
|
### 1. init() - 初始化服务器
|
|
130
57
|
|
|
131
|
-
初始化服务器(必需,连接后必须先调用)。
|
|
58
|
+
初始化服务器(必需,连接后必须先调用)。timestamp(在构造函数中传入)比现有的大则删除旧服务器并重新创建,否则返回现有数据。
|
|
132
59
|
|
|
133
60
|
```javascript
|
|
134
61
|
server.init({
|
|
135
|
-
hash: 'game-version-hash-123', // 必需:游戏版本哈希值
|
|
136
62
|
world: { score: 0, level: 1 }, // 可选:世界初始数据
|
|
137
63
|
self: {
|
|
138
64
|
public: { name: 'Player1', x: 100, y: 100 } // 可选:公开数据
|
|
@@ -153,14 +79,47 @@ server.init({
|
|
|
153
79
|
|
|
154
80
|
**注意:** `self` 和 `players[i]` 现在具有相同的结构,都只包含公开数据。
|
|
155
81
|
|
|
156
|
-
**关于
|
|
157
|
-
- **
|
|
158
|
-
- **
|
|
159
|
-
- **何时更新
|
|
82
|
+
**关于 timestamp:**
|
|
83
|
+
- **timestamp 较小或相等**:传入的值不生效,直接返回现有数据
|
|
84
|
+
- **timestamp 较大**:删除旧服务器并重新创建,使用传入的值初始化数据
|
|
85
|
+
- **何时更新 timestamp**:如果更改了游戏,且改动了角色或世界字段的设计(如新增/删除字段、改变字段类型),就需要使用更大的 timestamp(上下文中会给出当前编辑时的timestamp)让服务器重新初始化,避免数据结构不兼容
|
|
160
86
|
|
|
161
87
|
**注意:** init 成功后服务器每 0.2 秒自动推送最新数据
|
|
162
88
|
|
|
163
|
-
### 2.
|
|
89
|
+
### 2. update() - 更新数据
|
|
90
|
+
|
|
91
|
+
部分更新数据(合并到现有数据,不替换)。
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
// 更新世界数据
|
|
95
|
+
server.update({ world: { score: 200 } });
|
|
96
|
+
|
|
97
|
+
// 更新玩家数据
|
|
98
|
+
server.update({
|
|
99
|
+
self: {
|
|
100
|
+
public: { x: 15, y: 25, rotation: 90 }
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// 同时更新世界和玩家数据
|
|
105
|
+
server.update({
|
|
106
|
+
world: { score: 200 },
|
|
107
|
+
self: { public: { x: 15, y: 25 } }
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**响应数据(通过 onData 接收):**
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"world": { "score": 200, "level": 1 },
|
|
115
|
+
"self": { "name": "Player1", "x": 15, "y": 25, "rotation": 90 },
|
|
116
|
+
"players": [{ "name": "Player2", "x": 10, "y": 20 }]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**注意:** 只更新提供的字段,未提供的字段保持不变,更新后立即推送最新数据
|
|
121
|
+
|
|
122
|
+
### 3. onData() - 监听数据推送
|
|
164
123
|
|
|
165
124
|
监听服务器推送的最新数据。init 成功后每 0.2 秒自动推送,调用 init/update 后立即推送。
|
|
166
125
|
|
|
@@ -198,10 +157,10 @@ unsubscribe();
|
|
|
198
157
|
```javascript
|
|
199
158
|
import { RiffleServer } from '@lzpenguin/server';
|
|
200
159
|
|
|
160
|
+
// post_id 和 token 会自动从浏览器 URL 参数中读取
|
|
201
161
|
const server = new RiffleServer({
|
|
202
162
|
url: 'wss://api.riffle.app',
|
|
203
|
-
|
|
204
|
-
token: 'your-token-here'
|
|
163
|
+
timestamp: 'timestamp given in the context'
|
|
205
164
|
});
|
|
206
165
|
|
|
207
166
|
// 监听服务器推送,更新游戏状态
|
|
@@ -223,7 +182,6 @@ server.onData((data) => {
|
|
|
223
182
|
|
|
224
183
|
// 初始化游戏
|
|
225
184
|
server.init({
|
|
226
|
-
hash: 'v1.0.0',
|
|
227
185
|
world: { score: 0, level: 1 },
|
|
228
186
|
self: {
|
|
229
187
|
public: { name: 'Player1', x: 0, y: 0 }
|
|
@@ -232,12 +190,18 @@ server.init({
|
|
|
232
190
|
|
|
233
191
|
// 更新玩家位置
|
|
234
192
|
function movePlayer(x, y) {
|
|
235
|
-
server.
|
|
193
|
+
server.update({
|
|
194
|
+
self: {
|
|
195
|
+
public: { x, y }
|
|
196
|
+
}
|
|
197
|
+
});
|
|
236
198
|
}
|
|
237
199
|
|
|
238
200
|
// 更新分数
|
|
239
201
|
function updateScore(score) {
|
|
240
|
-
server.
|
|
202
|
+
server.update({
|
|
203
|
+
world: { score }
|
|
204
|
+
});
|
|
241
205
|
}
|
|
242
206
|
```
|
|
243
207
|
|
package/index.d.ts
CHANGED
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
export interface RiffleServerOptions {
|
|
9
9
|
/** WebSocket 服务器 URL */
|
|
10
10
|
url: string;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
/** 认证 token */
|
|
14
|
-
token: string;
|
|
11
|
+
/** 游戏时间戳(用于判断是否需要重新初始化,新 timestamp 必须大于旧的才会重置) */
|
|
12
|
+
timestamp: number;
|
|
15
13
|
/** 是否自动重连,默认 true */
|
|
16
14
|
autoReconnect?: boolean;
|
|
17
15
|
/** 重连间隔(毫秒),默认 3000 */
|
|
@@ -33,8 +31,6 @@ export interface PlayerSelfData {
|
|
|
33
31
|
* 初始化数据
|
|
34
32
|
*/
|
|
35
33
|
export interface InitData {
|
|
36
|
-
/** 游戏版本哈希值(必需) */
|
|
37
|
-
hash: string;
|
|
38
34
|
/** 世界初始数据(可选) */
|
|
39
35
|
world?: Record<string, any>;
|
|
40
36
|
/** 玩家初始数据(可选) */
|
|
@@ -63,68 +59,6 @@ export interface ServerData {
|
|
|
63
59
|
players: Array<Record<string, any>>;
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
/**
|
|
67
|
-
* WorldManager - 管理 world 数据的细粒度操作
|
|
68
|
-
*/
|
|
69
|
-
export class WorldManager {
|
|
70
|
-
/**
|
|
71
|
-
* 添加或设置 world 中的键值对
|
|
72
|
-
* @param key 键名
|
|
73
|
-
* @param value 值
|
|
74
|
-
*/
|
|
75
|
-
add(key: string, value: any): void;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 更新 world 中的键值对(与 add 相同,提供语义化接口)
|
|
79
|
-
* @param key 键名
|
|
80
|
-
* @param value 值
|
|
81
|
-
*/
|
|
82
|
-
update(key: string, value: any): void;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* 删除 world 中的键(通过设置为 null)
|
|
86
|
-
* @param key 键名
|
|
87
|
-
*/
|
|
88
|
-
delete(key: string): void;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 批量设置多个键值对
|
|
92
|
-
* @param data 键值对对象
|
|
93
|
-
*/
|
|
94
|
-
set(data: Record<string, any>): void;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* SelfManager - 管理 self 数据的细粒度操作
|
|
99
|
-
*/
|
|
100
|
-
export class SelfManager {
|
|
101
|
-
/**
|
|
102
|
-
* 添加或设置 self.public 中的键值对
|
|
103
|
-
* @param key 键名
|
|
104
|
-
* @param value 值
|
|
105
|
-
*/
|
|
106
|
-
add(key: string, value: any): void;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 更新 self.public 中的键值对(与 add 相同,提供语义化接口)
|
|
110
|
-
* @param key 键名
|
|
111
|
-
* @param value 值
|
|
112
|
-
*/
|
|
113
|
-
update(key: string, value: any): void;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* 删除 self.public 中的键(通过设置为 null)
|
|
117
|
-
* @param key 键名
|
|
118
|
-
*/
|
|
119
|
-
delete(key: string): void;
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* 批量设置多个键值对
|
|
123
|
-
* @param data 键值对对象
|
|
124
|
-
*/
|
|
125
|
-
set(data: Record<string, any>): void;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
62
|
/**
|
|
129
63
|
* RiffleServer - 游戏服务器 WebSocket 客户端
|
|
130
64
|
*/
|
|
@@ -142,17 +76,18 @@ export class RiffleServer {
|
|
|
142
76
|
/** 是否已初始化 */
|
|
143
77
|
readonly isInitialized: boolean;
|
|
144
78
|
|
|
145
|
-
/** World 数据管理器 */
|
|
146
|
-
readonly world: WorldManager;
|
|
147
|
-
/** Self 数据管理器 */
|
|
148
|
-
readonly self: SelfManager;
|
|
149
|
-
|
|
150
79
|
/**
|
|
151
80
|
* 初始化服务器(必需,连接后必须先调用)
|
|
152
81
|
* @param initData 初始化数据
|
|
153
82
|
*/
|
|
154
83
|
init(initData: InitData): void;
|
|
155
84
|
|
|
85
|
+
/**
|
|
86
|
+
* 更新数据(部分更新,合并到现有数据)
|
|
87
|
+
* @param updateData 更新数据
|
|
88
|
+
*/
|
|
89
|
+
update(updateData: UpdateData): void;
|
|
90
|
+
|
|
156
91
|
/**
|
|
157
92
|
* 监听服务器推送的最新数据
|
|
158
93
|
* @param callback 回调函数,接收服务器推送的数据
|
package/index.js
CHANGED
|
@@ -28,160 +28,88 @@ if (typeof window !== 'undefined' && window.WebSocket) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
/**
|
|
32
|
-
* WorldManager - 管理 world 数据的细粒度操作
|
|
33
|
-
*/
|
|
34
|
-
class WorldManager {
|
|
35
|
-
constructor(server) {
|
|
36
|
-
this._server = server;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 添加或设置 world 中的键值对
|
|
41
|
-
* @param {string} key - 键名
|
|
42
|
-
* @param {any} value - 值
|
|
43
|
-
*/
|
|
44
|
-
add(key, value) {
|
|
45
|
-
this._server.sendUpdate({ world: { [key]: value } });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 更新 world 中的键值对(与 add 相同,提供语义化接口)
|
|
50
|
-
* @param {string} key - 键名
|
|
51
|
-
* @param {any} value - 值
|
|
52
|
-
*/
|
|
53
|
-
update(key, value) {
|
|
54
|
-
this._server.sendUpdate({ world: { [key]: value } });
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 删除 world 中的键(通过设置为 null)
|
|
59
|
-
* @param {string} key - 键名
|
|
60
|
-
*/
|
|
61
|
-
delete(key) {
|
|
62
|
-
this._server.sendUpdate({ world: { [key]: null } });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 批量设置多个键值对
|
|
67
|
-
* @param {Object} data - 键值对对象
|
|
68
|
-
*/
|
|
69
|
-
set(data) {
|
|
70
|
-
this._server.sendUpdate({ world: data });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* SelfManager - 管理 self 数据的细粒度操作
|
|
76
|
-
*/
|
|
77
|
-
class SelfManager {
|
|
78
|
-
constructor(server) {
|
|
79
|
-
this._server = server;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 添加或设置 self.public 中的键值对
|
|
84
|
-
* @param {string} key - 键名
|
|
85
|
-
* @param {any} value - 值
|
|
86
|
-
*/
|
|
87
|
-
add(key, value) {
|
|
88
|
-
this._server.sendUpdate({ self: { public: { [key]: value } } });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 更新 self.public 中的键值对(与 add 相同,提供语义化接口)
|
|
93
|
-
* @param {string} key - 键名
|
|
94
|
-
* @param {any} value - 值
|
|
95
|
-
*/
|
|
96
|
-
update(key, value) {
|
|
97
|
-
this._server.sendUpdate({ self: { public: { [key]: value } } });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 删除 self.public 中的键(通过设置为 null)
|
|
102
|
-
* @param {string} key - 键名
|
|
103
|
-
*/
|
|
104
|
-
delete(key) {
|
|
105
|
-
this._server.sendUpdate({ self: { public: { [key]: null } } });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 批量设置多个键值对
|
|
110
|
-
* @param {Object} data - 键值对对象
|
|
111
|
-
*/
|
|
112
|
-
set(data) {
|
|
113
|
-
this._server.sendUpdate({ self: { public: data } });
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
31
|
/**
|
|
118
32
|
* RiffleServer - 游戏服务器 WebSocket 客户端
|
|
119
33
|
*
|
|
120
34
|
* @example
|
|
121
35
|
* ```js
|
|
122
|
-
* import { RiffleServer } from '@
|
|
36
|
+
* import { RiffleServer } from '@riffle/server';
|
|
123
37
|
*
|
|
124
38
|
* const server = new RiffleServer({
|
|
125
39
|
* url: 'wss://api.riffle.app',
|
|
126
|
-
*
|
|
127
|
-
* token
|
|
40
|
+
* timestamp: Date.now()
|
|
41
|
+
* // post_id 和 token 会自动从浏览器 URL 参数中读取
|
|
42
|
+
* // 例如:https://example.com/game.html?post_id=123456&token=xxx
|
|
128
43
|
* });
|
|
129
44
|
*
|
|
130
45
|
* // 监听服务器推送的最新数据
|
|
131
46
|
* server.onData((data) => {
|
|
132
47
|
* console.log('World:', data.world);
|
|
133
|
-
* console.log('Self:', data.self);
|
|
48
|
+
* console.log('Self:', data.self); // self 现在直接是公开数据,与 players[i] 结构一致
|
|
134
49
|
* console.log('Players:', data.players);
|
|
135
50
|
* });
|
|
136
51
|
*
|
|
137
52
|
* // 初始化服务器(必需,连接后必须先调用)
|
|
138
53
|
* server.init({
|
|
139
|
-
* hash: 'game-version-hash-123',
|
|
140
|
-
* world: { score: 0, level: 1 },
|
|
54
|
+
* hash: 'game-version-hash-123', // 游戏版本哈希值
|
|
55
|
+
* world: { score: 0, level: 1 }, // 世界初始数据(可选)
|
|
141
56
|
* self: {
|
|
142
|
-
* public: { name: 'Player1', x: 100, y: 100 }
|
|
57
|
+
* public: { name: 'Player1', x: 100, y: 100 } // 公开数据(可选)
|
|
143
58
|
* }
|
|
144
59
|
* });
|
|
145
60
|
*
|
|
146
|
-
* //
|
|
147
|
-
* server.
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* server.self.delete('oldProp'); // 删除 self.public.oldProp
|
|
154
|
-
*
|
|
155
|
-
* // 批量操作
|
|
156
|
-
* server.world.set({ score: 200, level: 2 });
|
|
157
|
-
* server.self.set({ x: 150, y: 250, rotation: 90 });
|
|
61
|
+
* // 更新数据
|
|
62
|
+
* server.update({
|
|
63
|
+
* world: { score: 200 },
|
|
64
|
+
* self: {
|
|
65
|
+
* public: { x: 15, y: 25, rotation: 90 }
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
158
68
|
* ```
|
|
159
69
|
*/
|
|
160
70
|
export class RiffleServer {
|
|
161
71
|
/**
|
|
162
72
|
* @param {Object} options - 配置选项
|
|
163
|
-
* @param {string} options.url - WebSocket 服务器 URL(例如:'wss://api.riffle.app'
|
|
164
|
-
* @param {number} options.
|
|
165
|
-
* @param {string} options.token - 认证 token
|
|
73
|
+
* @param {string} options.url - WebSocket 服务器 URL(例如:'wss://api.riffle.app')
|
|
74
|
+
* @param {number} options.timestamp - 游戏时间戳(用于判断是否需要重新初始化,新 timestamp 必须大于旧的才会重置)
|
|
166
75
|
* @param {boolean} [options.autoReconnect=true] - 是否自动重连
|
|
167
76
|
* @param {number} [options.reconnectInterval=3000] - 重连间隔(毫秒)
|
|
168
77
|
*/
|
|
169
78
|
constructor(options) {
|
|
170
|
-
const { url,
|
|
79
|
+
const { url, timestamp, autoReconnect = true, reconnectInterval = 3000 } = options;
|
|
171
80
|
|
|
172
81
|
if (!url) {
|
|
173
82
|
throw new Error('URL is required');
|
|
174
83
|
}
|
|
84
|
+
if (!timestamp) {
|
|
85
|
+
throw new Error('timestamp is required');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 从浏览器 URL 参数中读取 post_id 和 token
|
|
89
|
+
let postId;
|
|
90
|
+
let token;
|
|
91
|
+
|
|
92
|
+
if (isBrowser && typeof window !== 'undefined' && window.location) {
|
|
93
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
94
|
+
if (urlParams.has('post_id')) {
|
|
95
|
+
postId = parseInt(urlParams.get('post_id'), 10);
|
|
96
|
+
}
|
|
97
|
+
if (urlParams.has('token')) {
|
|
98
|
+
token = urlParams.get('token');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
175
102
|
if (!postId) {
|
|
176
|
-
throw new Error('
|
|
103
|
+
throw new Error('post_id not found in browser URL parameters. Please ensure URL contains ?post_id=xxx');
|
|
177
104
|
}
|
|
178
105
|
if (!token) {
|
|
179
|
-
throw new Error('token
|
|
106
|
+
throw new Error('token not found in browser URL parameters. Please ensure URL contains &token=xxx');
|
|
180
107
|
}
|
|
181
108
|
|
|
182
109
|
this.url = url;
|
|
183
110
|
this.postId = postId;
|
|
184
111
|
this.token = token;
|
|
112
|
+
this.timestamp = timestamp;
|
|
185
113
|
this.autoReconnect = autoReconnect;
|
|
186
114
|
this.reconnectInterval = reconnectInterval;
|
|
187
115
|
|
|
@@ -196,10 +124,6 @@ export class RiffleServer {
|
|
|
196
124
|
// 当前服务器数据缓存
|
|
197
125
|
this.currentData = null;
|
|
198
126
|
|
|
199
|
-
// 创建细粒度操作管理器
|
|
200
|
-
this.world = new WorldManager(this);
|
|
201
|
-
this.self = new SelfManager(this);
|
|
202
|
-
|
|
203
127
|
// 连接状态(异步调用,不阻塞构造函数)
|
|
204
128
|
this.connect().catch(err => {
|
|
205
129
|
console.error('[RiffleServer] Initial connection failed:', err);
|
|
@@ -359,7 +283,6 @@ export class RiffleServer {
|
|
|
359
283
|
/**
|
|
360
284
|
* 初始化服务器(必需,连接后必须先调用)
|
|
361
285
|
* @param {Object} initData - 初始化数据
|
|
362
|
-
* @param {string} initData.hash - 游戏版本哈希值(必需)
|
|
363
286
|
* @param {Object} [initData.world] - 世界初始数据(可选)
|
|
364
287
|
* @param {Object} [initData.self] - 玩家初始数据(可选)
|
|
365
288
|
* @param {Object} [initData.self.public] - 公开数据(可选,旧格式)
|
|
@@ -367,7 +290,6 @@ export class RiffleServer {
|
|
|
367
290
|
* @example
|
|
368
291
|
* // 推荐:直接传递公开数据
|
|
369
292
|
* server.init({
|
|
370
|
-
* hash: 'game-version-hash-123',
|
|
371
293
|
* world: { score: 0, level: 1 },
|
|
372
294
|
* self: {
|
|
373
295
|
* public: { name: 'Player1', x: 100, y: 100 }
|
|
@@ -377,19 +299,13 @@ export class RiffleServer {
|
|
|
377
299
|
* @example
|
|
378
300
|
* // 也支持直接传递对象(服务端会将其作为 public 数据处理)
|
|
379
301
|
* server.init({
|
|
380
|
-
* hash: 'game-version-hash-123',
|
|
381
302
|
* world: { score: 0 },
|
|
382
303
|
* self: {
|
|
383
304
|
* public: { name: 'Player1' }
|
|
384
305
|
* }
|
|
385
306
|
* });
|
|
386
307
|
*/
|
|
387
|
-
init(initData) {
|
|
388
|
-
if (!initData || !initData.hash) {
|
|
389
|
-
console.error('[RiffleServer] hash is required for init');
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
308
|
+
init(initData = {}) {
|
|
393
309
|
// 如果还未连接,保存 init 请求,连接建立后自动执行
|
|
394
310
|
if (!this.isConnected || this.ws?.readyState !== WebSocketImpl.OPEN) {
|
|
395
311
|
console.log('[RiffleServer] Not connected yet, will init after connection');
|
|
@@ -409,7 +325,7 @@ export class RiffleServer {
|
|
|
409
325
|
_doInit(initData) {
|
|
410
326
|
try {
|
|
411
327
|
const initMessage = {
|
|
412
|
-
|
|
328
|
+
timestamp: this.timestamp,
|
|
413
329
|
world: initData.world || undefined,
|
|
414
330
|
self: initData.self || undefined
|
|
415
331
|
};
|
|
@@ -419,6 +335,25 @@ export class RiffleServer {
|
|
|
419
335
|
}
|
|
420
336
|
}
|
|
421
337
|
|
|
338
|
+
/**
|
|
339
|
+
* 更新数据(部分更新)
|
|
340
|
+
* @param {Object} updateData - 更新数据
|
|
341
|
+
* @param {Object} [updateData.world] - 世界数据(可选)
|
|
342
|
+
* @param {Object} [updateData.self] - 玩家数据(可选)
|
|
343
|
+
* @param {Object} [updateData.self.public] - 公开数据(可选)
|
|
344
|
+
* @param {Object} [updateData.self.private] - 私有数据(已弃用)
|
|
345
|
+
* @example
|
|
346
|
+
* server.update({
|
|
347
|
+
* world: { score: 200 },
|
|
348
|
+
* self: {
|
|
349
|
+
* public: { x: 15, y: 25, rotation: 90 }
|
|
350
|
+
* }
|
|
351
|
+
* });
|
|
352
|
+
*/
|
|
353
|
+
update(updateData) {
|
|
354
|
+
this.sendUpdate(updateData);
|
|
355
|
+
}
|
|
356
|
+
|
|
422
357
|
/**
|
|
423
358
|
* 监听服务器推送的最新数据
|
|
424
359
|
* @param {Function} callback - 回调函数,接收服务器推送的数据
|