|
1 |
| -const http = require('https') |
2 |
| -const fs = require('fs') |
3 |
| -const cp = require('child_process') |
4 |
| -const debug = process.env.CI ? console.debug : require('debug')('minecraft-protocol') |
5 |
| -const https = require('https') |
6 |
| -const { getFiles, waitFor } = require('../src/datatypes/util') |
| 1 | +const bedrockServer = require('minecraft-bedrock-server') |
7 | 2 |
|
8 |
| -function head (url) { |
9 |
| - return new Promise((resolve, reject) => { |
10 |
| - const req = http.request(url, { method: 'HEAD', timeout: 1000 }, resolve) |
11 |
| - req.on('error', reject) |
12 |
| - req.on('timeout', () => { req.destroy(); debug('HEAD request timeout'); reject(new Error('timeout')) }) |
13 |
| - req.end() |
14 |
| - }) |
15 |
| -} |
16 |
| -function get (url, outPath) { |
17 |
| - const file = fs.createWriteStream(outPath) |
18 |
| - return new Promise((resolve, reject) => { |
19 |
| - https.get(url, { timeout: 1000 * 20 }, response => { |
20 |
| - if (response.statusCode !== 200) return reject(new Error('Server returned code ' + response.statusCode)) |
21 |
| - response.pipe(file) |
22 |
| - file.on('finish', () => { |
23 |
| - file.close() |
24 |
| - resolve() |
25 |
| - }) |
26 |
| - }) |
27 |
| - }) |
28 |
| -} |
29 |
| - |
30 |
| -// Get the latest versions |
31 |
| -// TODO: once we support multi-versions |
32 |
| -function fetchLatestStable () { |
33 |
| - get('https://raw.githubusercontent.com/minecraft-linux/mcpelauncher-versiondb/master/versions.json', 'versions.json') |
34 |
| - const versions = JSON.parse(fs.readFileSync('./versions.json')) |
35 |
| - const latest = versions[0] |
36 |
| - return latest.version_name |
37 |
| -} |
38 |
| - |
39 |
| -// Download + extract vanilla server and enter the directory |
40 |
| -async function download (os, version, path = 'bds-') { |
41 |
| - debug('Downloading server', os, version, 'into', path) |
42 |
| - process.chdir(__dirname) |
43 |
| - const verStr = version.split('.').slice(0, 3).join('.') |
44 |
| - const dir = path + version |
45 |
| - |
46 |
| - if (fs.existsSync(dir) && getFiles(dir).length) { |
47 |
| - process.chdir(path + version) // Enter server folder |
48 |
| - return verStr |
| 3 | +module.exports = { |
| 4 | + ...bedrockServer, |
| 5 | + startServerAndWait (version, withTimeout, options) { |
| 6 | + return bedrockServer.startServerAndWait(version, withTimeout, { ...options, root: __dirname }) |
| 7 | + }, |
| 8 | + startServerAndWait2 (version, withTimeout, options) { |
| 9 | + return bedrockServer.startServerAndWait2(version, withTimeout, { ...options, root: __dirname }) |
49 | 10 | }
|
50 |
| - try { fs.mkdirSync(dir) } catch { } |
51 |
| - |
52 |
| - process.chdir(path + version) // Enter server folder |
53 |
| - const url = (os, version) => `https://www.minecraft.net/bedrockdedicatedserver/bin-${os}/bedrock-server-${version}.zip` |
54 |
| - |
55 |
| - let found = false |
56 |
| - |
57 |
| - for (let i = 0; i < 20; i++) { // Check for the latest server build for version (major.minor.patch.BUILD) |
58 |
| - const u = url(os, `${verStr}.${String(i).padStart(2, '0')}`) |
59 |
| - debug('Opening', u, Date.now()) |
60 |
| - let ret |
61 |
| - try { ret = await head(u) } catch (e) { continue } |
62 |
| - if (ret.statusCode === 200) { |
63 |
| - found = u |
64 |
| - debug('Found server', ret.statusCode) |
65 |
| - break |
66 |
| - } |
67 |
| - } |
68 |
| - if (!found) throw Error('did not find server bin for ' + os + ' ' + version) |
69 |
| - console.info('🔻 Downloading', found) |
70 |
| - await get(found, 'bds.zip') |
71 |
| - console.info('⚡ Unzipping') |
72 |
| - // Unzip server |
73 |
| - if (process.platform === 'linux') cp.execSync('unzip -u bds.zip && chmod +777 ./bedrock_server') |
74 |
| - else cp.execSync('tar -xf bds.zip') |
75 |
| - return verStr |
76 |
| -} |
77 |
| - |
78 |
| -const defaultOptions = { |
79 |
| - 'level-generator': '2', |
80 |
| - 'server-port': '19130', |
81 |
| - 'online-mode': 'false' |
82 | 11 | }
|
83 |
| - |
84 |
| -// Setup the server |
85 |
| -function configure (options = {}) { |
86 |
| - const opts = { ...defaultOptions, ...options } |
87 |
| - let config = fs.readFileSync('./server.properties', 'utf-8') |
88 |
| - config += '\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator' |
89 |
| - for (const o in opts) config += `\n${o}=${opts[o]}` |
90 |
| - fs.writeFileSync('./server.properties', config) |
91 |
| -} |
92 |
| - |
93 |
| -function run (inheritStdout = true) { |
94 |
| - const exe = process.platform === 'win32' ? 'bedrock_server.exe' : './bedrock_server' |
95 |
| - return cp.spawn(exe, inheritStdout ? { stdio: 'inherit' } : {}) |
96 |
| -} |
97 |
| - |
98 |
| -let lastHandle |
99 |
| - |
100 |
| -// Run the server |
101 |
| -async function startServer (version, onStart, options = {}) { |
102 |
| - const os = process.platform === 'win32' ? 'win' : process.platform |
103 |
| - if (os !== 'win' && os !== 'linux') { |
104 |
| - throw Error('unsupported os ' + os) |
105 |
| - } |
106 |
| - await download(os, version, options.path) |
107 |
| - configure(options) |
108 |
| - const handle = lastHandle = run(!onStart) |
109 |
| - handle.on('error', (...a) => { |
110 |
| - console.warn('*** THE MINECRAFT PROCESS CRASHED ***', a) |
111 |
| - handle.kill('SIGKILL') |
112 |
| - }) |
113 |
| - if (onStart) { |
114 |
| - let stdout = '' |
115 |
| - handle.stdout.on('data', data => { |
116 |
| - stdout += data |
117 |
| - if (stdout.includes('Server started')) onStart() |
118 |
| - }) |
119 |
| - handle.stdout.pipe(process.stdout) |
120 |
| - handle.stderr.pipe(process.stdout) |
121 |
| - } |
122 |
| - return handle |
123 |
| -} |
124 |
| - |
125 |
| -// Start the server and wait for it to be ready, with a timeout |
126 |
| -async function startServerAndWait (version, withTimeout, options) { |
127 |
| - let handle |
128 |
| - await waitFor(async res => { |
129 |
| - handle = await startServer(version, res, options) |
130 |
| - }, withTimeout, () => { |
131 |
| - handle?.kill() |
132 |
| - throw new Error(`Server did not start on time (${withTimeout}ms, now ${Date.now()})`) |
133 |
| - }) |
134 |
| - return handle |
135 |
| -} |
136 |
| - |
137 |
| -async function startServerAndWait2 (version, withTimeout, options) { |
138 |
| - try { |
139 |
| - return await startServerAndWait(version, 1000 * 60, options) |
140 |
| - } catch (e) { |
141 |
| - console.log(e) |
142 |
| - console.log('^ Tring once more to start server in 10 seconds...') |
143 |
| - lastHandle?.kill() |
144 |
| - await new Promise(resolve => setTimeout(resolve, 10000)) |
145 |
| - process.chdir(__dirname) |
146 |
| - fs.rmSync('bds-' + version, { recursive: true }) |
147 |
| - return await startServerAndWait(version, withTimeout, options) |
148 |
| - } |
149 |
| -} |
150 |
| - |
151 |
| -if (!module.parent) { |
152 |
| - // if (process.argv.length < 3) throw Error('Missing version argument') |
153 |
| - startServer(process.argv[2] || '1.17.10', null, process.argv[3] ? { 'server-port': process.argv[3], 'online-mode': !!process.argv[4] } : undefined) |
154 |
| -} |
155 |
| - |
156 |
| -module.exports = { fetchLatestStable, startServer, startServerAndWait, startServerAndWait2 } |
0 commit comments