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.
@@ -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 {};
@@ -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 (!conn || !this.remoteDescriptionReady.has(signal.connectionId)) {
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
- this.pendingCandidates.delete(connectionId);
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).catch(error => {
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).catch(error => {
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.20";
14
- export declare const defaultOptions: Options;
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.20';
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: 975,
25
+ protocolVersion: 1001,
27
26
  };