Implement Realm joining (#193)
* Pass client options to ping * Implement RealmAPI to auth * Add Realm join example * Update package.json * Update README.md * Update index.d.ts * Show one option, remove listener * Fix wording * Explain options * Optional fields * Fix typo * Moved retry ad host/port extraction to prealms * Add docs * Fix lint * Depend on prealms release Co-authored-by: LucienHH <Lucien.holloway@aprox.co.uk>
This commit is contained in:
parent
dfff13867d
commit
cde600d51e
7 changed files with 88 additions and 3 deletions
13
README.md
13
README.md
|
|
@ -59,6 +59,19 @@ client.on('text', (packet) => { // Listen for chat messages and echo them back.
|
|||
})
|
||||
```
|
||||
|
||||
### Client example joining a Realm
|
||||
|
||||
Example to connect to a Realm that the authenticating account is owner of or has been invited to:
|
||||
|
||||
```js
|
||||
const bedrock = require('bedrock-protocol')
|
||||
const client = bedrock.createClient({
|
||||
realms: {
|
||||
pickRealm: (realms) => realms[0] // Function which recieves an array of joined/owned Realms and must return a single Realm. Can be async
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Server example
|
||||
|
||||
*Can't connect locally on Windows? See the [faq](docs/FAQ.md)*
|
||||
|
|
|
|||
22
docs/API.md
22
docs/API.md
|
|
@ -8,7 +8,7 @@ Returns a `Client` instance and connects to the server.
|
|||
|
||||
| Parameter | Optionality | Description |
|
||||
| ----------- | ----------- |-|
|
||||
| host | **Required** | host to connect to, for example `127.0.0.1`. |
|
||||
| host | Conditional | Not required if `realms` is set. host to connect to, for example `127.0.0.1`. |
|
||||
| port | *optional* | port to connect to, default to **19132** |
|
||||
| version | *optional* | Version to connect as. If not specified, automatically match server version. |
|
||||
| offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. |
|
||||
|
|
@ -22,6 +22,10 @@ Returns a `Client` instance and connects to the server.
|
|||
| useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. |
|
||||
| compressionLevel | *optional* | What zlib compression level to use, default to **7** |
|
||||
| batchingInterval | *optional* | How frequently, in milliseconds to flush and write the packet queue (default: 20ms) |
|
||||
| realms | *optional* | An object which should contain one of the following properties: `realmId`, `realmInvite`, `pickRealm`. When defined will attempt to join a Realm without needing to specify host/port. **The authenticated account must either own the Realm or have been invited to it** |
|
||||
| realms.realmId | *optional* | The id of the Realm to join. |
|
||||
| realms.realmInvite | *optional* | The invite link/code of the Realm to join. |
|
||||
| realms.pickRealm | *optional* | A function which will have an array of the user Realms (joined/owned) passed to it. The function should return a Realm. |
|
||||
|
||||
The following events are emitted by the client:
|
||||
* 'status' - When the client's login sequence status has changed
|
||||
|
|
@ -134,6 +138,22 @@ Order of client event emissions:
|
|||
* 'join' - the client is ready to recieve game packets after successful server-client handshake
|
||||
* 'spawn' - emitted after the client has permission from the server to spawn
|
||||
|
||||
### Realm docs
|
||||
|
||||
To make joining a Realm easier we've added an optional `realm` property to the client. It accepts the following options `realmId`, `realmInvite`, and `pickRealm`, supplying one of these will fetch host/port information for the specified Realm and then attempt to connect the bot.
|
||||
- `realmId` - The id of the Realm to join.
|
||||
- `realmInvite` - The invite code/link of the Realm to join.
|
||||
- `pickRealm` - A function that will be called with a list of Realms to pick from. The function should return the Realm to join.
|
||||
|
||||
```js
|
||||
const bedrock = require('bedrock-protocol')
|
||||
const client = bedrock.createClient({
|
||||
realms: {
|
||||
pickRealm: (realms) => realms[0] // Function which recieves an array of joined/owned Realms and must return a single Realm. Can be async
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Protocol docs
|
||||
|
||||
For documentation on the protocol, and packets/fields see the [the protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.18.0&d=protocol) (the emitted event names are the Packet types in lower case without the "packet_" prefix). More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields.
|
||||
|
|
|
|||
13
examples/client/realm.js
Normal file
13
examples/client/realm.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* eslint-disable */
|
||||
const bedrock = require('bedrock-protocol')
|
||||
const client = bedrock.createClient({
|
||||
realms: {
|
||||
// realmId: '1234567', // Connect the client to a Realm using the Realms ID
|
||||
// realmInvite: 'https://realms.gg/AB1CD2EFA3B', // Connect the client to a Realm using the Realms invite URL or code
|
||||
pickRealm: (realms) => realms.find(e => e.name === 'Realm Name') // Connect the client to a Realm using a function that returns a Realm
|
||||
}
|
||||
})
|
||||
|
||||
client.on('text', (packet) => { // Listen for chat messages
|
||||
console.log('Received Text:', packet)
|
||||
})
|
||||
9
index.d.ts
vendored
9
index.d.ts
vendored
|
|
@ -1,4 +1,5 @@
|
|||
import EventEmitter from "events"
|
||||
import { Realm } from "prismarine-realms"
|
||||
|
||||
declare module "bedrock-protocol" {
|
||||
type Version = '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201'
|
||||
|
|
@ -40,6 +41,8 @@ declare module "bedrock-protocol" {
|
|||
skipPing?: boolean
|
||||
// where to log connection information to (default to console.log)
|
||||
conLog?
|
||||
// used to join a Realm instead of supplying a host/port
|
||||
realms?: RealmsOptions
|
||||
}
|
||||
|
||||
export interface ServerOptions extends Options {
|
||||
|
|
@ -174,6 +177,12 @@ declare module "bedrock-protocol" {
|
|||
serverId: string
|
||||
}
|
||||
|
||||
export interface RealmsOptions {
|
||||
realmId?: string
|
||||
realmInvite?: string
|
||||
pickRealm?: (realms: Realm[]) => Realm
|
||||
}
|
||||
|
||||
export function createClient(options: ClientOptions): Client
|
||||
export function createServer(options: ServerOptions): Server
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
"minecraft-folder-path": "^1.2.0",
|
||||
"prismarine-auth": "^1.1.0",
|
||||
"prismarine-nbt": "^2.0.0",
|
||||
"prismarine-realms": "^1.1.0",
|
||||
"protodef": "^1.14.0",
|
||||
"uuid-1345": "^1.0.2",
|
||||
"raknet-native": "^1.0.3"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ const { Authflow: PrismarineAuth, Titles } = require('prismarine-auth')
|
|||
const minecraftFolderPath = require('minecraft-folder-path')
|
||||
const debug = require('debug')('minecraft-protocol')
|
||||
const { uuidFrom } = require('../datatypes/util')
|
||||
const { RealmAPI } = require('prismarine-realms')
|
||||
|
||||
function validateOptions (options) {
|
||||
if (!options.profilesFolder) {
|
||||
|
|
@ -16,7 +17,35 @@ function validateOptions (options) {
|
|||
|
||||
async function realmAuthenticate (options) {
|
||||
validateOptions(options)
|
||||
throw new Error('Not implemented')
|
||||
|
||||
options.authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode)
|
||||
|
||||
const api = RealmAPI.from(options.authflow, 'bedrock')
|
||||
const realms = await api.getRealms()
|
||||
|
||||
debug('realms', realms)
|
||||
|
||||
if (!realms || !realms.length) throw Error('Couldn\'t find any Realms for the authenticated account')
|
||||
|
||||
let realm
|
||||
|
||||
if (options.realms.realmId) {
|
||||
realm = realms.find(e => e.id === Number(options.realms.realmId))
|
||||
} else if (options.realms.realmInvite) {
|
||||
realm = await api.getRealmFromInvite(options.realms.realmInvite)
|
||||
} else if (options.realms.pickRealm) {
|
||||
if (typeof options.realms.pickRealm !== 'function') throw Error('realms.pickRealm must be a function')
|
||||
realm = await options.realms.pickRealm(realms)
|
||||
}
|
||||
|
||||
if (!realm) throw Error('Couldn\'t find a Realm to connect to. Authenticated account must be the owner or has been invited to the Realm.')
|
||||
|
||||
const { host, port } = await realm.getAddress()
|
||||
|
||||
debug('realms connection', { host, port })
|
||||
|
||||
options.host = host
|
||||
options.port = port
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function createClient (options) {
|
|||
if (options.skipPing) {
|
||||
client.init()
|
||||
} else {
|
||||
ping(options).then(ad => {
|
||||
ping(client.options).then(ad => {
|
||||
const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units
|
||||
client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION)
|
||||
client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue