bedrock-portal-nethernet 2.2.0 → 2.4.0
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/dist/nethernet/server.d.ts +0 -12
- package/dist/nethernet/server.js +7 -90
- package/dist/options.d.ts +11 -3
- package/dist/options.js +2 -3
- package/dist/protocol.d.ts +234 -712
- package/dist/protocol.js +847 -877
- package/dist/server.js +1 -1
- package/dist/serverPlayer.js +2 -1
- package/dist/signaling/signal.d.ts +8 -27
- package/dist/signaling/signal.js +155 -320
- package/dist/signaling/struct.d.ts +4 -5
- package/dist/signaling/struct.js +5 -4
- package/package.json +4 -3
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
import { Connection } from './connection';
|
|
2
2
|
import { Signal } from '../signaling/signal';
|
|
3
3
|
import { SignalStructure } from '../signaling/struct';
|
|
4
|
-
type PendingCandidate = {
|
|
5
|
-
signal: SignalStructure;
|
|
6
|
-
attempts: number;
|
|
7
|
-
};
|
|
8
4
|
export declare class Server {
|
|
9
5
|
networkId: bigint;
|
|
10
6
|
connectionId: bigint;
|
|
11
7
|
signaling: Signal;
|
|
12
8
|
connections: Map<bigint, Connection>;
|
|
13
|
-
pendingCandidates: Map<bigint, PendingCandidate[]>;
|
|
14
|
-
remoteDescriptionReady: Set<bigint>;
|
|
15
|
-
pendingCandidateTimers: Map<bigint, NodeJS.Timeout>;
|
|
16
9
|
onOpenConnection: (conn: Connection) => void;
|
|
17
10
|
onCloseConnection: (id: bigint, reason: string) => void;
|
|
18
11
|
onEncapsulated: (packet: Buffer, id: bigint) => void;
|
|
19
12
|
constructor(signaling: Signal, networkId?: bigint, connectionId?: bigint);
|
|
20
13
|
handleCandidate(signal: SignalStructure): Promise<void>;
|
|
21
|
-
queueCandidate(signal: SignalStructure, reason?: string): void;
|
|
22
|
-
schedulePendingCandidateFlush(connectionId: bigint): void;
|
|
23
|
-
flushPendingCandidates(connectionId: bigint): void;
|
|
24
|
-
requeueCandidate(candidate: PendingCandidate, remaining: PendingCandidate[], reason: string): void;
|
|
25
14
|
handleOffer(signal: SignalStructure): Promise<void>;
|
|
26
15
|
listen(): Promise<void>;
|
|
27
16
|
close(): void;
|
|
28
17
|
}
|
|
29
|
-
export {};
|
package/dist/nethernet/server.js
CHANGED
|
@@ -5,8 +5,6 @@ const node_datachannel_1 = require("node-datachannel");
|
|
|
5
5
|
const connection_1 = require("./connection");
|
|
6
6
|
const struct_1 = require("../signaling/struct");
|
|
7
7
|
const debugFn = require('debug')('bedrock-portal-nethernet');
|
|
8
|
-
const MAX_PENDING_CANDIDATE_ATTEMPTS = 50;
|
|
9
|
-
const PENDING_CANDIDATE_RETRY_MS = 100;
|
|
10
8
|
const getRandomUint64 = () => {
|
|
11
9
|
const high = Math.floor(Math.random() * 0xFFFFFFFF);
|
|
12
10
|
const low = Math.floor(Math.random() * 0xFFFFFFFF);
|
|
@@ -17,9 +15,6 @@ class Server {
|
|
|
17
15
|
connectionId;
|
|
18
16
|
signaling;
|
|
19
17
|
connections;
|
|
20
|
-
pendingCandidates;
|
|
21
|
-
remoteDescriptionReady;
|
|
22
|
-
pendingCandidateTimers;
|
|
23
18
|
onOpenConnection;
|
|
24
19
|
onCloseConnection;
|
|
25
20
|
onEncapsulated;
|
|
@@ -28,78 +23,18 @@ class Server {
|
|
|
28
23
|
this.networkId = networkId;
|
|
29
24
|
this.connectionId = connectionId;
|
|
30
25
|
this.connections = new Map();
|
|
31
|
-
this.pendingCandidates = new Map();
|
|
32
|
-
this.remoteDescriptionReady = new Set();
|
|
33
|
-
this.pendingCandidateTimers = new Map();
|
|
34
26
|
this.onOpenConnection = () => { };
|
|
35
27
|
this.onCloseConnection = () => { };
|
|
36
28
|
this.onEncapsulated = () => { };
|
|
37
29
|
}
|
|
38
30
|
async handleCandidate(signal) {
|
|
39
31
|
const conn = this.connections.get(signal.connectionId);
|
|
40
|
-
if (
|
|
41
|
-
this.queueCandidate(signal);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
32
|
+
if (conn) {
|
|
45
33
|
conn.rtcConnection.addRemoteCandidate(signal.data, '0');
|
|
46
34
|
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
this.queueCandidate(signal, formatCandidateError(error));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
queueCandidate(signal, reason = 'connection is not ready') {
|
|
52
|
-
const candidates = this.pendingCandidates.get(signal.connectionId) || [];
|
|
53
|
-
candidates.push({ signal, attempts: 0 });
|
|
54
|
-
this.pendingCandidates.set(signal.connectionId, candidates);
|
|
55
|
-
debugFn('Queued ICE candidate', signal.connectionId, reason);
|
|
56
|
-
this.schedulePendingCandidateFlush(signal.connectionId);
|
|
57
|
-
}
|
|
58
|
-
schedulePendingCandidateFlush(connectionId) {
|
|
59
|
-
if (this.pendingCandidateTimers.has(connectionId))
|
|
60
|
-
return;
|
|
61
|
-
const timer = setTimeout(() => {
|
|
62
|
-
this.pendingCandidateTimers.delete(connectionId);
|
|
63
|
-
this.flushPendingCandidates(connectionId);
|
|
64
|
-
}, PENDING_CANDIDATE_RETRY_MS);
|
|
65
|
-
timer.unref?.();
|
|
66
|
-
this.pendingCandidateTimers.set(connectionId, timer);
|
|
67
|
-
}
|
|
68
|
-
flushPendingCandidates(connectionId) {
|
|
69
|
-
const candidates = this.pendingCandidates.get(connectionId);
|
|
70
|
-
if (!candidates?.length)
|
|
71
|
-
return;
|
|
72
|
-
const conn = this.connections.get(connectionId);
|
|
73
|
-
const remaining = [];
|
|
74
|
-
for (const candidate of candidates) {
|
|
75
|
-
if (!conn || !this.remoteDescriptionReady.has(connectionId)) {
|
|
76
|
-
this.requeueCandidate(candidate, remaining, 'connection is not ready');
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
conn.rtcConnection.addRemoteCandidate(candidate.signal.data, '0');
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
this.requeueCandidate(candidate, remaining, formatCandidateError(error));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (remaining.length) {
|
|
87
|
-
this.pendingCandidates.set(connectionId, remaining);
|
|
88
|
-
this.schedulePendingCandidateFlush(connectionId);
|
|
89
|
-
}
|
|
90
35
|
else {
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
requeueCandidate(candidate, remaining, reason) {
|
|
95
|
-
if (candidate.attempts >= MAX_PENDING_CANDIDATE_ATTEMPTS) {
|
|
96
|
-
debugFn('Dropping ICE candidate after retries', candidate.signal.connectionId, reason);
|
|
97
|
-
return;
|
|
36
|
+
debugFn('Received candidate for unknown connection', signal);
|
|
98
37
|
}
|
|
99
|
-
remaining.push({
|
|
100
|
-
signal: candidate.signal,
|
|
101
|
-
attempts: candidate.attempts + 1,
|
|
102
|
-
});
|
|
103
38
|
}
|
|
104
39
|
async handleOffer(signal) {
|
|
105
40
|
if (!this.signaling.credentials) {
|
|
@@ -109,7 +44,7 @@ class Server {
|
|
|
109
44
|
const connection = new connection_1.Connection(this, signal.connectionId, rtcConnection);
|
|
110
45
|
this.connections.set(signal.connectionId, connection);
|
|
111
46
|
rtcConnection.onLocalCandidate(candidate => {
|
|
112
|
-
this.signaling.write(new struct_1.SignalStructure(struct_1.SignalType.CandidateAdd, signal.connectionId, candidate, signal.networkId));
|
|
47
|
+
this.signaling.write(new struct_1.SignalStructure(struct_1.SignalType.CandidateAdd, signal.connectionId, candidate, signal.networkId, signal.pmsgId));
|
|
113
48
|
});
|
|
114
49
|
rtcConnection.onDataChannel(channel => {
|
|
115
50
|
if (channel.getLabel() === 'ReliableDataChannel')
|
|
@@ -120,34 +55,25 @@ class Server {
|
|
|
120
55
|
rtcConnection.onIceStateChange(state => {
|
|
121
56
|
if (state === 'connected')
|
|
122
57
|
this.onOpenConnection(connection);
|
|
123
|
-
if (state === 'disconnected')
|
|
124
|
-
this.remoteDescriptionReady.delete(signal.connectionId);
|
|
125
|
-
this.pendingCandidates.delete(signal.connectionId);
|
|
58
|
+
if (state === 'disconnected')
|
|
126
59
|
this.onCloseConnection(signal.connectionId, 'disconnected');
|
|
127
|
-
}
|
|
128
60
|
});
|
|
129
61
|
rtcConnection.setRemoteDescription(signal.data, 'offer');
|
|
130
|
-
this.remoteDescriptionReady.add(signal.connectionId);
|
|
131
|
-
this.flushPendingCandidates(signal.connectionId);
|
|
132
62
|
const answer = rtcConnection.localDescription();
|
|
133
63
|
if (!answer) {
|
|
134
64
|
throw new Error('No answer');
|
|
135
65
|
}
|
|
136
|
-
this.signaling.write(new struct_1.SignalStructure(struct_1.SignalType.ConnectResponse, signal.connectionId, answer.sdp, signal.networkId));
|
|
66
|
+
this.signaling.write(new struct_1.SignalStructure(struct_1.SignalType.ConnectResponse, signal.connectionId, answer.sdp, signal.networkId, signal.pmsgId));
|
|
137
67
|
}
|
|
138
68
|
async listen() {
|
|
139
69
|
await this.signaling.connect();
|
|
140
70
|
this.signaling.on('signal', (signal) => {
|
|
141
71
|
switch (signal.type) {
|
|
142
72
|
case struct_1.SignalType.ConnectRequest:
|
|
143
|
-
this.handleOffer(signal)
|
|
144
|
-
debugFn('Failed to handle connect offer', signal, error);
|
|
145
|
-
});
|
|
73
|
+
this.handleOffer(signal);
|
|
146
74
|
break;
|
|
147
75
|
case struct_1.SignalType.CandidateAdd:
|
|
148
|
-
this.handleCandidate(signal)
|
|
149
|
-
debugFn('Failed to handle ICE candidate', signal, error);
|
|
150
|
-
});
|
|
76
|
+
this.handleCandidate(signal);
|
|
151
77
|
break;
|
|
152
78
|
default:
|
|
153
79
|
debugFn('Received signal for unknown type', signal);
|
|
@@ -155,18 +81,9 @@ class Server {
|
|
|
155
81
|
});
|
|
156
82
|
}
|
|
157
83
|
close() {
|
|
158
|
-
for (const timer of this.pendingCandidateTimers.values()) {
|
|
159
|
-
clearTimeout(timer);
|
|
160
|
-
}
|
|
161
|
-
this.pendingCandidateTimers.clear();
|
|
162
|
-
this.pendingCandidates.clear();
|
|
163
|
-
this.remoteDescriptionReady.clear();
|
|
164
84
|
for (const conn of this.connections.values()) {
|
|
165
85
|
conn.close();
|
|
166
86
|
}
|
|
167
87
|
}
|
|
168
88
|
}
|
|
169
89
|
exports.Server = Server;
|
|
170
|
-
function formatCandidateError(error) {
|
|
171
|
-
return error instanceof Error ? error.message : String(error);
|
|
172
|
-
}
|
package/dist/options.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { CompressionAlgorithm } from './transforms/framer';
|
|
2
2
|
export type Options = {
|
|
3
3
|
version: string;
|
|
4
|
-
signalingMode: 'rpc' | 'legacy';
|
|
5
4
|
autoInitPlayer: boolean;
|
|
6
5
|
offline: boolean;
|
|
7
6
|
connectTimeout: number;
|
|
@@ -10,5 +9,14 @@ export type Options = {
|
|
|
10
9
|
compressionThreshold: number;
|
|
11
10
|
protocolVersion: number;
|
|
12
11
|
};
|
|
13
|
-
export declare const CURRENT_VERSION = "1.26.
|
|
14
|
-
export declare const defaultOptions:
|
|
12
|
+
export declare const CURRENT_VERSION = "1.26.30";
|
|
13
|
+
export declare const defaultOptions: {
|
|
14
|
+
version: string;
|
|
15
|
+
autoInitPlayer: boolean;
|
|
16
|
+
offline: boolean;
|
|
17
|
+
connectTimeout: number;
|
|
18
|
+
compressionAlgorithm: CompressionAlgorithm;
|
|
19
|
+
compressionLevel: number;
|
|
20
|
+
compressionThreshold: number;
|
|
21
|
+
protocolVersion: number;
|
|
22
|
+
};
|
package/dist/options.js
CHANGED
|
@@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.defaultOptions = exports.CURRENT_VERSION = void 0;
|
|
4
4
|
const framer_1 = require("./transforms/framer");
|
|
5
5
|
// Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data
|
|
6
|
-
exports.CURRENT_VERSION = '1.26.
|
|
6
|
+
exports.CURRENT_VERSION = '1.26.30';
|
|
7
7
|
exports.defaultOptions = {
|
|
8
8
|
// https://minecraft.wiki/w/Protocol_version#Bedrock_Edition_2
|
|
9
9
|
version: exports.CURRENT_VERSION,
|
|
10
|
-
signalingMode: 'rpc',
|
|
11
10
|
// client: If we should send SetPlayerInitialized to the server after getting play_status spawn.
|
|
12
11
|
// if this is disabled, no 'spawn' event will be emitted, you should manually set
|
|
13
12
|
// client.status to ClientStatus.Initialized after sending the init packet.
|
|
@@ -23,5 +22,5 @@ exports.defaultOptions = {
|
|
|
23
22
|
// server: If true, only compress if a payload is larger than compressionThreshold
|
|
24
23
|
compressionThreshold: 512,
|
|
25
24
|
// server and client: The protocol version to use
|
|
26
|
-
protocolVersion:
|
|
25
|
+
protocolVersion: 1001,
|
|
27
26
|
};
|