bedrock-portal 1.1.5 → 2.0.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/README.md +34 -37
- package/dist/classes/Host.js +59 -22
- package/dist/common/constants.js +1 -1
- package/dist/common/start_game.d.ts +10 -6
- package/dist/common/start_game.js +22 -24
- package/dist/index.d.ts +18 -11
- package/dist/index.js +68 -17
- package/dist/modules/autoFriendAccept.d.ts +6 -0
- package/dist/modules/autoFriendAccept.js +17 -12
- package/dist/modules/autoFriendAdd.js +3 -9
- package/dist/modules/inviteOnMessage.js +4 -8
- package/docs/migration-v2.md +126 -0
- package/package.json +1 -1
- package/dist/modules/multipleAccounts.d.ts +0 -23
- package/dist/modules/multipleAccounts.js +0 -58
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@ npm install bedrock-portal
|
|
|
12
12
|
### Warning
|
|
13
13
|
This package is not meant to be used with your main account. It is meant to be used with alt accounts. If you use this package with your main account, you may be banned from the XSAPI. This package is not affiliated with Mojang or Microsoft.
|
|
14
14
|
|
|
15
|
+
## Migration
|
|
16
|
+
|
|
17
|
+
Upgrading from v1.x to v2.x introduces breaking API changes. See [docs/migration-v2.md](docs/migration-v2.md).
|
|
18
|
+
|
|
15
19
|
## Usage
|
|
16
20
|
|
|
17
21
|
### BedrockPortal(options)
|
|
@@ -20,11 +24,12 @@ This package is not meant to be used with your main account. It is meant to be u
|
|
|
20
24
|
- **ip** - The IP address of the server to redirect players to (required)
|
|
21
25
|
- **port** - The port of the server to redirect players to | default: 19132
|
|
22
26
|
- **joinability** - The joinability of the session | default: Joinability.FriendsOfFriends
|
|
23
|
-
- **
|
|
27
|
+
- **host** - Either an Authflow instance from [prismarine-auth](https://github.com/PrismarineJS/prismarine-auth#authflow) or an object with the following properties:
|
|
24
28
|
- **username** - The username of the account to use for the session | default: 'BedrockPortal'
|
|
25
29
|
- **cache** - The cache directory to use for the session | default: './'
|
|
26
30
|
- **options** - Options for the Authflow instance from [prismarine-auth](https://github.com/PrismarineJS/prismarine-auth#authflow)
|
|
27
|
-
- **
|
|
31
|
+
- **peers** - Additional accounts that should be connected to the session. Each entry can be either an Authflow instance or an object with the same shape as **host**. | default: []
|
|
32
|
+
- **updatePresence** - Whether to update the presence of the authenticated account making it appear as if they are playing Minecraft. Will also update the presence of any connected peers. | default: true
|
|
28
33
|
- **world** - The world config to use for the session. Changes the session card which is displayed in the Minecraft client. (optional)
|
|
29
34
|
- **hostName** - string
|
|
30
35
|
- **name** - string
|
|
@@ -57,10 +62,37 @@ const main = async () => {
|
|
|
57
62
|
main();
|
|
58
63
|
```
|
|
59
64
|
|
|
65
|
+
### Use multiple joinable accounts
|
|
66
|
+
```js
|
|
67
|
+
const { BedrockPortal, Modules } = require('bedrock-portal')
|
|
68
|
+
const { Titles } = require('prismarine-auth')
|
|
69
|
+
|
|
70
|
+
const main = async () => {
|
|
71
|
+
const portal = new BedrockPortal({
|
|
72
|
+
ip: 'your.server.ip',
|
|
73
|
+
port: 19132,
|
|
74
|
+
peers: [
|
|
75
|
+
{ username: 'account1' },
|
|
76
|
+
{ username: 'account2' },
|
|
77
|
+
],
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
portal.use(Modules.AutoFriendAdd, {
|
|
81
|
+
inviteOnAdd: true,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
await portal.start()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main()
|
|
88
|
+
```
|
|
89
|
+
|
|
60
90
|
## Modules
|
|
61
91
|
|
|
62
92
|
Modules are used to extend the functionality of the BedrockPortal class. **Modules should be initialised before calling the `start` method.**
|
|
63
93
|
|
|
94
|
+
Modules that operate on Xbox accounts use the primary **host** account and any configured **peers** automatically.
|
|
95
|
+
|
|
64
96
|
### ServerFormList
|
|
65
97
|
|
|
66
98
|
Instead of redirecting players to a server, the portal will display a list of servers to join from a form. `#.use(Modules.serverFormList, options);`
|
|
@@ -99,41 +131,6 @@ const main = async () => {
|
|
|
99
131
|
main()
|
|
100
132
|
```
|
|
101
133
|
|
|
102
|
-
### MultipleAccounts
|
|
103
|
-
|
|
104
|
-
Allows the portal to use multiple accounts to redirect players to the server. `#.use(Modules.MultipleAccounts, options);`
|
|
105
|
-
|
|
106
|
-
Options:
|
|
107
|
-
- **accounts**: Authflow[] - An array of authflows from [prismarine-auth](https://github.com/PrismarineJS/prismarine-auth), these accounts are automatically added to the host session and allows players to add them as a friend to join the game. (required)
|
|
108
|
-
|
|
109
|
-
```js
|
|
110
|
-
const { Authflow, Titles } = require('prismarine-auth')
|
|
111
|
-
const { BedrockPortal, Modules } = require('bedrock-portal')
|
|
112
|
-
|
|
113
|
-
const main = async () => {
|
|
114
|
-
const portal = new BedrockPortal( {
|
|
115
|
-
ip: 'your.server.ip',
|
|
116
|
-
port: 19132,
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
portal.use(Modules.AutoFriendAdd, {
|
|
120
|
-
inviteOnAdd: true,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
portal.use(Modules.MultipleAccounts, {
|
|
124
|
-
accounts: [
|
|
125
|
-
new Authflow('account1', './', { authTitle: Titles.MinecraftIOS, deviceType: 'iOS', flow: 'sisu' }),
|
|
126
|
-
new Authflow('account2', './', { authTitle: Titles.MinecraftIOS, deviceType: 'iOS', flow: 'sisu' }),
|
|
127
|
-
],
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
await portal.start()
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
main()
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
|
|
137
134
|
### RedirectFromRealm
|
|
138
135
|
|
|
139
136
|
> Requires [bedrock-protocol](https://github.com/PrismarineJS/bedrock-protocol) to be installed. `npm install bedrock-protocol`
|
package/dist/classes/Host.js
CHANGED
|
@@ -23,33 +23,67 @@ class Host {
|
|
|
23
23
|
this.rest = new rest_1.default(this.authflow);
|
|
24
24
|
}
|
|
25
25
|
async connect() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.
|
|
41
|
-
|
|
26
|
+
let rta = null;
|
|
27
|
+
let presenceInterval = null;
|
|
28
|
+
try {
|
|
29
|
+
const auth = await this.authflow.getXboxToken();
|
|
30
|
+
const profile = await this.rest.getProfile(auth.userXUID);
|
|
31
|
+
rta = new xbox_rta_1.XboxRTA(this.authflow);
|
|
32
|
+
await rta.connect();
|
|
33
|
+
const subResponse = await rta.subscribe('https://sessiondirectory.xboxlive.com/connections/');
|
|
34
|
+
const subData = subResponse.data;
|
|
35
|
+
this.profile = profile;
|
|
36
|
+
this.rta = rta;
|
|
37
|
+
this.connectionId = subData.ConnectionId ?? null;
|
|
38
|
+
this.subscriptionId = (0, uuid_1.v4)();
|
|
39
|
+
this.rta.on('subscribe', (event) => this.onSubscribe(event));
|
|
40
|
+
if (this.portal.options.updatePresence) {
|
|
41
|
+
const updatePresence = () => {
|
|
42
|
+
if (this.profile) {
|
|
43
|
+
this.rest.setPresence(this.profile.xuid)
|
|
44
|
+
.catch(e => { debug('Failed to set presence', e); });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
presenceInterval = setInterval(updatePresence, 300000);
|
|
48
|
+
this.presenceInterval = presenceInterval;
|
|
49
|
+
updatePresence();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
if (presenceInterval) {
|
|
54
|
+
clearInterval(presenceInterval);
|
|
55
|
+
}
|
|
56
|
+
if (rta) {
|
|
57
|
+
await rta.destroy()
|
|
58
|
+
.catch(error => { debug('Failed to destroy host RTA during connect cleanup', error); });
|
|
59
|
+
}
|
|
60
|
+
this.rta = null;
|
|
61
|
+
this.profile = null;
|
|
62
|
+
this.connectionId = null;
|
|
63
|
+
this.presenceInterval = null;
|
|
64
|
+
this.subscriptionId = (0, uuid_1.v4)();
|
|
65
|
+
throw e;
|
|
42
66
|
}
|
|
43
67
|
}
|
|
44
68
|
async disconnect() {
|
|
45
|
-
|
|
46
|
-
|
|
69
|
+
const rta = this.rta;
|
|
70
|
+
const presenceInterval = this.presenceInterval;
|
|
71
|
+
const sessionName = this.portal.session.name;
|
|
72
|
+
this.rta = null;
|
|
73
|
+
this.profile = null;
|
|
74
|
+
this.connectionId = null;
|
|
75
|
+
this.presenceInterval = null;
|
|
76
|
+
this.subscriptionId = (0, uuid_1.v4)();
|
|
77
|
+
if (presenceInterval) {
|
|
78
|
+
clearInterval(presenceInterval);
|
|
79
|
+
}
|
|
80
|
+
if (rta) {
|
|
81
|
+
await rta.destroy();
|
|
47
82
|
}
|
|
48
|
-
if (
|
|
49
|
-
|
|
83
|
+
if (sessionName) {
|
|
84
|
+
await this.rest.leaveSession(sessionName);
|
|
50
85
|
}
|
|
51
|
-
|
|
52
|
-
.catch(() => { debug('Failed to leave session as host'); });
|
|
86
|
+
debug('Successfully disconnected host', this.authflow.username);
|
|
53
87
|
}
|
|
54
88
|
async onSubscribe(event) {
|
|
55
89
|
const connectionId = event.data?.ConnectionId;
|
|
@@ -57,6 +91,9 @@ class Host {
|
|
|
57
91
|
debug('Received RTA subscribe event', event);
|
|
58
92
|
try {
|
|
59
93
|
this.connectionId = connectionId;
|
|
94
|
+
if (!this.portal.session.name) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
60
97
|
await this.rest.updateConnection(this.portal.session.name, connectionId);
|
|
61
98
|
await this.rest.setActivity(this.portal.session.name);
|
|
62
99
|
}
|
package/dist/common/constants.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.SessionConfig = {
|
|
|
5
5
|
MinecraftTitleID: '896928775',
|
|
6
6
|
MinecraftSCID: '4fc10100-5f7a-4470-899b-280835760c07',
|
|
7
7
|
MinecraftTemplateName: 'MinecraftLobby',
|
|
8
|
-
MiencraftProtocolVersion:
|
|
8
|
+
MiencraftProtocolVersion: 924,
|
|
9
9
|
};
|
|
10
10
|
var Joinability;
|
|
11
11
|
(function (Joinability) {
|
|
@@ -11,7 +11,7 @@ export declare const start_game: {
|
|
|
11
11
|
x: number;
|
|
12
12
|
z: number;
|
|
13
13
|
};
|
|
14
|
-
seed:
|
|
14
|
+
seed: never[];
|
|
15
15
|
biome_type: number;
|
|
16
16
|
biome_name: string;
|
|
17
17
|
dimension: string;
|
|
@@ -69,17 +69,13 @@ export declare const start_game: {
|
|
|
69
69
|
experimental_gameplay_override: boolean;
|
|
70
70
|
chat_restriction_level: string;
|
|
71
71
|
disable_player_interactions: boolean;
|
|
72
|
-
server_identifier: string;
|
|
73
|
-
world_identifier: string;
|
|
74
|
-
scenario_identifier: string;
|
|
75
|
-
owner_identifier: string;
|
|
76
72
|
level_id: string;
|
|
77
73
|
world_name: string;
|
|
78
74
|
premium_world_template_id: string;
|
|
79
75
|
is_trial: boolean;
|
|
80
76
|
rewind_history_size: number;
|
|
81
77
|
server_authoritative_block_breaking: boolean;
|
|
82
|
-
current_tick:
|
|
78
|
+
current_tick: never[];
|
|
83
79
|
enchantment_seed: number;
|
|
84
80
|
block_properties: never[];
|
|
85
81
|
multiplayer_correlation_id: string;
|
|
@@ -95,4 +91,12 @@ export declare const start_game: {
|
|
|
95
91
|
client_side_generation: boolean;
|
|
96
92
|
block_network_ids_are_hashes: boolean;
|
|
97
93
|
server_controlled_sound: boolean;
|
|
94
|
+
has_server_join_info: boolean;
|
|
95
|
+
server_join_info: {
|
|
96
|
+
has_gathering_info: boolean;
|
|
97
|
+
};
|
|
98
|
+
server_identifier: string;
|
|
99
|
+
scenario_identifier: string;
|
|
100
|
+
world_identifier: string;
|
|
101
|
+
owner_identifier: string;
|
|
98
102
|
};
|
|
@@ -2,22 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.start_game = void 0;
|
|
4
4
|
exports.start_game = {
|
|
5
|
-
entity_id: '-
|
|
6
|
-
runtime_entity_id: '
|
|
5
|
+
entity_id: '-8589934591',
|
|
6
|
+
runtime_entity_id: '1',
|
|
7
7
|
player_gamemode: 'fallback',
|
|
8
8
|
player_position: {
|
|
9
|
-
x:
|
|
10
|
-
y:
|
|
11
|
-
z:
|
|
9
|
+
x: 0.5,
|
|
10
|
+
y: 32769.62109375,
|
|
11
|
+
z: 0.5,
|
|
12
12
|
},
|
|
13
13
|
rotation: {
|
|
14
14
|
x: 0,
|
|
15
15
|
z: 0,
|
|
16
16
|
},
|
|
17
|
-
seed: [
|
|
18
|
-
3914114795,
|
|
19
|
-
628404793,
|
|
20
|
-
],
|
|
17
|
+
seed: [],
|
|
21
18
|
biome_type: 0,
|
|
22
19
|
biome_name: 'minecraft:plains',
|
|
23
20
|
dimension: 'overworld',
|
|
@@ -26,15 +23,15 @@ exports.start_game = {
|
|
|
26
23
|
hardcore: false,
|
|
27
24
|
difficulty: 1,
|
|
28
25
|
spawn_position: {
|
|
29
|
-
x:
|
|
26
|
+
x: 0,
|
|
30
27
|
y: 32767,
|
|
31
|
-
z:
|
|
28
|
+
z: 0,
|
|
32
29
|
},
|
|
33
30
|
achievements_disabled: true,
|
|
34
31
|
editor_world_type: 'not_editor',
|
|
35
32
|
created_in_editor: false,
|
|
36
33
|
exported_from_editor: false,
|
|
37
|
-
day_cycle_stop_time:
|
|
34
|
+
day_cycle_stop_time: 16,
|
|
38
35
|
edu_offer: 0,
|
|
39
36
|
edu_features_enabled: false,
|
|
40
37
|
edu_product_uuid: '',
|
|
@@ -75,25 +72,18 @@ exports.start_game = {
|
|
|
75
72
|
experimental_gameplay_override: false,
|
|
76
73
|
chat_restriction_level: 'none',
|
|
77
74
|
disable_player_interactions: false,
|
|
78
|
-
server_identifier: '',
|
|
79
|
-
world_identifier: '',
|
|
80
|
-
scenario_identifier: '',
|
|
81
|
-
owner_identifier: '',
|
|
82
75
|
level_id: 'Bedrock level',
|
|
83
76
|
world_name: 'Bedrock level',
|
|
84
77
|
premium_world_template_id: '00000000-0000-0000-0000-000000000000',
|
|
85
78
|
is_trial: false,
|
|
86
79
|
rewind_history_size: 40,
|
|
87
80
|
server_authoritative_block_breaking: true,
|
|
88
|
-
current_tick: [
|
|
89
|
-
|
|
90
|
-
12818,
|
|
91
|
-
],
|
|
92
|
-
enchantment_seed: 270445177,
|
|
81
|
+
current_tick: [],
|
|
82
|
+
enchantment_seed: 819671441,
|
|
93
83
|
block_properties: [],
|
|
94
|
-
multiplayer_correlation_id: '<raknet>
|
|
84
|
+
multiplayer_correlation_id: '<raknet>94bd-eecc-2f56-479c',
|
|
95
85
|
server_authoritative_inventory: true,
|
|
96
|
-
engine: '1.
|
|
86
|
+
engine: '1.26.0',
|
|
97
87
|
property_data: {
|
|
98
88
|
type: 'compound',
|
|
99
89
|
name: '',
|
|
@@ -101,7 +91,15 @@ exports.start_game = {
|
|
|
101
91
|
},
|
|
102
92
|
block_pallette_checksum: [],
|
|
103
93
|
world_template_id: '00000000-0000-0000-0000-000000000000',
|
|
104
|
-
client_side_generation:
|
|
94
|
+
client_side_generation: false,
|
|
105
95
|
block_network_ids_are_hashes: true,
|
|
106
96
|
server_controlled_sound: true,
|
|
97
|
+
has_server_join_info: true,
|
|
98
|
+
server_join_info: {
|
|
99
|
+
has_gathering_info: false,
|
|
100
|
+
},
|
|
101
|
+
server_identifier: '',
|
|
102
|
+
scenario_identifier: '',
|
|
103
|
+
world_identifier: '',
|
|
104
|
+
owner_identifier: '',
|
|
107
105
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Message } from 'xbox-message';
|
|
|
3
3
|
import { EventResponse } from 'xbox-rta';
|
|
4
4
|
import { TypedEmitter } from 'tiny-typed-emitter';
|
|
5
5
|
import { Server } from 'bedrock-portal-nethernet';
|
|
6
|
-
import { Authflow, CacheFactory, MicrosoftAuthFlowOptions } from 'prismarine-auth';
|
|
6
|
+
import { Authflow, CacheFactory, MicrosoftAuthFlowOptions, ServerDeviceCodeResponse } from 'prismarine-auth';
|
|
7
7
|
import Host from './classes/Host';
|
|
8
8
|
import Player from './classes/Player';
|
|
9
9
|
import Module from './classes/Module';
|
|
@@ -11,14 +11,14 @@ import { Joinability } from './common/constants';
|
|
|
11
11
|
import AutoFriendAdd from './modules/autoFriendAdd';
|
|
12
12
|
import InviteOnMessage from './modules/inviteOnMessage';
|
|
13
13
|
import RedirectFromRealm from './modules/redirectFromRealm';
|
|
14
|
-
import MultipleAccounts from './modules/multipleAccounts';
|
|
15
14
|
import AutoFriendAccept from './modules/autoFriendAccept';
|
|
16
15
|
import UpdateMemberCount from './modules/updateMemberCount';
|
|
17
16
|
import ServerFromList from './modules/serverFormList';
|
|
18
17
|
type AuthflowOptions = {
|
|
19
|
-
username
|
|
20
|
-
cache
|
|
21
|
-
options
|
|
18
|
+
username?: string;
|
|
19
|
+
cache?: string | CacheFactory;
|
|
20
|
+
options?: MicrosoftAuthFlowOptions;
|
|
21
|
+
onMsaCode?: (res: ServerDeviceCodeResponse) => void;
|
|
22
22
|
};
|
|
23
23
|
type BedrockPortalOptions = {
|
|
24
24
|
/**
|
|
@@ -60,12 +60,17 @@ type BedrockPortalOptions = {
|
|
|
60
60
|
*/
|
|
61
61
|
updatePresence: boolean;
|
|
62
62
|
/**
|
|
63
|
-
* The
|
|
63
|
+
* The authflow options or authflow instance to use for the host account.
|
|
64
64
|
*/
|
|
65
|
-
|
|
65
|
+
host: AuthflowOptions | Authflow;
|
|
66
66
|
/**
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
* Additional accounts which are connected to the session and can be used to join the portal..
|
|
68
|
+
* @default []
|
|
69
|
+
*/
|
|
70
|
+
peers: (AuthflowOptions | Authflow)[];
|
|
71
|
+
/**
|
|
72
|
+
* The world config to use for the session. Changes the session card which is displayed in the Minecraft client
|
|
73
|
+
*/
|
|
69
74
|
world: {
|
|
70
75
|
/**
|
|
71
76
|
* The host name of the world.
|
|
@@ -122,13 +127,13 @@ interface PortalEvents {
|
|
|
122
127
|
}) => void;
|
|
123
128
|
}
|
|
124
129
|
export declare class BedrockPortal extends TypedEmitter<PortalEvents> {
|
|
125
|
-
authflow: Authflow;
|
|
126
130
|
host: Host;
|
|
127
131
|
options: BedrockPortalOptions;
|
|
128
132
|
session: {
|
|
129
133
|
name: string;
|
|
130
134
|
};
|
|
131
135
|
players: Map<string, Player>;
|
|
136
|
+
peers: Map<string, Host>;
|
|
132
137
|
modules: Map<string, Module>;
|
|
133
138
|
server: Server;
|
|
134
139
|
constructor(options?: Partial<BedrockPortalOptions>);
|
|
@@ -145,6 +150,7 @@ export declare class BedrockPortal extends TypedEmitter<PortalEvents> {
|
|
|
145
150
|
* Returns the current members in the session.
|
|
146
151
|
*/
|
|
147
152
|
getSessionMembers(): Map<string, Player>;
|
|
153
|
+
getHostAndPeers(): Host[];
|
|
148
154
|
/**
|
|
149
155
|
* Invites a player to the BedrockPortal instance.
|
|
150
156
|
* @param identifyer The player's gamertag or XUID.
|
|
@@ -178,6 +184,8 @@ export declare class BedrockPortal extends TypedEmitter<PortalEvents> {
|
|
|
178
184
|
use<T extends ExtendedModule>(mod: ExtendedModuleConstructor<T>, options?: Partial<T['options']>): void;
|
|
179
185
|
onServerConnection: (client: any) => void;
|
|
180
186
|
private createAndPublishSession;
|
|
187
|
+
private connectPeers;
|
|
188
|
+
private disconnectPeers;
|
|
181
189
|
private createSessionBody;
|
|
182
190
|
}
|
|
183
191
|
export { Joinability } from './common/constants';
|
|
@@ -186,7 +194,6 @@ declare const Modules: {
|
|
|
186
194
|
AutoFriendAdd: typeof AutoFriendAdd;
|
|
187
195
|
InviteOnMessage: typeof InviteOnMessage;
|
|
188
196
|
RedirectFromRealm: typeof RedirectFromRealm;
|
|
189
|
-
MultipleAccounts: typeof MultipleAccounts;
|
|
190
197
|
AutoFriendAccept: typeof AutoFriendAccept;
|
|
191
198
|
UpdateMemberCount: typeof UpdateMemberCount;
|
|
192
199
|
ServerFromList: typeof ServerFromList;
|
package/dist/index.js
CHANGED
|
@@ -17,19 +17,31 @@ const Event_1 = __importDefault(require("./handlers/Event"));
|
|
|
17
17
|
const autoFriendAdd_1 = __importDefault(require("./modules/autoFriendAdd"));
|
|
18
18
|
const inviteOnMessage_1 = __importDefault(require("./modules/inviteOnMessage"));
|
|
19
19
|
const redirectFromRealm_1 = __importDefault(require("./modules/redirectFromRealm"));
|
|
20
|
-
const multipleAccounts_1 = __importDefault(require("./modules/multipleAccounts"));
|
|
21
20
|
const autoFriendAccept_1 = __importDefault(require("./modules/autoFriendAccept"));
|
|
22
21
|
const updateMemberCount_1 = __importDefault(require("./modules/updateMemberCount"));
|
|
23
22
|
const serverFormList_1 = __importDefault(require("./modules/serverFormList"));
|
|
24
23
|
const start_game_1 = require("./common/start_game");
|
|
25
24
|
const util_1 = require("./common/util");
|
|
26
25
|
const debug = (0, debug_1.default)('bedrock-portal');
|
|
26
|
+
const getDefaultAuthflowOptions = (options = {}) => ({
|
|
27
|
+
username: 'BedrockPortal',
|
|
28
|
+
cache: './',
|
|
29
|
+
options: {
|
|
30
|
+
authTitle: prismarine_auth_1.Titles.MinecraftIOS,
|
|
31
|
+
flow: 'sisu',
|
|
32
|
+
deviceType: 'iOS',
|
|
33
|
+
},
|
|
34
|
+
onMsaCode: (res) => {
|
|
35
|
+
console.log(`${options.username} - ${res.message}`);
|
|
36
|
+
},
|
|
37
|
+
...options,
|
|
38
|
+
});
|
|
27
39
|
class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
28
|
-
authflow;
|
|
29
40
|
host;
|
|
30
41
|
options;
|
|
31
42
|
session;
|
|
32
43
|
players;
|
|
44
|
+
peers;
|
|
33
45
|
modules = new Map();
|
|
34
46
|
server = new bedrock_portal_nethernet_1.Server();
|
|
35
47
|
constructor(options = {}) {
|
|
@@ -41,16 +53,8 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
41
53
|
webRTCNetworkId: (0, util_1.getRandomUint64)(),
|
|
42
54
|
updatePresence: true,
|
|
43
55
|
...options,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
cache: './',
|
|
47
|
-
options: {
|
|
48
|
-
authTitle: prismarine_auth_1.Titles.MinecraftIOS,
|
|
49
|
-
flow: 'sisu',
|
|
50
|
-
deviceType: 'iOS',
|
|
51
|
-
},
|
|
52
|
-
...options.authflow,
|
|
53
|
-
},
|
|
56
|
+
host: options.host instanceof prismarine_auth_1.Authflow ? options.host : getDefaultAuthflowOptions(options.host),
|
|
57
|
+
peers: options.peers ? options.peers.map(peer => peer instanceof prismarine_auth_1.Authflow ? peer : getDefaultAuthflowOptions(peer)) : [],
|
|
54
58
|
world: {
|
|
55
59
|
hostName: 'Bedrock Portal v1.0.0',
|
|
56
60
|
name: 'By LucienHH',
|
|
@@ -63,10 +67,10 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
63
67
|
},
|
|
64
68
|
};
|
|
65
69
|
this.validateOptions(this.options);
|
|
66
|
-
this.
|
|
67
|
-
this.host = new Host_1.default(this, this.authflow);
|
|
70
|
+
this.host = new Host_1.default(this, this.options.host instanceof prismarine_auth_1.Authflow ? this.options.host : new prismarine_auth_1.Authflow(this.options.host.username, this.options.host.cache, this.options.host.options, this.options.host.onMsaCode));
|
|
68
71
|
this.session = { name: '' };
|
|
69
72
|
this.players = new Map();
|
|
73
|
+
this.peers = new Map();
|
|
70
74
|
this.modules = new Map();
|
|
71
75
|
}
|
|
72
76
|
validateOptions(options) {
|
|
@@ -82,9 +86,10 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
82
86
|
this.players = new Map();
|
|
83
87
|
await this.host.connect();
|
|
84
88
|
this.session.name = (0, uuid_1.v4)();
|
|
85
|
-
await this.server.listen(this.authflow, this.options.webRTCNetworkId);
|
|
89
|
+
await this.server.listen(this.host.authflow, this.options.webRTCNetworkId);
|
|
86
90
|
this.server.on('connect', (client) => this.onServerConnection(client));
|
|
87
91
|
const session = await this.createAndPublishSession();
|
|
92
|
+
await this.connectPeers();
|
|
88
93
|
this.host.rta.on('event', (event) => {
|
|
89
94
|
(0, Event_1.default)(this, event)
|
|
90
95
|
.catch(e => debug('Failed to handle event', e));
|
|
@@ -102,13 +107,14 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
102
107
|
* Ends the BedrockPortal instance.
|
|
103
108
|
*/
|
|
104
109
|
async end(resume = false) {
|
|
105
|
-
await this.host.disconnect();
|
|
106
110
|
if (this.modules) {
|
|
107
111
|
for (const mod of this.modules.values()) {
|
|
108
112
|
debug(`Stopping module: ${mod.name}`);
|
|
109
113
|
await mod.stop();
|
|
110
114
|
}
|
|
111
115
|
}
|
|
116
|
+
await this.disconnectPeers();
|
|
117
|
+
await this.host.disconnect();
|
|
112
118
|
debug(`Abandoned session, name: ${this.session.name} - Resume: ${resume}`);
|
|
113
119
|
if (resume) {
|
|
114
120
|
return this.start();
|
|
@@ -120,6 +126,9 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
120
126
|
getSessionMembers() {
|
|
121
127
|
return this.players;
|
|
122
128
|
}
|
|
129
|
+
getHostAndPeers() {
|
|
130
|
+
return [this.host, ...this.peers.values()];
|
|
131
|
+
}
|
|
123
132
|
/**
|
|
124
133
|
* Invites a player to the BedrockPortal instance.
|
|
125
134
|
* @param identifyer The player's gamertag or XUID.
|
|
@@ -217,6 +226,49 @@ class BedrockPortal extends tiny_typed_emitter_1.TypedEmitter {
|
|
|
217
226
|
debug(`Published session, name: ${this.session.name}, ID: ${this.options.webRTCNetworkId}`);
|
|
218
227
|
return session;
|
|
219
228
|
}
|
|
229
|
+
async connectPeers() {
|
|
230
|
+
for (const account of this.options.peers) {
|
|
231
|
+
let peer = null;
|
|
232
|
+
try {
|
|
233
|
+
peer = new Host_1.default(this, account instanceof prismarine_auth_1.Authflow ? account : new prismarine_auth_1.Authflow(account.username, account.cache, account.options, account.onMsaCode));
|
|
234
|
+
await peer.connect();
|
|
235
|
+
if (!peer.profile || !peer.connectionId) {
|
|
236
|
+
throw Error(`Failed to connect to ${account.username}`);
|
|
237
|
+
}
|
|
238
|
+
debug(`Connected ${peer.profile.gamertag}`);
|
|
239
|
+
const hostAddPeer = await this.host.rest.addXboxFriend(peer.profile.xuid)
|
|
240
|
+
.then(() => null)
|
|
241
|
+
.catch(error => error);
|
|
242
|
+
const peerAddHost = await peer.rest.addXboxFriend(this.host.profile.xuid)
|
|
243
|
+
.then(() => null)
|
|
244
|
+
.catch(error => error);
|
|
245
|
+
if (hostAddPeer || peerAddHost) {
|
|
246
|
+
if (hostAddPeer)
|
|
247
|
+
debug(`Failed to add ${peer.profile.gamertag} as a friend - ${hostAddPeer.message}`);
|
|
248
|
+
if (peerAddHost)
|
|
249
|
+
debug(`Failed to add ${this.host.profile.gamertag} as a friend - ${peerAddHost.message}`);
|
|
250
|
+
throw Error(`Failed to create friendship between ${this.host.profile.gamertag} and ${peer.profile.gamertag}`);
|
|
251
|
+
}
|
|
252
|
+
await peer.rest.addConnection(this.session.name, peer.profile.xuid, peer.connectionId, peer.subscriptionId);
|
|
253
|
+
await peer.rest.setActivity(this.session.name);
|
|
254
|
+
this.peers.set(peer.profile.xuid, peer);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
debug(`Failed to initialise ${account.username} - ${error.message}`);
|
|
258
|
+
if (peer) {
|
|
259
|
+
await peer.disconnect()
|
|
260
|
+
.catch((err) => debug(`Failed to disconnect ${peer?.authflow.username ?? account.username}`, err));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async disconnectPeers() {
|
|
266
|
+
for (const peer of this.peers.values()) {
|
|
267
|
+
await peer.disconnect()
|
|
268
|
+
.catch((err) => debug(`Failed to disconnect ${peer.authflow.username}`, err));
|
|
269
|
+
}
|
|
270
|
+
this.peers.clear();
|
|
271
|
+
}
|
|
220
272
|
createSessionBody() {
|
|
221
273
|
if (!this.host.profile || !this.host.connectionId)
|
|
222
274
|
throw new Error('No session owner');
|
|
@@ -290,7 +342,6 @@ const Modules = {
|
|
|
290
342
|
AutoFriendAdd: autoFriendAdd_1.default,
|
|
291
343
|
InviteOnMessage: inviteOnMessage_1.default,
|
|
292
344
|
RedirectFromRealm: redirectFromRealm_1.default,
|
|
293
|
-
MultipleAccounts: multipleAccounts_1.default,
|
|
294
345
|
AutoFriendAccept: autoFriendAccept_1.default,
|
|
295
346
|
UpdateMemberCount: updateMemberCount_1.default,
|
|
296
347
|
ServerFromList: serverFormList_1.default,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { BedrockPortal } from '../index';
|
|
2
2
|
import type { FriendRequestPerson } from '../types/peoplehub';
|
|
3
|
+
import type { EventResponse } from 'xbox-rta';
|
|
3
4
|
import Module from '../classes/Module';
|
|
5
|
+
import Host from '../classes/Host';
|
|
4
6
|
export default class AutoFriendAccept extends Module {
|
|
5
7
|
options: {
|
|
6
8
|
/**
|
|
@@ -16,6 +18,10 @@ export default class AutoFriendAccept extends Module {
|
|
|
16
18
|
*/
|
|
17
19
|
conditionToMeet: (request: FriendRequestPerson) => boolean;
|
|
18
20
|
};
|
|
21
|
+
listeners: Map<string, {
|
|
22
|
+
host: Host;
|
|
23
|
+
listener: (event: EventResponse) => Promise<void>;
|
|
24
|
+
}>;
|
|
19
25
|
constructor(portal: BedrockPortal);
|
|
20
26
|
run(): Promise<void>;
|
|
21
27
|
stop(): Promise<void>;
|
|
@@ -5,19 +5,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const Module_1 = __importDefault(require("../classes/Module"));
|
|
7
7
|
const Player_1 = __importDefault(require("../classes/Player"));
|
|
8
|
-
const multipleAccounts_1 = __importDefault(require("./multipleAccounts"));
|
|
9
8
|
class AutoFriendAccept extends Module_1.default {
|
|
10
9
|
options;
|
|
10
|
+
listeners;
|
|
11
11
|
constructor(portal) {
|
|
12
12
|
super(portal, 'autoFriendAccept', 'Automatically accept friend requests');
|
|
13
13
|
this.options = {
|
|
14
14
|
inviteOnAdd: false,
|
|
15
15
|
conditionToMeet: () => true,
|
|
16
16
|
};
|
|
17
|
+
this.listeners = new Map();
|
|
17
18
|
}
|
|
18
19
|
async run() {
|
|
19
20
|
const addXboxFriend = async (host) => {
|
|
20
|
-
host.rta
|
|
21
|
+
if (!host.rta || !host.profile || this.listeners.has(host.authflow.username)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const listener = async (event) => {
|
|
21
25
|
if (event.data.NotificationType !== 'IncomingFriendRequestCountChanged')
|
|
22
26
|
return;
|
|
23
27
|
this.debug('Received Friend RTA event', event);
|
|
@@ -35,21 +39,22 @@ class AutoFriendAccept extends Module_1.default {
|
|
|
35
39
|
await this.portal.invitePlayer(person.xuid).catch(error => this.debug(`Error: Failed to invite ${person.gamertag}`, error));
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
42
|
+
};
|
|
43
|
+
this.listeners.set(host.authflow.username, { host, listener });
|
|
44
|
+
host.rta.on('event', listener);
|
|
45
|
+
await host.rta.subscribe(`https://social.xboxlive.com/users/xuid(${host.profile.xuid})/friends`);
|
|
40
46
|
};
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
addXboxFriend(account)
|
|
45
|
-
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
46
|
-
}
|
|
47
|
+
for (const account of this.portal.getHostAndPeers()) {
|
|
48
|
+
addXboxFriend(account)
|
|
49
|
+
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
47
50
|
}
|
|
48
|
-
addXboxFriend(this.portal.host)
|
|
49
|
-
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
50
51
|
}
|
|
51
52
|
async stop() {
|
|
52
53
|
super.stop();
|
|
54
|
+
for (const { host, listener } of this.listeners.values()) {
|
|
55
|
+
host.rta?.removeListener('event', listener);
|
|
56
|
+
}
|
|
57
|
+
this.listeners.clear();
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
exports.default = AutoFriendAccept;
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const promises_1 = require("timers/promises");
|
|
7
7
|
const Module_1 = __importDefault(require("../classes/Module"));
|
|
8
8
|
const Player_1 = __importDefault(require("../classes/Player"));
|
|
9
|
-
const multipleAccounts_1 = __importDefault(require("./multipleAccounts"));
|
|
10
9
|
class AutoFriendAdd extends Module_1.default {
|
|
11
10
|
interval = null;
|
|
12
11
|
options;
|
|
@@ -57,15 +56,10 @@ class AutoFriendAdd extends Module_1.default {
|
|
|
57
56
|
}
|
|
58
57
|
};
|
|
59
58
|
this.interval = setInterval(() => {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
addXboxFriend(account)
|
|
64
|
-
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
65
|
-
}
|
|
59
|
+
for (const account of this.portal.getHostAndPeers()) {
|
|
60
|
+
addXboxFriend(account)
|
|
61
|
+
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
66
62
|
}
|
|
67
|
-
addXboxFriend(this.portal.host)
|
|
68
|
-
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
69
63
|
}, this.options.checkInterval);
|
|
70
64
|
}
|
|
71
65
|
async stop() {
|
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const xbox_message_1 = require("xbox-message");
|
|
7
7
|
const Module_1 = __importDefault(require("../classes/Module"));
|
|
8
|
-
const multipleAccounts_1 = __importDefault(require("./multipleAccounts"));
|
|
9
8
|
class IniteOnMessage extends Module_1.default {
|
|
10
9
|
options;
|
|
11
10
|
clients;
|
|
@@ -32,20 +31,17 @@ class IniteOnMessage extends Module_1.default {
|
|
|
32
31
|
});
|
|
33
32
|
await client.connect();
|
|
34
33
|
};
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
xboxMessageHandler(account)
|
|
39
|
-
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
40
|
-
}
|
|
34
|
+
for (const account of this.portal.getHostAndPeers()) {
|
|
35
|
+
xboxMessageHandler(account)
|
|
36
|
+
.catch(error => this.debug(`Error: ${error.message}`, error));
|
|
41
37
|
}
|
|
42
|
-
xboxMessageHandler(this.portal.host);
|
|
43
38
|
}
|
|
44
39
|
async stop() {
|
|
45
40
|
super.stop();
|
|
46
41
|
for (const client of this.clients.values()) {
|
|
47
42
|
await client.destroy();
|
|
48
43
|
}
|
|
44
|
+
this.clients.clear();
|
|
49
45
|
}
|
|
50
46
|
}
|
|
51
47
|
exports.default = IniteOnMessage;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# V2 Migration Guide
|
|
2
|
+
|
|
3
|
+
This guide covers the breaking changes required to move from v1.x to v2.x.
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
The main API changes in v2 are:
|
|
8
|
+
|
|
9
|
+
- `authflow` has been renamed to `host` if you previously set a custom authflow in the constructor
|
|
10
|
+
- additional accounts are now configured with `peers` on `BedrockPortal`
|
|
11
|
+
- `Modules.MultipleAccounts` has been removed
|
|
12
|
+
- account-oriented modules automatically operate on the primary host and any configured peers
|
|
13
|
+
|
|
14
|
+
## Constructor Changes
|
|
15
|
+
|
|
16
|
+
If you did not pass `authflow` in v1, you do not need to add `host` in v2 unless you want to override the default account configuration.
|
|
17
|
+
|
|
18
|
+
### v1
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
const portal = new BedrockPortal({
|
|
22
|
+
ip: 'your.server.ip',
|
|
23
|
+
port: 19132,
|
|
24
|
+
authflow: new Authflow('main-account', './', {
|
|
25
|
+
authTitle: Titles.MinecraftIOS,
|
|
26
|
+
deviceType: 'iOS',
|
|
27
|
+
flow: 'sisu',
|
|
28
|
+
}),
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### v2
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
const portal = new BedrockPortal({
|
|
36
|
+
ip: 'your.server.ip',
|
|
37
|
+
port: 19132,
|
|
38
|
+
host: new Authflow('main-account', './', {
|
|
39
|
+
authTitle: Titles.MinecraftIOS,
|
|
40
|
+
deviceType: 'iOS',
|
|
41
|
+
flow: 'sisu',
|
|
42
|
+
}),
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can also pass a plain config object instead of an `Authflow` instance:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const portal = new BedrockPortal({
|
|
50
|
+
ip: 'your.server.ip',
|
|
51
|
+
port: 19132,
|
|
52
|
+
host: {
|
|
53
|
+
username: 'main-account',
|
|
54
|
+
cache: './',
|
|
55
|
+
options: {
|
|
56
|
+
authTitle: Titles.MinecraftIOS,
|
|
57
|
+
deviceType: 'iOS',
|
|
58
|
+
flow: 'sisu',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Multiple Account Changes
|
|
65
|
+
|
|
66
|
+
### v1
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
const portal = new BedrockPortal({
|
|
70
|
+
ip: 'your.server.ip',
|
|
71
|
+
port: 19132,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
portal.use(Modules.MultipleAccounts, {
|
|
75
|
+
accounts: [
|
|
76
|
+
new Authflow('account1', './', {
|
|
77
|
+
authTitle: Titles.MinecraftIOS,
|
|
78
|
+
deviceType: 'iOS',
|
|
79
|
+
flow: 'sisu',
|
|
80
|
+
}),
|
|
81
|
+
new Authflow('account2', './', {
|
|
82
|
+
authTitle: Titles.MinecraftIOS,
|
|
83
|
+
deviceType: 'iOS',
|
|
84
|
+
flow: 'sisu',
|
|
85
|
+
}),
|
|
86
|
+
],
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### v2
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
const portal = new BedrockPortal({
|
|
94
|
+
ip: 'your.server.ip',
|
|
95
|
+
port: 19132,
|
|
96
|
+
peers: [
|
|
97
|
+
new Authflow('account1', './', {
|
|
98
|
+
authTitle: Titles.MinecraftIOS,
|
|
99
|
+
deviceType: 'iOS',
|
|
100
|
+
flow: 'sisu',
|
|
101
|
+
}),
|
|
102
|
+
// or with a config object instead of an Authflow instance:
|
|
103
|
+
{
|
|
104
|
+
username: 'account2',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Module Behavior Changes
|
|
111
|
+
|
|
112
|
+
Modules that interact with Xbox accounts now automatically use all connected accounts.
|
|
113
|
+
|
|
114
|
+
This affects modules such as:
|
|
115
|
+
|
|
116
|
+
- `AutoFriendAdd`
|
|
117
|
+
- `AutoFriendAccept`
|
|
118
|
+
- `InviteOnMessage`
|
|
119
|
+
|
|
120
|
+
You do not need to add a separate module to make those features work across peer accounts.
|
|
121
|
+
|
|
122
|
+
## Migration Checklist
|
|
123
|
+
|
|
124
|
+
- Rename `authflow` to `host` if your v1 code explicitly set `authflow`
|
|
125
|
+
- Move any `Modules.MultipleAccounts` configuration into `peers`
|
|
126
|
+
- Remove `portal.use(Modules.MultipleAccounts, ...)`
|
package/package.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { Authflow } from 'prismarine-auth';
|
|
2
|
-
import type { BedrockPortal } from '../index';
|
|
3
|
-
import Module from '../classes/Module';
|
|
4
|
-
import Host from '../classes/Host';
|
|
5
|
-
export default class MultipleAccounts extends Module {
|
|
6
|
-
options: {
|
|
7
|
-
/**
|
|
8
|
-
* An array of authflows from prismarine-auth, these accounts are automatically added to the host session and allows players to add them as a friend to join the game
|
|
9
|
-
* @example
|
|
10
|
-
* portal.use(Modules.MultipleAccounts, {
|
|
11
|
-
accounts: [
|
|
12
|
-
new Authflow('account1', './'),
|
|
13
|
-
new Authflow('account2', './')
|
|
14
|
-
],
|
|
15
|
-
})
|
|
16
|
-
*/
|
|
17
|
-
accounts: Authflow[];
|
|
18
|
-
};
|
|
19
|
-
peers: Map<string, Host>;
|
|
20
|
-
constructor(portal: BedrockPortal);
|
|
21
|
-
run(): Promise<void>;
|
|
22
|
-
stop(): Promise<void>;
|
|
23
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const Module_1 = __importDefault(require("../classes/Module"));
|
|
7
|
-
const Host_1 = __importDefault(require("../classes/Host"));
|
|
8
|
-
class MultipleAccounts extends Module_1.default {
|
|
9
|
-
options;
|
|
10
|
-
peers;
|
|
11
|
-
constructor(portal) {
|
|
12
|
-
super(portal, 'multipleAccounts', 'Make the portal session joinable from multiple accounts');
|
|
13
|
-
this.options = {
|
|
14
|
-
accounts: [],
|
|
15
|
-
};
|
|
16
|
-
this.peers = new Map();
|
|
17
|
-
}
|
|
18
|
-
async run() {
|
|
19
|
-
if (!this.portal.host || !this.portal.host.profile) {
|
|
20
|
-
this.debug('No host to connect to');
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
await Promise.all(this.options.accounts.map(account => account.getXboxToken()));
|
|
24
|
-
for (const account of this.options.accounts) {
|
|
25
|
-
const peer = new Host_1.default(this.portal, account);
|
|
26
|
-
await peer.connect();
|
|
27
|
-
if (!peer.profile || !peer.connectionId) {
|
|
28
|
-
this.debug(`Failed to connect to ${account.username}`);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
this.peers.set(peer.profile.xuid, peer);
|
|
32
|
-
this.debug(`Connected ${peer.profile.gamertag}`);
|
|
33
|
-
const hostAddPeer = await this.portal.host.rest.addXboxFriend(peer.profile.xuid)
|
|
34
|
-
.catch(error => ({ error }));
|
|
35
|
-
const peerAddHost = await peer.rest.addXboxFriend(this.portal.host.profile.xuid)
|
|
36
|
-
.catch(error => ({ error }));
|
|
37
|
-
if ((hostAddPeer && 'error' in hostAddPeer) || (peerAddHost && 'error' in peerAddHost)) {
|
|
38
|
-
if (hostAddPeer)
|
|
39
|
-
this.debug(`Failed to add ${peer.profile.gamertag} as a friend - ${hostAddPeer.error.message}`);
|
|
40
|
-
if (peerAddHost)
|
|
41
|
-
this.debug(`Failed to add ${this.portal.host.profile.gamertag} as a friend - ${peerAddHost.error.message}`);
|
|
42
|
-
console.error(`Error creating a friendship between ${this.portal.host.profile.gamertag} and ${peer.profile.gamertag} - BedrockPortal will continue to run, but will not be joinable from ${peer.profile.gamertag}`);
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
await peer.rest.addConnection(this.portal.session.name, peer.profile.xuid, peer.connectionId, peer.subscriptionId);
|
|
46
|
-
await peer.rest.setActivity(this.portal.session.name);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async stop() {
|
|
50
|
-
super.stop();
|
|
51
|
-
for (const peer of this.peers.values()) {
|
|
52
|
-
await peer.disconnect()
|
|
53
|
-
.then(() => this.debug(`Disconnected ${peer.profile?.gamertag}`))
|
|
54
|
-
.catch(() => this.debug(`Failed to disconnect ${peer.profile?.gamertag}`));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.default = MultipleAccounts;
|