Monorepo project #508
@ -1,11 +0,0 @@
|
|||||||
FROM ghcr.io/sirherobrine23/initjs:latest
|
|
||||||
# Install dependecies to Bedrock server
|
|
||||||
RUN (apt update && apt install -y libssl1.1 || (echo "deb http://security.ubuntu.com/ubuntu focal-security main" | tee /etc/apt/sources.list.d/focal-security.list && apt update && apt install -y libssl1.1)) || echo exit $?
|
|
||||||
|
|
||||||
# Add non root user and Install oh my zsh
|
|
||||||
ARG USERNAME="devcontainer"
|
|
||||||
ARG USER_UID="1000"
|
|
||||||
ARG USER_GID=$USER_UID
|
|
||||||
RUN initjs create-user --username "${USERNAME}" --uid "${USER_UID}" --gid "${USER_GID}" --groups sudo --groups docker
|
|
||||||
USER $USERNAME
|
|
||||||
WORKDIR /home/$USERNAME
|
|
@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Bds Maneger Core",
|
|
||||||
"updateRemoteUserUID": false,
|
|
||||||
"containerUser": "develop",
|
|
||||||
"remoteUser": "develop",
|
|
||||||
"overrideCommand": false,
|
|
||||||
"postCreateCommand": "npm install",
|
|
||||||
"build": {
|
|
||||||
"dockerfile": "Dockerfile",
|
|
||||||
"args": {
|
|
||||||
"USERNAME": "develop",
|
|
||||||
"USER_UID": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"runArgs": [
|
|
||||||
"--init",
|
|
||||||
"--privileged"
|
|
||||||
],
|
|
||||||
"mounts": [
|
|
||||||
"target=/var/lib/docker,type=volume,source=bdsmanegercore"
|
|
||||||
],
|
|
||||||
"extensions": [
|
|
||||||
"benshabatnoam.google-translate-ext",
|
|
||||||
"eamodio.gitlens",
|
|
||||||
"github.vscode-pull-request-github",
|
|
||||||
"visualstudioexptteam.vscodeintellicode",
|
|
||||||
"redhat.vscode-yaml",
|
|
||||||
"ms-vscode-remote.remote-containers",
|
|
||||||
"wix.vscode-import-cost",
|
|
||||||
"eg2.vscode-npm-script",
|
|
||||||
"christian-kohler.npm-intellisense",
|
|
||||||
"christian-kohler.path-intellisense",
|
|
||||||
"aaron-bond.better-comments",
|
|
||||||
"vscode-icons-team.vscode-icons",
|
|
||||||
"me-dutour-mathieu.vscode-github-actions",
|
|
||||||
"cschleiden.vscode-github-actions",
|
|
||||||
"oderwat.indent-rainbow",
|
|
||||||
"ms-azuretools.vscode-docker",
|
|
||||||
"formulahendry.code-runner",
|
|
||||||
"chrmarti.regex"
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"editor.tabSize": 2,
|
|
||||||
"editor.minimap.enabled": false,
|
|
||||||
"files.eol": "\n",
|
|
||||||
"files.trimFinalNewlines": true,
|
|
||||||
"files.trimTrailingWhitespace": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,4 +10,4 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: monthly
|
interval: monthly
|
||||||
assignees:
|
assignees:
|
||||||
- Sirherobrine23
|
- Sirherobrine23
|
29
.github/spigotBuilld/index.mjs
vendored
29
.github/spigotBuilld/index.mjs
vendored
@ -1,29 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
import { createReadStream, promises as fs } from "node:fs";
|
|
||||||
import { Cloud, Extends } from "@sirherobrine23/coreutils";
|
|
||||||
import path from "path";
|
|
||||||
const { tenancy, fingerprint, privateKey, user, passphase } = process.env;
|
|
||||||
const oracleBucket = await Cloud.oracleBucket({
|
|
||||||
region: "sa-saopaulo-1",
|
|
||||||
name: "bdsFiles",
|
|
||||||
namespace: "grwodtg32n4d",
|
|
||||||
auth: {
|
|
||||||
type: "user",
|
|
||||||
tenancy,
|
|
||||||
fingerprint,
|
|
||||||
privateKey,
|
|
||||||
user,
|
|
||||||
passphase
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const __dirname = path.resolve(process.cwd(), process.argv.slice(2)[0]||"");
|
|
||||||
|
|
||||||
await Extends.extendsFS.readdir({folderPath: __dirname}).then(files => files.filter(file => file.endsWith(".jar"))).then(async files => {
|
|
||||||
for (const file of files) {
|
|
||||||
const version = path.basename(file, ".jar").split("-")[1];
|
|
||||||
if (!version) continue;
|
|
||||||
console.log("Uploading %s, file: %O", version, "SpigotBuild/"+version+".jar");
|
|
||||||
await oracleBucket.uploadFile("SpigotBuild/"+version+".jar", createReadStream(file)).then(() => console.log("Uploaded %s", version));
|
|
||||||
await fs.unlink(file);
|
|
||||||
}
|
|
||||||
});
|
|
23
.github/uploadToBucket.mjs
vendored
Normal file
23
.github/uploadToBucket.mjs
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { createReadStream } from "fs";
|
||||||
|
import { oracleBucket } from "@sirherobrine23/cloud";
|
||||||
|
import extendsFS from "@sirherobrine23/extends";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
const [,, remote, local] = process.argv;
|
||||||
|
const bucket = await oracleBucket.oracleBucket({
|
||||||
|
region: "sa-saopaulo-1",
|
||||||
|
namespace: "grwodtg32n4d",
|
||||||
|
name: "bdsFiles",
|
||||||
|
auth: {
|
||||||
|
type: "preAuthentication",
|
||||||
|
// Public auth (No write enabled).
|
||||||
|
PreAuthenticatedKey: process.env.OCI_AUTHKEY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for await (const file of await extendsFS.readdir(path.resolve(process.cwd(), local))) {
|
||||||
|
console.log("Uploading %O", file);
|
||||||
|
await bucket.uploadFile(path.posix.resolve("/", remote ?? "", path.basename(file)), createReadStream(file));
|
||||||
|
console.log("Success %O", file);
|
||||||
|
}
|
24
.github/uploadphp/index.mjs
vendored
24
.github/uploadphp/index.mjs
vendored
@ -1,24 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
import { createReadStream } from "node:fs";
|
|
||||||
import coreutils, { extendFs } from "@sirherobrine23/coreutils";
|
|
||||||
import path from "node:path";
|
|
||||||
import fs from "node:fs/promises";
|
|
||||||
if (!process.env.OCI_AUTHKEY) throw new Error("No key auth");
|
|
||||||
const ociKeyAuth = (process.env.OCI_AUTHKEY||"").trim();
|
|
||||||
console.log("using key to upload '%s'", ociKeyAuth);
|
|
||||||
|
|
||||||
const files = (await extendFs.readdir({folderPath: path.join(process.cwd(), "phpOutput")})).filter(file => file.endsWith(".tar.gz")||file.endsWith(".zip")||file.endsWith(".tgz"));
|
|
||||||
await Promise.all(files.map(async file => {
|
|
||||||
const fileName = path.basename(file);
|
|
||||||
console.log("Uploading %s", fileName);
|
|
||||||
await coreutils.httpRequest.bufferFetch({
|
|
||||||
url: `https://objectstorage.sa-saopaulo-1.oraclecloud.com/p/${ociKeyAuth}/n/grwodtg32n4d/b/bdsFiles/o/php_bin/${encodeURIComponent(fileName.toLowerCase())}`,
|
|
||||||
method: "PUT",
|
|
||||||
body: createReadStream(file),
|
|
||||||
headers: {
|
|
||||||
"Content-Length": (await fs.lstat(file)).size.toString(),
|
|
||||||
"Content-Type": "application/octet-stream"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log("Upload success to %s", fileName);
|
|
||||||
}));
|
|
43
.github/workflows/code_analyzer.yml
vendored
43
.github/workflows/code_analyzer.yml
vendored
@ -1,43 +0,0 @@
|
|||||||
name: Code Analyze
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
schedule:
|
|
||||||
- cron: "26 8 * * 1"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
snyk:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@master
|
|
||||||
- name: Run Snyk to check for vulnerabilities
|
|
||||||
uses: snyk/actions/node@master
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
||||||
with:
|
|
||||||
args: --sarif-file-output=snyk.sarif
|
|
||||||
- name: Upload result to GitHub Code Scanning
|
|
||||||
continue-on-error: true
|
|
||||||
uses: github/codeql-action/upload-sarif@v2
|
|
||||||
with:
|
|
||||||
sarif_file: snyk.sarif
|
|
||||||
|
|
||||||
codeql:
|
|
||||||
name: CodeQL Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
languages: javascript
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v2
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
43
.github/workflows/gendocs.yaml
vendored
43
.github/workflows/gendocs.yaml
vendored
@ -1,43 +0,0 @@
|
|||||||
name: Deploy bds core wiki
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "src/**/*"
|
|
||||||
- "tests/**/*"
|
|
||||||
- "package*.json"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pages: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy_doc:
|
|
||||||
environment:
|
|
||||||
name: github-pages
|
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3.6.0
|
|
||||||
name: Setup node.js
|
|
||||||
with:
|
|
||||||
node-version: latest
|
|
||||||
|
|
||||||
- run: npm ci
|
|
||||||
|
|
||||||
- name: Gen docs
|
|
||||||
run: npm run docs
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-pages-artifact@v1
|
|
||||||
with:
|
|
||||||
path: "docs"
|
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
|
||||||
id: deployment
|
|
||||||
uses: actions/deploy-pages@v1
|
|
@ -215,7 +215,7 @@ jobs:
|
|||||||
path: ./phpOutput
|
path: ./phpOutput
|
||||||
|
|
||||||
- name: Upload to bucket
|
- name: Upload to bucket
|
||||||
run: node .github/uploadphp/index.mjs
|
run: node .github/uploadphp/index.mjs php_bin phpOutput
|
||||||
timeout-minutes: 25
|
timeout-minutes: 25
|
||||||
env:
|
env:
|
||||||
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
69
.github/workflows/publish.yml
vendored
69
.github/workflows/publish.yml
vendored
@ -1,69 +0,0 @@
|
|||||||
name: Publish package
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- prereleased
|
|
||||||
- released
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publishpackage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Publish
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
name: Code checkout
|
|
||||||
with:
|
|
||||||
persist-credentials: true
|
|
||||||
ref: main
|
|
||||||
fetch-depth: 2
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
# Install basic tools
|
|
||||||
- uses: actions/setup-node@v3.6.0
|
|
||||||
name: Setup node.js
|
|
||||||
with:
|
|
||||||
registry-url: https://registry.npmjs.org/
|
|
||||||
node-version: latest
|
|
||||||
|
|
||||||
- name: Edit version
|
|
||||||
shell: node {0}
|
|
||||||
run: |
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const packagePath = path.join(process.cwd(), "package.json");
|
|
||||||
const package = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
||||||
package.version = "${{ github.ref }}";
|
|
||||||
package.version = package.version.replace(/[A-Za-z_\/]+/, "");
|
|
||||||
fs.writeFileSync(packagePath, JSON.stringify(package, null, 2));
|
|
||||||
|
|
||||||
# Install depencides and build
|
|
||||||
- run: npm ci && npm run build
|
|
||||||
|
|
||||||
# Publish
|
|
||||||
- run: npm publish --tag ${{ github.event.release.prerelease && 'next' || 'latest' }}
|
|
||||||
name: Publish to npm
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_ORG_TOKEN }}
|
|
||||||
|
|
||||||
# Add version to environment variables
|
|
||||||
- name: Add version to environment variables
|
|
||||||
run: |
|
|
||||||
cat package.json | jq -r '.version' > /tmp/version.txt
|
|
||||||
echo "PACKAGE_VERSION=$(cat /tmp/version.txt)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# Create pull request to update version in main branch
|
|
||||||
- uses: peter-evans/create-pull-request@v4
|
|
||||||
name: Create Pull Request
|
|
||||||
continue-on-error: true
|
|
||||||
with:
|
|
||||||
commit-message: Update version v${{ env.PACKAGE_VERSION }}
|
|
||||||
delete-branch: true
|
|
||||||
assignees: SirHerobrine23
|
|
||||||
reviewers: SirHerobrine23
|
|
||||||
branch: update-version
|
|
||||||
title: Update package version v${{ env.PACKAGE_VERSION }}
|
|
||||||
body: Auto update package version, created with GitHub Actions
|
|
8
.github/workflows/spigotBuild.yaml
vendored
8
.github/workflows/spigotBuild.yaml
vendored
@ -107,10 +107,6 @@ jobs:
|
|||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Upload to actifial
|
- name: Upload to actifial
|
||||||
run: node .github/spigotBuilld/index.mjs artifacts
|
run: node .github/uploadToBucket.ts SpigotBuild artifacts
|
||||||
env:
|
env:
|
||||||
tenancy: ${{ secrets.OCI_TENANCY }}
|
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
||||||
fingerprint: ${{ secrets.OCI_FING }}
|
|
||||||
privateKey: ${{ secrets.OCI_PRIV }}
|
|
||||||
user: ${{ secrets.OCI_USER }}
|
|
||||||
passphase: ${{ secrets.OCI_PASSPHASE || '' }}
|
|
@ -1,23 +1,13 @@
|
|||||||
|
|
||||||
name: Test
|
name: Test
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "src/**/*"
|
|
||||||
- "tests/**/*"
|
|
||||||
- "package*.json"
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: "Test"
|
name: "Test"
|
||||||
env:
|
env:
|
||||||
BDS_HOME: "~/.bdsCore"
|
bdscoreroot: "~/.bdsCore"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
name: Code checkout
|
name: Code checkout
|
||||||
@ -36,8 +26,8 @@ jobs:
|
|||||||
|
|
||||||
# Install dependecies
|
# Install dependecies
|
||||||
- name: Install nodejs dependencies
|
- name: Install nodejs dependencies
|
||||||
run: npm ci
|
run: npm install --no-save
|
||||||
|
|
||||||
# Run test
|
# Build Core
|
||||||
- name: Test
|
- name: Core Build
|
||||||
run: npm run test
|
run: cd package/core && npm run build
|
20
.gitignore
vendored
20
.gitignore
vendored
@ -1,17 +1,9 @@
|
|||||||
/*.log
|
# Node
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
|
||||||
src/**/*.d.ts
|
|
||||||
src/**/*.d.js
|
|
||||||
src/**/*.js
|
|
||||||
docs/
|
|
||||||
|
|
||||||
# PHP Bins
|
# Typescript
|
||||||
muslCrossMake/
|
packages/**/*.js
|
||||||
phpOutput/
|
packages/**/*.d.ts
|
||||||
*.tar.gz
|
|
||||||
*.tgz
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# Spigot
|
# PHP Pre builds
|
||||||
*.jar
|
phpOutput/
|
19
.gitpod.yml
19
.gitpod.yml
@ -1,19 +0,0 @@
|
|||||||
image:
|
|
||||||
file: .devcontainer/Dockerfile
|
|
||||||
tasks:
|
|
||||||
- init: npm install
|
|
||||||
vscode:
|
|
||||||
extensions:
|
|
||||||
- formulahendry.code-runner
|
|
||||||
- github.vscode-pull-request-github
|
|
||||||
- redhat.vscode-yaml
|
|
||||||
- eamodio.gitlens
|
|
||||||
- wix.vscode-import-cost
|
|
||||||
- eg2.vscode-npm-script
|
|
||||||
- christian-kohler.npm-intellisense
|
|
||||||
- christian-kohler.path-intellisense
|
|
||||||
- aaron-bond.better-comments
|
|
||||||
- vscode-icons-team.vscode-icons
|
|
||||||
- cschleiden.vscode-github-actions
|
|
||||||
- oderwat.indent-rainbow
|
|
||||||
- ms-azuretools.vscode-docker
|
|
8
.hintrc
8
.hintrc
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"development"
|
|
||||||
],
|
|
||||||
"hints": {
|
|
||||||
"typescript-config/strict": "off"
|
|
||||||
}
|
|
||||||
}
|
|
11
.mocharc.yml
11
.mocharc.yml
@ -1,11 +0,0 @@
|
|||||||
exit: true
|
|
||||||
colors: true
|
|
||||||
full-trace: true
|
|
||||||
recursive: true
|
|
||||||
parallel: true
|
|
||||||
timeout: 0
|
|
||||||
node-option:
|
|
||||||
- "experimental-specifier-resolution=node"
|
|
||||||
- "loader=ts-node/esm"
|
|
||||||
extension:
|
|
||||||
- "test.ts"
|
|
@ -1,2 +0,0 @@
|
|||||||
!dist/
|
|
||||||
backup_*.zip
|
|
22
.vscode/extensions.json
vendored
22
.vscode/extensions.json
vendored
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"formulahendry.code-runner",
|
|
||||||
"chrmarti.regex",
|
|
||||||
"benshabatnoam.google-translate-ext",
|
|
||||||
"eamodio.gitlens",
|
|
||||||
"github.vscode-pull-request-github",
|
|
||||||
"visualstudioexptteam.vscodeintellicode",
|
|
||||||
"redhat.vscode-yaml",
|
|
||||||
"ms-vscode-remote.remote-containers",
|
|
||||||
"wix.vscode-import-cost",
|
|
||||||
"eg2.vscode-npm-script",
|
|
||||||
"christian-kohler.npm-intellisense",
|
|
||||||
"christian-kohler.path-intellisense",
|
|
||||||
"aaron-bond.better-comments",
|
|
||||||
"vscode-icons-team.vscode-icons",
|
|
||||||
"me-dutour-mathieu.vscode-github-actions",
|
|
||||||
"cschleiden.vscode-github-actions",
|
|
||||||
"oderwat.indent-rainbow",
|
|
||||||
"ms-azuretools.vscode-docker"
|
|
||||||
]
|
|
||||||
}
|
|
34
.vscode/launch.json
vendored
34
.vscode/launch.json
vendored
@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"name": "Current file",
|
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
|
||||||
"request": "launch",
|
|
||||||
"env": {
|
|
||||||
"BDSD_IGNORE_KEY": "1",
|
|
||||||
"PORT": "3000"
|
|
||||||
},
|
|
||||||
"args": [
|
|
||||||
"-r", "ts-node/register",
|
|
||||||
"${file}"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"name": "Mocha Tests",
|
|
||||||
"program": "${workspaceFolder}/node_modules/mocha/bin/mocha.js",
|
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
|
||||||
"request": "launch",
|
|
||||||
"skipFiles": [
|
|
||||||
"<node_internals>/**"
|
|
||||||
],
|
|
||||||
"args": [
|
|
||||||
"-r", "ts-node/register",
|
|
||||||
"--colors",
|
|
||||||
"${workspaceFolder}/tests/**/*.ts"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -8,9 +8,7 @@
|
|||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"**/node_modules/": true,
|
"**/node_modules/": true,
|
||||||
// Ignore generate tsc files
|
"**/src/**/*.js": true,
|
||||||
"**/dist/": true,
|
"**/src/**/*.d.ts": true,
|
||||||
"**/src/**/*.js": false,
|
|
||||||
"**/src/**/*.d.ts": false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,128 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We as members, contributors, and leaders pledge to make participation in our
|
|
||||||
community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
||||||
identity and expression, level of experience, education, socio-economic status,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity
|
|
||||||
and orientation.
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
||||||
diverse, inclusive, and healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our
|
|
||||||
community include:
|
|
||||||
|
|
||||||
* Demonstrating empathy and kindness toward other people
|
|
||||||
* Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
* Giving and gracefully accepting constructive feedback
|
|
||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
||||||
and learning from the experience
|
|
||||||
* Focusing on what is best not just for us as individuals, but for the
|
|
||||||
overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery, and sexual attention or
|
|
||||||
advances of any kind
|
|
||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or email
|
|
||||||
address, without their explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Community leaders are responsible for clarifying and enforcing our standards of
|
|
||||||
acceptable behavior and will take appropriate and fair corrective action in
|
|
||||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
||||||
or harmful.
|
|
||||||
|
|
||||||
Community leaders have the right and responsibility to remove, edit, or reject
|
|
||||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
||||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
||||||
decisions when appropriate.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies within all community spaces, and also applies when
|
|
||||||
an individual is officially representing the community in public spaces.
|
|
||||||
Examples of representing our community include using an official e-mail address,
|
|
||||||
posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported to the community leaders responsible for enforcement at
|
|
||||||
Email or Github issues.
|
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
|
||||||
reporter of any incident.
|
|
||||||
|
|
||||||
## Enforcement Guidelines
|
|
||||||
|
|
||||||
Community leaders will follow these Community Impact Guidelines in determining
|
|
||||||
the consequences for any action they deem in violation of this Code of Conduct:
|
|
||||||
|
|
||||||
### 1. Correction
|
|
||||||
|
|
||||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
||||||
unprofessional or unwelcome in the community.
|
|
||||||
|
|
||||||
**Consequence**: A private, written warning from community leaders, providing
|
|
||||||
clarity around the nature of the violation and an explanation of why the
|
|
||||||
behavior was inappropriate. A public apology may be requested.
|
|
||||||
|
|
||||||
### 2. Warning
|
|
||||||
|
|
||||||
**Community Impact**: A violation through a single incident or series
|
|
||||||
of actions.
|
|
||||||
|
|
||||||
**Consequence**: A warning with consequences for continued behavior. No
|
|
||||||
interaction with the people involved, including unsolicited interaction with
|
|
||||||
those enforcing the Code of Conduct, for a specified period of time. This
|
|
||||||
includes avoiding interactions in community spaces as well as external channels
|
|
||||||
like social media. Violating these terms may lead to a temporary or
|
|
||||||
permanent ban.
|
|
||||||
|
|
||||||
### 3. Temporary Ban
|
|
||||||
|
|
||||||
**Community Impact**: A serious violation of community standards, including
|
|
||||||
sustained inappropriate behavior.
|
|
||||||
|
|
||||||
**Consequence**: A temporary ban from any sort of interaction or public
|
|
||||||
communication with the community for a specified period of time. No public or
|
|
||||||
private interaction with the people involved, including unsolicited interaction
|
|
||||||
with those enforcing the Code of Conduct, is allowed during this period.
|
|
||||||
Violating these terms may lead to a permanent ban.
|
|
||||||
|
|
||||||
### 4. Permanent Ban
|
|
||||||
|
|
||||||
**Community Impact**: Demonstrating a pattern of violation of community
|
|
||||||
standards, including sustained inappropriate behavior, harassment of an
|
|
||||||
individual, or aggression toward or disparagement of classes of individuals.
|
|
||||||
|
|
||||||
**Consequence**: A permanent ban from any sort of public interaction within
|
|
||||||
the community.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
||||||
version 2.0, available at
|
|
||||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
||||||
|
|
||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
||||||
enforcement ladder](https://github.com/mozilla/diversity).
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at
|
|
||||||
https://www.contributor-covenant.org/translations.
|
|
@ -1,8 +0,0 @@
|
|||||||
# Contributing to the core
|
|
||||||
|
|
||||||
We hope to have multiple platforms supported by the project, as I want to bring together multiple servers to be managed in one place.
|
|
||||||
|
|
||||||
Any new platform will have to fork the repository or open an issue to request the new platform.
|
|
||||||
|
|
||||||
1. not all servers can be added because of project licensing but we can talk to the maintainers if needed.
|
|
||||||
2. This project is designed to run on various operating systems such as Android, Linux, Windows and MacOS (other systems can be added to be supported).
|
|
5
LICENSE
5
LICENSE
@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
|||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) 2023 Matheus Sampaio Queiroga
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
<program> Copyright (C) 2023 Matheus Sampaio Queiroga
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
@ -672,4 +672,3 @@ may consider it more useful to permit linking proprietary applications with
|
|||||||
the library. If this is what you want to do, use the GNU Lesser General
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
Public License instead of this License. But first, please read
|
Public License instead of this License. But first, please read
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
|
|
||||||
|
12
README.md
12
README.md
@ -1,12 +0,0 @@
|
|||||||
# Bds Maneger Core
|
|
||||||
|
|
||||||
A quick way to install, update and start your Minecraft Java and Bedrock server.
|
|
||||||
|
|
||||||
## Current Bds core support servers
|
|
||||||
|
|
||||||
1. `Bedrock` (Mojang)
|
|
||||||
2. `Java` (Mojang)
|
|
||||||
3. `Pocketmine` (PMMP - Minecraft bedrock server writed in PHP)
|
|
||||||
4. `Spigot` (Spigot-MC is Minecraft java server to add plugins and more to server)
|
|
||||||
5. `Powernukkit` (Minecraft Bedrock Server in java)
|
|
||||||
6. `Paper` (PaperMC is Minecraft java server with plugins and mods)
|
|
@ -1,135 +0,0 @@
|
|||||||
server-name=Dedicated Server
|
|
||||||
# Used as the server name
|
|
||||||
# Allowed values: Any string without semicolon symbol.
|
|
||||||
|
|
||||||
gamemode=survival
|
|
||||||
# Sets the game mode for new players.
|
|
||||||
# Allowed values: "survival", "creative", or "adventure"
|
|
||||||
|
|
||||||
force-gamemode=false
|
|
||||||
# force-gamemode=false (or force-gamemode is not defined in the server.properties)
|
|
||||||
# prevents the server from sending to the client gamemode values other
|
|
||||||
# than the gamemode value saved by the server during world creation
|
|
||||||
# even if those values are set in server.properties after world creation.
|
|
||||||
#
|
|
||||||
# force-gamemode=true forces the server to send to the client gamemode values
|
|
||||||
# other than the gamemode value saved by the server during world creation
|
|
||||||
# if those values are set in server.properties after world creation.
|
|
||||||
|
|
||||||
difficulty=easy
|
|
||||||
# Sets the difficulty of the world.
|
|
||||||
# Allowed values: "peaceful", "easy", "normal", or "hard"
|
|
||||||
|
|
||||||
allow-cheats=false
|
|
||||||
# If true then cheats like commands can be used.
|
|
||||||
# Allowed values: "true" or "false"
|
|
||||||
|
|
||||||
max-players=10
|
|
||||||
# The maximum number of players that can play on the server.
|
|
||||||
# Allowed values: Any positive integer
|
|
||||||
|
|
||||||
online-mode=true
|
|
||||||
# If true then all connected players must be authenticated to Xbox Live.
|
|
||||||
# Clients connecting to remote (non-LAN) servers will always require Xbox Live authentication regardless of this setting.
|
|
||||||
# If the server accepts connections from the Internet, then it's highly recommended to enable online-mode.
|
|
||||||
# Allowed values: "true" or "false"
|
|
||||||
|
|
||||||
allow-list=false
|
|
||||||
# If true then all connected players must be listed in the separate allowlist.json file.
|
|
||||||
# Allowed values: "true" or "false"
|
|
||||||
|
|
||||||
server-port=34215
|
|
||||||
# Which IPv4 port the server should listen to.
|
|
||||||
# Allowed values: Integers in the range [1, 65535]
|
|
||||||
|
|
||||||
server-portv6=33657
|
|
||||||
# Which IPv6 port the server should listen to.
|
|
||||||
# Allowed values: Integers in the range [1, 65535]
|
|
||||||
|
|
||||||
view-distance=32
|
|
||||||
# The maximum allowed view distance in number of chunks.
|
|
||||||
# Allowed values: Positive integer equal to 5 or greater.
|
|
||||||
|
|
||||||
tick-distance=4
|
|
||||||
# The world will be ticked this many chunks away from any player.
|
|
||||||
# Allowed values: Integers in the range [4, 12]
|
|
||||||
|
|
||||||
player-idle-timeout=30
|
|
||||||
# After a player has idled for this many minutes they will be kicked. If set to 0 then players can idle indefinitely.
|
|
||||||
# Allowed values: Any non-negative integer.
|
|
||||||
|
|
||||||
max-threads=8
|
|
||||||
# Maximum number of threads the server will try to use. If set to 0 or removed then it will use as many as possible.
|
|
||||||
# Allowed values: Any positive integer.
|
|
||||||
|
|
||||||
level-name=Bedrock level
|
|
||||||
# Allowed values: Any string without semicolon symbol or symbols illegal for file name: /\n\r\t\f`?*\\<>|\":
|
|
||||||
|
|
||||||
level-seed=
|
|
||||||
# Use to randomize the world
|
|
||||||
# Allowed values: Any string
|
|
||||||
|
|
||||||
default-player-permission-level=member
|
|
||||||
# Permission level for new players joining for the first time.
|
|
||||||
# Allowed values: "visitor", "member", "operator"
|
|
||||||
|
|
||||||
texturepack-required=false
|
|
||||||
# Force clients to use texture packs in the current world
|
|
||||||
# Allowed values: "true" or "false"
|
|
||||||
|
|
||||||
content-log-file-enabled=false
|
|
||||||
# Enables logging content errors to a file
|
|
||||||
# Allowed values: "true" or "false"
|
|
||||||
|
|
||||||
compression-threshold=1
|
|
||||||
# Determines the smallest size of raw network payload to compress
|
|
||||||
# Allowed values: 0-65535
|
|
||||||
|
|
||||||
compression-algorithm=zlib
|
|
||||||
# Determines the compression algorithm to use for networking
|
|
||||||
# Allowed values: "zlib", "snappy"
|
|
||||||
|
|
||||||
server-authoritative-movement=server-auth
|
|
||||||
# Allowed values: "client-auth", "server-auth", "server-auth-with-rewind"
|
|
||||||
# Enables server authoritative movement. If "server-auth", the server will replay local user input on
|
|
||||||
# the server and send down corrections when the client's position doesn't match the server's.
|
|
||||||
# If "server-auth-with-rewind" is enabled and the server sends a correction, the clients will be instructed
|
|
||||||
# to rewind time back to the correction time, apply the correction, then replay all the player's inputs since then. This results in smoother and more frequent corrections.
|
|
||||||
# Corrections will only happen if correct-player-movement is set to true.
|
|
||||||
|
|
||||||
player-movement-score-threshold=20
|
|
||||||
# The number of incongruent time intervals needed before abnormal behavior is reported.
|
|
||||||
# Disabled by server-authoritative-movement.
|
|
||||||
|
|
||||||
player-movement-action-direction-threshold=0.85
|
|
||||||
# The amount that the player's attack direction and look direction can differ.
|
|
||||||
# Allowed values: Any value in the range of [0, 1] where 1 means that the
|
|
||||||
# direction of the players view and the direction the player is attacking
|
|
||||||
# must match exactly and a value of 0 means that the two directions can
|
|
||||||
# differ by up to and including 90 degrees.
|
|
||||||
|
|
||||||
player-movement-distance-threshold=0.3
|
|
||||||
# The difference between server and client positions that needs to be exceeded before abnormal behavior is detected.
|
|
||||||
# Disabled by server-authoritative-movement.
|
|
||||||
|
|
||||||
player-movement-duration-threshold-in-ms=500
|
|
||||||
# The duration of time the server and client positions can be out of sync (as defined by player-movement-distance-threshold)
|
|
||||||
# before the abnormal movement score is incremented. This value is defined in milliseconds.
|
|
||||||
# Disabled by server-authoritative-movement.
|
|
||||||
|
|
||||||
correct-player-movement=false
|
|
||||||
# If true, the client position will get corrected to the server position if the movement score exceeds the threshold.
|
|
||||||
|
|
||||||
|
|
||||||
server-authoritative-block-breaking=false
|
|
||||||
# If true, the server will compute block mining operations in sync with the client so it can verify that the client should be able to break blocks when it thinks it can.
|
|
||||||
|
|
||||||
chat-restriction=None
|
|
||||||
# Allowed values: "None", "Dropped", "Disabled"
|
|
||||||
# This represents the level of restriction applied to the chat for each player that joins the server.
|
|
||||||
# "None" is the default and represents regular free chat.
|
|
||||||
# "Dropped" means the chat messages are dropped and never sent to any client. Players receive a message to let them know the feature is disabled.
|
|
||||||
# "Disabled" means that unless the player is an operator, the chat UI does not even appear. No information is displayed to the player.
|
|
||||||
|
|
||||||
disable-player-interaction=false
|
|
||||||
# If true, the server will inform clients that they should ignore other players when interacting with the world. This is not server authoritative.
|
|
@ -1,57 +0,0 @@
|
|||||||
#Minecraft server properties
|
|
||||||
#Mon Oct 17 00:27:26 UTC 2022
|
|
||||||
enable-jmx-monitoring=false
|
|
||||||
rcon.port=25575
|
|
||||||
level-seed=
|
|
||||||
gamemode=survival
|
|
||||||
enable-command-block=false
|
|
||||||
enable-query=false
|
|
||||||
generator-settings={}
|
|
||||||
enforce-secure-profile=true
|
|
||||||
level-name=world
|
|
||||||
motd=A Minecraft Server
|
|
||||||
query.port=25565
|
|
||||||
pvp=true
|
|
||||||
generate-structures=true
|
|
||||||
max-chained-neighbor-updates=1000000
|
|
||||||
difficulty=easy
|
|
||||||
network-compression-threshold=256
|
|
||||||
max-tick-time=60000
|
|
||||||
require-resource-pack=false
|
|
||||||
use-native-transport=true
|
|
||||||
max-players=20
|
|
||||||
online-mode=true
|
|
||||||
enable-status=true
|
|
||||||
allow-flight=false
|
|
||||||
broadcast-rcon-to-ops=true
|
|
||||||
view-distance=10
|
|
||||||
server-ip=
|
|
||||||
resource-pack-prompt=
|
|
||||||
allow-nether=true
|
|
||||||
server-port=25565
|
|
||||||
enable-rcon=false
|
|
||||||
sync-chunk-writes=true
|
|
||||||
op-permission-level=4
|
|
||||||
prevent-proxy-connections=false
|
|
||||||
hide-online-players=false
|
|
||||||
resource-pack=
|
|
||||||
entity-broadcast-range-percentage=100
|
|
||||||
simulation-distance=10
|
|
||||||
rcon.password=
|
|
||||||
player-idle-timeout=0
|
|
||||||
force-gamemode=false
|
|
||||||
rate-limit=0
|
|
||||||
hardcore=false
|
|
||||||
white-list=false
|
|
||||||
broadcast-console-to-ops=true
|
|
||||||
spawn-npcs=true
|
|
||||||
previews-chat=false
|
|
||||||
spawn-animals=true
|
|
||||||
function-permission-level=2
|
|
||||||
level-type=minecraft\:normal
|
|
||||||
text-filtering-config=
|
|
||||||
spawn-monsters=true
|
|
||||||
enforce-whitelist=false
|
|
||||||
spawn-protection=16
|
|
||||||
resource-pack-sha1=
|
|
||||||
max-world-size=29999984
|
|
1338
package-lock.json
generated
1338
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@ -1,52 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@the-bds-maneger/core",
|
"name": "@the-bds-maneger/monorepo",
|
||||||
"version": "5.4.0",
|
"private": true,
|
||||||
"description": "A very simple way to manage Minecraft servers",
|
"scripts": {},
|
||||||
"author": "Sirherobrine23",
|
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"homepage": "https://sirherobrine23.org/BdsProject",
|
|
||||||
"type": "module",
|
|
||||||
"types": "./src/index.d.ts",
|
|
||||||
"main": "./src/index.js",
|
|
||||||
"private": false,
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"docs": "typedoc --readme none --out docs src/index.ts",
|
|
||||||
"build": "tsc",
|
|
||||||
"test": "mocha src"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/Sirherobrine23/Bds-Maneger-Core.git"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/Sirherobrine23/Bds-Maneger-Core/issues/new",
|
|
||||||
"email": "support_bds@sirherobrine23.org"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@sirherobrine23/coreutils": "^3.1.2",
|
|
||||||
"adm-zip": "^0.5.10",
|
|
||||||
"compare-versions": "^5.0.3",
|
|
||||||
"debug": "^4.3.4",
|
|
||||||
"prismarine-nbt": "^2.2.1",
|
|
||||||
"tar": "^6.1.13"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/adm-zip": "^0.5.0",
|
"@types/node": "^18.14.0",
|
||||||
"@types/debug": "^4.1.7",
|
|
||||||
"@types/mocha": "^10.0.1",
|
|
||||||
"@types/node": "^18.13.0",
|
|
||||||
"@types/tar": "^6.1.3",
|
|
||||||
"mocha": "^10.2.0",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tsconfig-paths": "^4.1.2",
|
|
||||||
"typedoc": "^0.23.24",
|
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
},
|
||||||
|
"workspaces": [
|
||||||
|
"package/core",
|
||||||
|
"package/cli",
|
||||||
|
"package/docker"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
18
package/cli/package.json
Normal file
18
package/cli/package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "@the-bds-maneger/cli",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@the-bds-maneger/core": "*",
|
||||||
|
"yargs": "^17.7.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/yargs": "^17.0.22"
|
||||||
|
}
|
||||||
|
}
|
39
package/cli/src/index.ts
Normal file
39
package/cli/src/index.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import bdsCore from "@the-bds-maneger/core";
|
||||||
|
import yargs from "yargs";
|
||||||
|
|
||||||
|
// Init yargs
|
||||||
|
yargs(process.argv.slice(2)).version(false).help(true).strictCommands().demandCommand()
|
||||||
|
|
||||||
|
// bedrock
|
||||||
|
.command("bedrock", "Bedrock", yargs => yargs.command("install", "Install Server", async yargs => {
|
||||||
|
const options = yargs.option("altServer", {
|
||||||
|
string: true,
|
||||||
|
description: "Select a server other than Mojang",
|
||||||
|
demandOption: false,
|
||||||
|
choices: [
|
||||||
|
"pocketmine",
|
||||||
|
"powernukkit",
|
||||||
|
"cloudbust"
|
||||||
|
],
|
||||||
|
}).option("list", {
|
||||||
|
alias: "l",
|
||||||
|
boolean: true,
|
||||||
|
default: false,
|
||||||
|
description: "List versions instead of installing"
|
||||||
|
}).option("version", {
|
||||||
|
alias: "V",
|
||||||
|
string: true,
|
||||||
|
default: "latest",
|
||||||
|
description: "Server version to install",
|
||||||
|
}).parseSync();
|
||||||
|
if (options.list) return console.log(JSON.stringify(await bdsCore.Bedrock.listVersions({altServer: options.altServer as any}), null, 2));
|
||||||
|
const data = await bdsCore.Bedrock.installServer({
|
||||||
|
altServer: options.altServer as any,
|
||||||
|
version: options.version,
|
||||||
|
});
|
||||||
|
console.log("Server ID: %O", data.id);
|
||||||
|
}))
|
||||||
|
|
||||||
|
// run
|
||||||
|
.parseAsync();
|
31
package/cli/tsconfig.json
Normal file
31
package/cli/tsconfig.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"declaration": true,
|
||||||
|
"strict": false,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"lib": [
|
||||||
|
"ESNext"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/*.test.*"
|
||||||
|
],
|
||||||
|
"ts-node": {
|
||||||
|
"esm": true
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../core"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
package/core/README.md
Normal file
5
package/core/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Bds Maneger Core
|
||||||
|
|
||||||
|
Este é um nucleo de utilização basica como: Fazer download do servidor, Gerenciar e outras coisas.
|
||||||
|
|
||||||
|
**Atualmente suportamos varias servidores, tanto para o Bedrock tanto o Java**
|
26
package/core/package.json
Normal file
26
package/core/package.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "@the-bds-maneger/core",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"types": "src/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
|
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --build --clean && tsc"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sirherobrine23/cloud": "^3.2.1",
|
||||||
|
"@sirherobrine23/extends": "^3.2.1",
|
||||||
|
"@sirherobrine23/http": "^3.2.1",
|
||||||
|
"semver": "^7.3.8",
|
||||||
|
"tar": "^6.1.13",
|
||||||
|
"unzip-stream": "^0.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/semver": "^7.3.13",
|
||||||
|
"@types/tar": "^6.1.4",
|
||||||
|
"@types/unzip-stream": "^0.3.1"
|
||||||
|
}
|
||||||
|
}
|
12
package/core/src/index.ts
Normal file
12
package/core/src/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export * from "./serverManeger.js";
|
||||||
|
export * as Bedrock from "./servers/bedrock.js";
|
||||||
|
export * as Java from "./servers/java.js";
|
||||||
|
|
||||||
|
import * as serverManeger from "./serverManeger.js";
|
||||||
|
import * as Bedrock from "./servers/bedrock.js";
|
||||||
|
import * as Java from "./servers/java.js";
|
||||||
|
export default {
|
||||||
|
...serverManeger,
|
||||||
|
Bedrock,
|
||||||
|
Java
|
||||||
|
};
|
@ -1,11 +1,12 @@
|
|||||||
import { Cloud } from "@sirherobrine23/coreutils";
|
import { oracleBucket } from "@sirherobrine23/cloud";
|
||||||
|
|
||||||
export const oracleBucket = await Cloud.oracleBucket({
|
export const oracleStorage = await oracleBucket.oracleBucket({
|
||||||
region: "sa-saopaulo-1",
|
region: "sa-saopaulo-1",
|
||||||
namespace: "grwodtg32n4d",
|
namespace: "grwodtg32n4d",
|
||||||
name: "bdsFiles",
|
name: "bdsFiles",
|
||||||
auth: {
|
auth: {
|
||||||
type: "preAuthentication",
|
type: "preAuthentication",
|
||||||
|
// Public auth (No write enabled).
|
||||||
PreAuthenticatedKey: "0IKM-5KFpAF8PuWoVe86QFsF4sipU2rXfojpaOMEdf4QgFQLcLlDWgMSPHWmjf5W"
|
PreAuthenticatedKey: "0IKM-5KFpAF8PuWoVe86QFsF4sipU2rXfojpaOMEdf4QgFQLcLlDWgMSPHWmjf5W"
|
||||||
}
|
}
|
||||||
});
|
});
|
121
package/core/src/serverManeger.ts
Normal file
121
package/core/src/serverManeger.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { extendsFS } from "@sirherobrine23/extends";
|
||||||
|
import child_process from "node:child_process";
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
import path from "node:path";
|
||||||
|
import fs from "node:fs/promises";
|
||||||
|
import os from "node:os";
|
||||||
|
|
||||||
|
// Default bds maneger core
|
||||||
|
export const bdsManegerRoot = process.env.bdscoreroot ? path.resolve(process.cwd(), process.env.bdscoreroot) : path.join(os.homedir(), ".bdsmaneger");
|
||||||
|
if (!(await extendsFS.exists(bdsManegerRoot))) await fs.mkdir(bdsManegerRoot, {recursive: true});
|
||||||
|
|
||||||
|
export type runOptions = {
|
||||||
|
cwd: string,
|
||||||
|
env?: {[k: string]: string|number|boolean},
|
||||||
|
command: string,
|
||||||
|
args?: (string|number|boolean)[],
|
||||||
|
serverActions?: {
|
||||||
|
stop?(child: serverRun): void|Promise<void>,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export declare class serverRun extends child_process.ChildProcess {
|
||||||
|
on(event: string, listener: (...args: any[]) => void): this;
|
||||||
|
on(event: "error", listener: (err: Error) => void): this;
|
||||||
|
on(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||||
|
on(event: "disconnect", listener: () => void): this;
|
||||||
|
on(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||||
|
on(event: "message", listener: (message: child_process.Serializable, sendHandle: child_process.SendHandle) => void): this;
|
||||||
|
on(event: "spawn", listener: () => void): this;
|
||||||
|
|
||||||
|
once(event: string, listener: (...args: any[]) => void): this;
|
||||||
|
once(event: "error", listener: (err: Error) => void): this;
|
||||||
|
once(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||||
|
once(event: "disconnect", listener: () => void): this;
|
||||||
|
once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||||
|
once(event: "message", listener: (message: child_process.Serializable, sendHandle: child_process.SendHandle) => void): this;
|
||||||
|
once(event: "spawn", listener: () => void): this;
|
||||||
|
|
||||||
|
stopServer(): Promise<{code?: number, signal?: NodeJS.Signals}>;
|
||||||
|
sendCommand(...args: (string|number|boolean)[]): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function runServer(options: runOptions): Promise<serverRun> {
|
||||||
|
const child = child_process.execFile(options.command, [...((options.args ?? []).map(String))], {
|
||||||
|
maxBuffer: Infinity,
|
||||||
|
cwd: options.cwd || process.cwd(),
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...Object.keys(options.env ?? {}).reduce((acc, a) => {
|
||||||
|
acc[a] = String(options.env[a]);
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
}) as serverRun;
|
||||||
|
child.sendCommand = function (...args) {
|
||||||
|
if (!child.stdin.writable) {
|
||||||
|
child.emit("error", new Error("cannot send command to server"));
|
||||||
|
return child;
|
||||||
|
};
|
||||||
|
child.stdin.write(args.map(String).join(" ")+"\n");
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.stopServer = async function () {
|
||||||
|
const stop = options.serverActions?.stop ?? function (child) {
|
||||||
|
|
||||||
|
};
|
||||||
|
Promise.resolve().then(() => stop(child)).catch(err => child.emit("error", err));
|
||||||
|
return new Promise((done, reject) => child.once("error", reject).once("exit", (code, signal) => done({code, signal})));
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type manegerOptions = {
|
||||||
|
ID?: string,
|
||||||
|
newID?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function serverManeger(options: manegerOptions) {
|
||||||
|
if (!options) throw new TypeError("Por favor adicione as opções do serverManeger!");
|
||||||
|
if (!options.ID) options.newID = true;
|
||||||
|
if (options.newID) {
|
||||||
|
while(true) {
|
||||||
|
options.ID = crypto.randomBytes(16).toString("hex");
|
||||||
|
if (!(await fs.readdir(bdsManegerRoot)).includes(options.ID)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform ID root path
|
||||||
|
*/
|
||||||
|
const rootPath = path.join(bdsManegerRoot, options.ID);
|
||||||
|
if (!(await extendsFS.exists(rootPath))) await fs.mkdir(rootPath, {recursive: true});
|
||||||
|
|
||||||
|
// sub-folders
|
||||||
|
const serverFolder = path.join(rootPath, "server");
|
||||||
|
const backup = path.join(rootPath, "backups");
|
||||||
|
|
||||||
|
for await (const p of [
|
||||||
|
serverFolder,
|
||||||
|
backup,
|
||||||
|
]) if (!(await extendsFS.exists(p))) await fs.mkdir(p, {recursive: true});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: options.ID,
|
||||||
|
rootPath,
|
||||||
|
serverFolder,
|
||||||
|
backup,
|
||||||
|
async runCommand(options: Omit<runOptions, "cwd">) {
|
||||||
|
return runServer({...options, cwd: serverFolder});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type serverManegerV1 = Awaited<ReturnType<typeof serverManeger>>;
|
205
package/core/src/servers/bedrock.ts
Normal file
205
package/core/src/servers/bedrock.ts
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
import coreHttp, { Github, large } from "@sirherobrine23/http";
|
||||||
|
import { manegerOptions, runOptions, serverManeger } from "../serverManeger.js";
|
||||||
|
import { commandExists } from "../childPromisses.js";
|
||||||
|
import { oracleStorage } from "../internal.js";
|
||||||
|
import { pipeline } from "node:stream/promises";
|
||||||
|
import semver from "semver";
|
||||||
|
import unzip from "unzip-stream";
|
||||||
|
import utils from "node:util";
|
||||||
|
import path from "node:path";
|
||||||
|
import tar from "tar";
|
||||||
|
import extendsFS from "@sirherobrine23/extends";
|
||||||
|
|
||||||
|
export type bedrockOptions = manegerOptions & {
|
||||||
|
/**
|
||||||
|
* Servidor alternativo ao invés do servidor ofical da Mojang
|
||||||
|
*/
|
||||||
|
altServer?: "pocketmine"|"powernukkit"|"cloudbust",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pocketmineGithub = await Github.GithubManeger("pmmp", "PocketMine-MP");
|
||||||
|
|
||||||
|
export async function listVersions(options: {altServer: "powernukkit"} & Omit<bedrockOptions, "altServer"|keyof manegerOptions>): Promise<{version: string, mcpeVersion: string, date: Date, variantType: "stable"|"snapshot", url: string}[]>;
|
||||||
|
export async function listVersions(options: {altServer: "pocketmine"} & Omit<bedrockOptions, "altServer"|keyof manegerOptions>): Promise<Github.githubRelease[]>;
|
||||||
|
export async function listVersions(): Promise<{version: string, date: Date, release?: "stable"|"preview", url: {[platform in NodeJS.Platform]?: {[arch in NodeJS.Architecture]?: string}}}[]>;
|
||||||
|
export async function listVersions(options?: Omit<bedrockOptions, keyof manegerOptions>) {
|
||||||
|
if (!options) options = {};
|
||||||
|
if (options.altServer === "pocketmine") return pocketmineGithub.getRelease();
|
||||||
|
else if (options.altServer === "powernukkit") {
|
||||||
|
const releases_version = (await coreHttp.jsonRequest<{[k: string]: {version: string, releaseTime: number, minecraftVersion: string, artefacts: string[], commitId: string, snapshotBuild?: number}[]}>("https://raw.githubusercontent.com/PowerNukkit/powernukkit-version-aggregator/master/powernukkit-versions.json")).body;
|
||||||
|
return Object.keys(releases_version).reduce((acc, key) => {
|
||||||
|
for (const data of releases_version[key]) {
|
||||||
|
const dt = new Date(data.releaseTime);
|
||||||
|
const getArtefactExtension = (artefactId: string) => (artefactId.includes("REDUCED_JAR")) ? ".jar" : (artefactId.includes("REDUCED_SOURCES_JAR")) ? "-sources.jar" : (artefactId.includes("SHADED_JAR")) ? "-shaded.jar" : (artefactId.includes("SHADED_SOURCES_JAR")) ? "-shaded-sources.jar" : (artefactId.includes("JAVADOC_JAR")) ? "-javadoc.jar" : ".unknown";
|
||||||
|
function buildArtefactUrl(data: any, artefactId?: string) {
|
||||||
|
const buildReleaseArtefactUrl = (data: any, artefactId?: string) => !data.artefacts.includes(artefactId) ? null : utils.format("https://search.maven.org/remotecontent?filepath=org/powernukkit/powernukkit/%s/powernukkit-%s%s", data.version, data.version, getArtefactExtension(artefactId));
|
||||||
|
const buildSnapshotArtefactUrl = (data: any, artefactId?: string) => !data.artefacts.includes(artefactId) ? null : utils.format("https://oss.sonatype.org/content/repositories/snapshots/org/powernukkit/powernukkit/%s-SNAPSHOT/powernukkit-%s-%s%s", data.version.substring(0, data.version.indexOf("-SNAPSHOT")), data.version.substring(0, data.version.indexOf("-SNAPSHOT")), dt.getUTCFullYear().toString().padStart(4, "0") + (dt.getUTCMonth() + 1).toString().padStart(2, "0") + dt.getUTCDate().toString().padStart(2, "0") + "." + dt.getUTCHours().toString().padStart(2, "0") + dt.getUTCMinutes().toString().padStart(2, "0") + dt.getUTCSeconds().toString().padStart(2, "0") + "-" + data.snapshotBuild, getArtefactExtension(artefactId));
|
||||||
|
if (artefactId == "GIT_SOURCE") {
|
||||||
|
if (data.commitId) return utils.format("https://github.com/PowerNukkit/PowerNukkit/tree/%s", data.commitId);
|
||||||
|
else if (data.snapshotBuild && data.artefacts.includes("SHADED_SOURCES_JAR")) return buildSnapshotArtefactUrl(data, "SHADED_SOURCES_JAR");
|
||||||
|
else if (data.snapshotBuild && data.artefacts.includes("REDUCED_SOURCES_JAR")) return buildSnapshotArtefactUrl(data, "REDUCED_SOURCES_JAR");
|
||||||
|
else if (data.artefacts.includes("SHADED_SOURCES_JAR")) return buildReleaseArtefactUrl(data, "SHADED_SOURCES_JAR");
|
||||||
|
else if (data.artefacts.includes("REDUCED_SOURCES_JAR")) return buildReleaseArtefactUrl(data, "REDUCED_SOURCES_JAR");
|
||||||
|
} else if (data.snapshotBuild) return buildSnapshotArtefactUrl(data, artefactId);
|
||||||
|
else return buildReleaseArtefactUrl(data, artefactId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const artefacts = data.artefacts.reduce((acc, artefactId) => {acc[artefactId] = buildArtefactUrl(data, artefactId); return acc;}, {} as {[key: string]: string});
|
||||||
|
const verRel = {
|
||||||
|
version: data.version,
|
||||||
|
mcpeVersion: data.minecraftVersion,
|
||||||
|
date: dt,
|
||||||
|
variantType: (!data.snapshotBuild?"snapshot":"stable") as "stable"|"snapshot",
|
||||||
|
url: artefacts.SHADED_JAR || artefacts.REDUCED_JAR
|
||||||
|
};
|
||||||
|
if (!!verRel.url) acc.push(verRel);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, [] as {version: string, mcpeVersion: string, date: Date, variantType: "stable"|"snapshot", url: string}[]).filter(a => !!a.url).sort((b, a) => (b.date.getTime() - a.date.getTime()) - semver.compare(semver.valid(semver.coerce(a.version)), semver.valid(semver.coerce(b.version))));
|
||||||
|
} else if (options.altServer === "cloudbust") throw new TypeError("O Cloudbust não tem listagem de versöes");
|
||||||
|
return (await coreHttp.jsonRequest<{version: string, date: Date, release?: "stable"|"preview", url: {[platform in NodeJS.Platform]?: {[arch in NodeJS.Architecture]?: string}}}[]>("https://sirherobrine23.github.io/BedrockFetch/all.json")).body;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function installServer(options: bedrockOptions & {version?: string, allowBeta?: boolean}): Promise<{id: string, version: string, mcpeVersion?: string, releaseDate: Date}> {
|
||||||
|
const serverPath = await serverManeger(options);
|
||||||
|
if (options.altServer === "pocketmine") {
|
||||||
|
const version = (options.version ?? "latest").trim();
|
||||||
|
const rel = (await pocketmineGithub.getRelease(version));
|
||||||
|
if (!rel) throw new Error("Não foi possivel encontrar a versão informada do Pocketmine!");
|
||||||
|
|
||||||
|
const phpFile = (await oracleStorage.listFiles("php_bin")).find(file => file.name.includes(process.platform) && file.name.includes(process.arch));
|
||||||
|
if (!phpFile) throw new Error(`Não foi possivel encontra os arquivos do php para o ${process.platform} com a arquitetura ${process.arch}`);
|
||||||
|
if (phpFile.name.endsWith(".tar.gz")) await pipeline(await oracleStorage.getFileStream(phpFile.name), tar.extract({cwd: serverPath.serverFolder}));
|
||||||
|
else if (phpFile.name.endsWith(".zip")) await pipeline(await oracleStorage.getFileStream(phpFile.name), unzip.Extract({path: serverPath.serverFolder}));
|
||||||
|
else throw new Error("Arquivo encontrado não é suportado!");
|
||||||
|
|
||||||
|
// save phar
|
||||||
|
await large.saveFile({
|
||||||
|
url: rel.assets.find(a => a.name.endsWith(".phar"))?.browser_download_url,
|
||||||
|
path: path.join(serverPath.serverFolder, "server.phar")
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: serverPath.id,
|
||||||
|
version: rel.tag_name,
|
||||||
|
releaseDate: new Date(rel.published_at)
|
||||||
|
};
|
||||||
|
} else if (options.altServer === "powernukkit") {
|
||||||
|
const version = (options.version ?? "latest").trim();
|
||||||
|
const releases = await listVersions({altServer: "powernukkit"});
|
||||||
|
const relVersion = releases.find(rel => {
|
||||||
|
if (rel.variantType === "snapshot") if (!options.allowBeta) return false;
|
||||||
|
if (version.toLowerCase() === "latest") return true;
|
||||||
|
return (rel.version === version || rel.mcpeVersion === version);
|
||||||
|
});
|
||||||
|
if (!relVersion) throw new Error("A versão não foi encontrada, por favor verique a versão informada!");
|
||||||
|
await large.saveFile({
|
||||||
|
path: path.join(serverPath.serverFolder, "server.jar"),
|
||||||
|
url: relVersion.url
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
id: serverPath.id,
|
||||||
|
version: relVersion.version,
|
||||||
|
mcpeVersion: relVersion.mcpeVersion,
|
||||||
|
releaseDate: relVersion.date,
|
||||||
|
};
|
||||||
|
} else if (options.altServer === "cloudbust") {
|
||||||
|
await large.saveFile({
|
||||||
|
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
||||||
|
path: path.join(serverPath.serverFolder, "server.jar")
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: serverPath.id,
|
||||||
|
version: "bleeding",
|
||||||
|
releaseDate: new Date()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const bedrockVersion = (await listVersions()).find(rel => {
|
||||||
|
if (rel.release === "preview" && !!options.allowBeta) return false;
|
||||||
|
const version = (options.version ?? "latest").trim();
|
||||||
|
if (version.toLowerCase() === "latest") return true;
|
||||||
|
return rel.version === version;
|
||||||
|
});
|
||||||
|
if (!bedrockVersion) throw new Error("Não existe essa versão");
|
||||||
|
let downloadUrl = bedrockVersion.url[process.platform]?.[process.arch];
|
||||||
|
if ((["android", "linux"] as NodeJS.Process["platform"][]).includes(process.platform) && process.arch !== "x64") {
|
||||||
|
if (!downloadUrl) {
|
||||||
|
for (const emu of ["qemu-x86_64-static", "qemu-x86_64", "box64"]) {
|
||||||
|
if (downloadUrl) break;
|
||||||
|
if (await commandExists(emu)) downloadUrl = bedrockVersion.url.linux?.x64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!downloadUrl) throw new Error(`Não existe o URL de download para ${process.platform} na arquitetura ${process.arch}`);
|
||||||
|
await pipeline(await coreHttp.streamRequest(downloadUrl), unzip.Extract({path: serverPath.serverFolder}));
|
||||||
|
return {
|
||||||
|
id: serverPath.id,
|
||||||
|
version: bedrockVersion.version,
|
||||||
|
releaseDate: bedrockVersion.date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startServer(options: bedrockOptions) {
|
||||||
|
const serverPath = await serverManeger(options);
|
||||||
|
if (options.altServer === "powernukkit"||options.altServer === "cloudbust") {
|
||||||
|
return serverPath.runCommand({
|
||||||
|
command: "java",
|
||||||
|
args: [
|
||||||
|
"-XX:+UseG1GC",
|
||||||
|
"-XX:+ParallelRefProcEnabled",
|
||||||
|
"-XX:MaxGCPauseMillis=200",
|
||||||
|
"-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+DisableExplicitGC",
|
||||||
|
"-XX:+AlwaysPreTouch",
|
||||||
|
"-XX:G1NewSizePercent=30",
|
||||||
|
"-XX:G1MaxNewSizePercent=40",
|
||||||
|
"-XX:G1HeapRegionSize=8M",
|
||||||
|
"-XX:G1ReservePercent=20",
|
||||||
|
"-XX:G1HeapWastePercent=5",
|
||||||
|
"-XX:G1MixedGCCountTarget=4",
|
||||||
|
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||||
|
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||||
|
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||||
|
"-XX:SurvivorRatio=32",
|
||||||
|
"-XX:+PerfDisableSharedMem",
|
||||||
|
"-XX:MaxTenuringThreshold=1",
|
||||||
|
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||||
|
"-Daikars.new.flags=true",
|
||||||
|
"-jar", "server.jar",
|
||||||
|
],
|
||||||
|
serverActions: {
|
||||||
|
stop(child) {
|
||||||
|
child.sendCommand("stop");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (options.altServer === "pocketmine") {
|
||||||
|
return serverPath.runCommand({
|
||||||
|
command: (await extendsFS.readdir(serverPath.serverFolder)).find(file => file.endsWith("php")||file.endsWith("php.exe")),
|
||||||
|
args: [
|
||||||
|
"server.jar",
|
||||||
|
"--no-wizard"
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (process.platform === "darwin") throw new Error("Run in docker or podman!");
|
||||||
|
const run: Omit<runOptions, "cwd"> = {
|
||||||
|
command: path.join(serverPath.serverFolder, "bedrock_server"),
|
||||||
|
serverActions: {
|
||||||
|
stop(child) {
|
||||||
|
child.sendCommand("stop");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ((["android", "linux"] as NodeJS.Process["platform"][]).includes(process.platform) && process.arch !== "x64") {
|
||||||
|
for (const emu of ["qemu-x86_64-static", "qemu-x86_64", "box64"]) {
|
||||||
|
if (await commandExists(emu)) {
|
||||||
|
run.args = [emu, run.command];
|
||||||
|
run.command = emu;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serverPath.runCommand(run);
|
||||||
|
}
|
88
package/core/src/servers/java.ts
Normal file
88
package/core/src/servers/java.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { manegerOptions, serverManeger } from "../serverManeger.js";
|
||||||
|
import coreHttp, { large } from "@sirherobrine23/http";
|
||||||
|
import utils from "node:util";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
export type javaOptions = manegerOptions & {
|
||||||
|
/**
|
||||||
|
* Servidor alternativo ao invés do servidor ofical da Mojang
|
||||||
|
*/
|
||||||
|
altServer?: "spigot"|"paper"|"purpur"
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function listVersions(options: Omit<javaOptions, keyof manegerOptions>) {
|
||||||
|
if (options.altServer === "purpur") {
|
||||||
|
return Promise.all((await coreHttp.jsonRequest<{versions: string[]}>("https://api.purpurmc.org/v2/purpur")).body.versions.map(async version => ({
|
||||||
|
version,
|
||||||
|
downloadUrl: utils.format("https://api.purpurmc.org/v2/purpur/%s/latest/download", version),
|
||||||
|
date: new Date((await coreHttp.jsonRequest<{timestamp: number}>(utils.format("https://api.purpurmc.org/v2/purpur/%s/latest", version))).body.timestamp)
|
||||||
|
})));
|
||||||
|
} else if (options.altServer === "paper") {
|
||||||
|
return Promise.all((await coreHttp.jsonRequest<{versions: string[]}>("https://api.papermc.io/v2/projects/paper")).body.versions.map(async version => {
|
||||||
|
const build = (await coreHttp.jsonRequest<{builds: number[]}>(utils.format("https://api.papermc.io/v2/projects/paper/versions/%s", version))).body.builds.at(-1);
|
||||||
|
const data = (await coreHttp.jsonRequest<{time: string, downloads: {[k: string]: {name: string, sha256: string}}}>(utils.format("https://api.papermc.io/v2/projects/paper/versions/%s/builds/%s", version, build))).body;
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
date: new Date(data.time),
|
||||||
|
downloadUrl: utils.format("https://api.papermc.io/v2/projects/paper/versions/%s/builds/%s/downloads/%s", version, build, data.downloads["application"].name)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else if (options.altServer === "spigot") {
|
||||||
|
throw new Error("Não foi implementado!");
|
||||||
|
}
|
||||||
|
return (await Promise.all((await coreHttp.jsonRequest<{versions: {id: string, releaseTime: string, url: string}[]}>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json")).body.versions.map(async data => ({
|
||||||
|
version: data.id,
|
||||||
|
date: new Date(data.releaseTime),
|
||||||
|
downloadUrl: (await coreHttp.jsonRequest<{downloads: {[k: string]: {size: number, url: string}}}>(data.url)).body.downloads?.["server"]?.url
|
||||||
|
})))).filter(a => !!a.downloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function installServer(options: javaOptions & {version?: string}) {
|
||||||
|
const serverPath = await serverManeger(options);
|
||||||
|
const version = (await listVersions(options)).find(rel => (!options.version || options.version === "latest" || rel.version === options.version));
|
||||||
|
if (!version) throw new Error("Não existe a versão informada!");
|
||||||
|
await large.saveFile({
|
||||||
|
path: path.join(serverPath.serverFolder, "server.jar"),
|
||||||
|
url: version.downloadUrl
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...version,
|
||||||
|
id: serverPath.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startServer(options: javaOptions) {
|
||||||
|
const serverPath = await serverManeger(options);
|
||||||
|
return serverPath.runCommand({
|
||||||
|
command: "java",
|
||||||
|
args: [
|
||||||
|
"-XX:+UseG1GC",
|
||||||
|
"-XX:+ParallelRefProcEnabled",
|
||||||
|
"-XX:MaxGCPauseMillis=200",
|
||||||
|
"-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:+DisableExplicitGC",
|
||||||
|
"-XX:+AlwaysPreTouch",
|
||||||
|
"-XX:G1NewSizePercent=30",
|
||||||
|
"-XX:G1MaxNewSizePercent=40",
|
||||||
|
"-XX:G1HeapRegionSize=8M",
|
||||||
|
"-XX:G1ReservePercent=20",
|
||||||
|
"-XX:G1HeapWastePercent=5",
|
||||||
|
"-XX:G1MixedGCCountTarget=4",
|
||||||
|
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||||
|
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||||
|
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||||
|
"-XX:SurvivorRatio=32",
|
||||||
|
"-XX:+PerfDisableSharedMem",
|
||||||
|
"-XX:MaxTenuringThreshold=1",
|
||||||
|
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||||
|
"-Daikars.new.flags=true",
|
||||||
|
"-jar", "server.jar",
|
||||||
|
],
|
||||||
|
serverActions: {
|
||||||
|
stop(child) {
|
||||||
|
child.sendCommand("stop");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
27
package/core/tsconfig.json
Normal file
27
package/core/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"declaration": true,
|
||||||
|
"strict": false,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"lib": [
|
||||||
|
"ESNext"
|
||||||
|
],
|
||||||
|
"composite": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/*.test.*"
|
||||||
|
],
|
||||||
|
"ts-node": {
|
||||||
|
"esm": true
|
||||||
|
}
|
||||||
|
}
|
17
package/docker/package.json
Normal file
17
package/docker/package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "@the-bds-maneger/docker",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"bdsdocker": "./src/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
31
package/docker/tsconfig.json
Normal file
31
package/docker/tsconfig.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"declaration": true,
|
||||||
|
"strict": false,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"lib": [
|
||||||
|
"ESNext"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/*.test.*"
|
||||||
|
],
|
||||||
|
"ts-node": {
|
||||||
|
"esm": true
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../core"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export * as serverManeger from "./serverManeger.js";
|
|
||||||
export * as Bedrock from "./platform/Bedrock.js";
|
|
||||||
export * as Java from "./platform/Java.js";
|
|
@ -1,43 +0,0 @@
|
|||||||
export default {parse, stringify};
|
|
||||||
export type properitiesBase = {[key: string]: string|number|true|false};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse Proprieties files and return a map of properties.
|
|
||||||
*
|
|
||||||
* @param Proper - String with the properties or similar files
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function parse<PropertiesObject extends properitiesBase>(Proper: string): PropertiesObject {
|
|
||||||
const ProPri = {};
|
|
||||||
const ProperSplit = Proper.replace(/\\\s+?\n/gi, "").split(/\r?\n/).map(Line => Line.trim()).filter(line => /.*(\s+)?\=(\s+)?.*/.test(line) && !/^#/.test(line));
|
|
||||||
for (const Line of ProperSplit) {
|
|
||||||
const LineMatch = Line.match(/^([^\s\=]+)\s*\=(.*)$/);
|
|
||||||
const key = LineMatch[1].trim(), value = LineMatch[2].trim();
|
|
||||||
ProPri[key] = value;
|
|
||||||
if (ProPri[key] === "true") ProPri[key] = true;
|
|
||||||
else if (ProPri[key] === "false") ProPri[key] = false;
|
|
||||||
else if (/^[0-9]+\.[0-9]+/.test(ProPri[key]) && !/^[0-9]+\.[0-9]+\.[0-9]+/.test(ProPri[key])) ProPri[key] = parseFloat(ProPri[key]);
|
|
||||||
else if (/^[0-9]+/.test(ProPri[key])) ProPri[key] = parseInt(ProPri[key]);
|
|
||||||
}
|
|
||||||
return ProPri as PropertiesObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert json to properities files.
|
|
||||||
*
|
|
||||||
* @param ProPri - String with properties file
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function stringify(ProPri: properitiesBase): string {
|
|
||||||
const Proper = [];
|
|
||||||
for (const key of Object.keys(ProPri)) {
|
|
||||||
if (ProPri[key] === null||ProPri[key] === undefined) Proper.push(`${key}=`);
|
|
||||||
else if (ProPri[key] === true) Proper.push(`${key}=true`);
|
|
||||||
else if (ProPri[key] === false) Proper.push(`${key}=false`);
|
|
||||||
else if (typeof ProPri[key] === "number") Proper.push(`${key}=${ProPri[key]}`);
|
|
||||||
else if (typeof ProPri[key] === "string") Proper.push(`${key}=${ProPri[key]}`);
|
|
||||||
else if (typeof ProPri[key] === "object") Proper.push(`${key}=${JSON.stringify(ProPri[key])}`);
|
|
||||||
else console.error(`[Proprieties.stringify] ${key} is not a valid type.`);
|
|
||||||
}
|
|
||||||
return Proper.join("\n");
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
import dgram from "node:dgram";
|
|
||||||
import net from "node:net";
|
|
||||||
|
|
||||||
export type proxyUdpToTcpOptions = {
|
|
||||||
udpType?: dgram.SocketType,
|
|
||||||
listen?: number,
|
|
||||||
portListen?: (port: number) => void
|
|
||||||
};
|
|
||||||
|
|
||||||
export type proxyTcpToUdpClient = {
|
|
||||||
udpType?: dgram.SocketType,
|
|
||||||
listen?: number,
|
|
||||||
remote: {
|
|
||||||
host: string,
|
|
||||||
port: number
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transfer packets from UDP to TCP to send through some tunnel that only accepts TCP
|
|
||||||
*
|
|
||||||
* This also means that it will also have error transporting the data, so it is not guaranteed to work properly even more when dealing with UDP packets.
|
|
||||||
*/
|
|
||||||
export function proxyUdpToTcp(udpPort: number, options?: proxyUdpToTcpOptions) {
|
|
||||||
const tcpServer = net.createServer();
|
|
||||||
tcpServer.on("error", err => console.error(err));
|
|
||||||
tcpServer.on("connection", socket => {
|
|
||||||
const udpClient = dgram.createSocket(options?.udpType||"udp4");
|
|
||||||
|
|
||||||
// Close Sockets
|
|
||||||
udpClient.once("close", () => socket.end());
|
|
||||||
socket.once("close", () => udpClient.close());
|
|
||||||
|
|
||||||
// Print error
|
|
||||||
udpClient.on("error", console.error);
|
|
||||||
socket.on("error", console.error);
|
|
||||||
|
|
||||||
// Pipe Datas
|
|
||||||
udpClient.on("message", data => socket.write(data));
|
|
||||||
socket.on("data", data => udpClient.send(data));
|
|
||||||
|
|
||||||
// Connect
|
|
||||||
udpClient.connect(udpPort);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen
|
|
||||||
tcpServer.listen(options?.listen||0, function() {
|
|
||||||
const addr = this.address();
|
|
||||||
if (options?.portListen) options.portListen(addr.port);
|
|
||||||
console.debug("bds proxy port listen, %s, (udp -> tcp)", addr.port);
|
|
||||||
tcpServer.once("close", () => console.debug("bds proxy close, %s", addr.port));
|
|
||||||
});
|
|
||||||
|
|
||||||
return tcpServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function proxyTcpToUdp(options: proxyTcpToUdpClient) {
|
|
||||||
const sessions: {[keyIP: string]: net.Socket} = {};
|
|
||||||
const udp = dgram.createSocket(options?.udpType||"udp4");
|
|
||||||
|
|
||||||
udp.on("error", console.error);
|
|
||||||
udp.on("message", (msg, ipInfo) => {
|
|
||||||
const keyInfo = `${ipInfo.address}:${ipInfo.port}`;
|
|
||||||
|
|
||||||
// Client TCP
|
|
||||||
if (!sessions[keyInfo]) {
|
|
||||||
sessions[keyInfo] = net.createConnection(options.remote);
|
|
||||||
sessions[keyInfo].on("data", data => udp.send(data, ipInfo.port, ipInfo.address));
|
|
||||||
sessions[keyInfo].on("error", console.error);
|
|
||||||
sessions[keyInfo].once("close", () => {
|
|
||||||
delete sessions[keyInfo];
|
|
||||||
console.log("Client %s:%f close", ipInfo.address, ipInfo.port);
|
|
||||||
});
|
|
||||||
console.log("Client %s:%f connected", ipInfo.address, ipInfo.port);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send message
|
|
||||||
sessions[keyInfo].write(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen port
|
|
||||||
udp.bind(options.listen||0, function(){
|
|
||||||
const addr = this.address();
|
|
||||||
console.log("Port listen, %s (tcp -> udp)", addr.port);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import net from "net"
|
|
||||||
export async function randomPort(): Promise<number> {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
const srv = net.createServer();
|
|
||||||
srv.listen(0, () => {
|
|
||||||
const address = srv.address();
|
|
||||||
if (typeof address === "string") return rej(new Error("Invalid listen port"));
|
|
||||||
srv.close((_err) => res(address.port));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,252 +0,0 @@
|
|||||||
import { createServerManeger, platformPathID, pathOptions, serverConfig } from "../serverManeger.js";
|
|
||||||
import { promises as fs, createWriteStream } from "node:fs";
|
|
||||||
import { oracleBucket } from "../lib/remote.js";
|
|
||||||
import { promisify } from "node:util";
|
|
||||||
import { pipeline } from "node:stream/promises";
|
|
||||||
import * as childPromisses from "../lib/childPromisses.js";
|
|
||||||
import coreUtils from "@sirherobrine23/coreutils";
|
|
||||||
import AdmZip from "adm-zip";
|
|
||||||
import path from "node:path";
|
|
||||||
import tar from "tar";
|
|
||||||
|
|
||||||
export type bedrockRootOption = pathOptions & {
|
|
||||||
variant?: "oficial"|"Pocketmine-PMMP"|"Powernukkit"|"Cloudbust"
|
|
||||||
};
|
|
||||||
|
|
||||||
export const hostArchEmulate = Object.freeze([
|
|
||||||
"qemu-x86_64-static",
|
|
||||||
"qemu-x86_64",
|
|
||||||
"box64"
|
|
||||||
]);
|
|
||||||
|
|
||||||
type bedrockVersionJSON = {
|
|
||||||
version: string,
|
|
||||||
date: Date,
|
|
||||||
release?: "stable"|"preview",
|
|
||||||
url: {
|
|
||||||
[platform in NodeJS.Platform]?: {
|
|
||||||
[arch in NodeJS.Architecture]?: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getPHPBin(options?: bedrockRootOption) {
|
|
||||||
options = {variant: "oficial", ...options};
|
|
||||||
const serverPath = await platformPathID("bedrock", options);
|
|
||||||
const binFolder = path.join(serverPath.serverPath, "bin");
|
|
||||||
const files = await coreUtils.Extends.readdir({folderPath: binFolder});
|
|
||||||
const file = files.find((v) => v.endsWith("php.exe")||v.endsWith("php"));
|
|
||||||
if (!file) throw new Error("PHP Bin not found");
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function installServer(version?: string, options?: bedrockRootOption) {
|
|
||||||
options = {variant: "oficial", ...options};
|
|
||||||
const serverPath = await platformPathID("bedrock", options);
|
|
||||||
if (options?.variant === "Pocketmine-PMMP") {
|
|
||||||
if (!version) version = "latest";
|
|
||||||
const phpBin = ((await oracleBucket.listFiles()) as any[]).filter(({name}) => name.includes("php_bin/")).filter(({name}) => name.includes(process.platform) && name.includes(process.arch)).at(0);
|
|
||||||
if (!phpBin) throw new Error("PHP Bin not found");
|
|
||||||
const binFolder = path.join(serverPath.serverPath, "bin");
|
|
||||||
if (await coreUtils.Extends.exists(binFolder)) await fs.rm(binFolder, {recursive: true});
|
|
||||||
await fs.mkdir(binFolder);
|
|
||||||
await pipeline(await oracleBucket.getFileStream(phpBin.name), createWriteStream(path.join(binFolder, "phpTmp")));
|
|
||||||
|
|
||||||
if (phpBin.name.endsWith(".tar.gz")) {
|
|
||||||
await tar.extract({
|
|
||||||
file: path.join(binFolder, "phpTmp"),
|
|
||||||
cwd: binFolder
|
|
||||||
});
|
|
||||||
} else if (phpBin.name.endsWith(".zip")) {
|
|
||||||
await promisify((new AdmZip(path.join(binFolder, "phpTmp"))).extractAllToAsync)(binFolder, true, true);
|
|
||||||
}
|
|
||||||
await fs.rm(path.join(binFolder, "phpTmp"));
|
|
||||||
|
|
||||||
const rel = await (await coreUtils.http.Github.GithubManeger("pmmp", "PocketMine-MP")).getRelease();
|
|
||||||
const relData = version.trim().toLowerCase() === "latest" ? rel.at(0) : rel.find((v) => v.tag_name === version.trim());
|
|
||||||
if (!relData) throw new Error("Version not found");
|
|
||||||
const phpAsset = relData.assets.find((a) => a.name.endsWith(".phar"))?.browser_download_url;
|
|
||||||
if (!phpAsset) throw new Error("PHP asset not found");
|
|
||||||
await coreUtils.http.large.saveFile({url: phpAsset, path: path.join(serverPath.serverPath, "PocketMine-MP.phar")});
|
|
||||||
|
|
||||||
return {
|
|
||||||
version: relData.tag_name,
|
|
||||||
releaseDate: new Date(relData.published_at),
|
|
||||||
release: (relData.prerelease ? "preview" : "stable") as "preview"|"stable",
|
|
||||||
url: phpAsset,
|
|
||||||
phpBin: phpBin.name,
|
|
||||||
};
|
|
||||||
} else if (options?.variant === "Powernukkit") {
|
|
||||||
if (!version) version = "latest";
|
|
||||||
const versions = await coreUtils.http.jsonRequest<{version: string, mcpeVersion: string, date: string, url: string, variantType: "snapshot"|"stable"}[]>("https://mcpeversion-static.sirherobrine23.org/powernukkit/all.json").then(data => data.body);
|
|
||||||
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim() || v.mcpeVersion === version.trim());
|
|
||||||
if (!versionData) throw new Error("Version not found");
|
|
||||||
const url = versionData.url;
|
|
||||||
if (!url) throw new Error("Platform not supported");
|
|
||||||
await coreUtils.http.large.saveFile({url, path: path.join(serverPath.serverPath, "server.jar")});
|
|
||||||
return {
|
|
||||||
version: versionData.version,
|
|
||||||
mcpeVersion: versionData.mcpeVersion,
|
|
||||||
variantType: versionData.variantType,
|
|
||||||
releaseDate: new Date(versionData.date),
|
|
||||||
url,
|
|
||||||
};
|
|
||||||
} else if (options?.variant === "Cloudbust") {
|
|
||||||
await coreUtils.http.large.saveFile({
|
|
||||||
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
|
||||||
path: path.join(serverPath.serverPath, "server.jar")
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
version: "bleeding",
|
|
||||||
releaseDate: new Date(),
|
|
||||||
release: "preview",
|
|
||||||
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (!version) version = "latest";
|
|
||||||
const versions = await coreUtils.http.jsonRequest<bedrockVersionJSON[]>("https://sirherobrine23.github.io/BedrockFetch/all.json").then(data => data.body);
|
|
||||||
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim());
|
|
||||||
if (!versionData) throw new Error("Version not found");
|
|
||||||
let currentPlatform = process.platform;
|
|
||||||
if (currentPlatform === "android") currentPlatform = "linux";
|
|
||||||
const url = versionData.url[currentPlatform]?.[process.arch];
|
|
||||||
if (!url) throw new Error("Platform not supported");
|
|
||||||
(await coreUtils.http.large.admZip(url)).zip.extractAllTo(serverPath.serverPath, true, true);
|
|
||||||
return {
|
|
||||||
version: versionData.version,
|
|
||||||
releaseDate: new Date(versionData.date),
|
|
||||||
release: versionData.release ?? "stable",
|
|
||||||
url: url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function startServer(options?: bedrockRootOption) {
|
|
||||||
// Bad fix options
|
|
||||||
options = {variant: "oficial", ...options};
|
|
||||||
const serverPath = await platformPathID("bedrock", options);
|
|
||||||
// Server Object
|
|
||||||
const serverExec: serverConfig = {
|
|
||||||
exec: {
|
|
||||||
cwd: serverPath.serverPath,
|
|
||||||
},
|
|
||||||
actions: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options?.variant === "Pocketmine-PMMP") {
|
|
||||||
serverExec.exec.exec = await getPHPBin();
|
|
||||||
serverExec.exec.args = ["PocketMine-MP.phar", "--no-wizard"];
|
|
||||||
serverExec.actions = {
|
|
||||||
stopServer(child_process) {
|
|
||||||
child_process.stdin.write("stop\n");
|
|
||||||
},
|
|
||||||
onStart(lineData, fnRegister) {
|
|
||||||
if (!(lineData.includes("INFO") && lineData.includes("Done") && lineData.includes("help"))) return;
|
|
||||||
const doneStart = new Date();
|
|
||||||
fnRegister({
|
|
||||||
serverAvaible: doneStart,
|
|
||||||
bootUp: runStart.getTime() - doneStart.getTime()
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else if (options?.variant === "Powernukkit" || options?.variant === "Cloudbust") {
|
|
||||||
serverExec.exec.exec = "java";
|
|
||||||
serverExec.exec.args = [
|
|
||||||
"-XX:+UseG1GC",
|
|
||||||
"-XX:+ParallelRefProcEnabled",
|
|
||||||
"-XX:MaxGCPauseMillis=200",
|
|
||||||
"-XX:+UnlockExperimentalVMOptions",
|
|
||||||
"-XX:+DisableExplicitGC",
|
|
||||||
"-XX:+AlwaysPreTouch",
|
|
||||||
"-XX:G1NewSizePercent=30",
|
|
||||||
"-XX:G1MaxNewSizePercent=40",
|
|
||||||
"-XX:G1HeapRegionSize=8M",
|
|
||||||
"-XX:G1ReservePercent=20",
|
|
||||||
"-XX:G1HeapWastePercent=5",
|
|
||||||
"-XX:G1MixedGCCountTarget=4",
|
|
||||||
"-XX:InitiatingHeapOccupancyPercent=15",
|
|
||||||
"-XX:G1MixedGCLiveThresholdPercent=90",
|
|
||||||
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
|
||||||
"-XX:SurvivorRatio=32",
|
|
||||||
"-XX:+PerfDisableSharedMem",
|
|
||||||
"-XX:MaxTenuringThreshold=1",
|
|
||||||
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
|
||||||
"-Daikars.new.flags=true",
|
|
||||||
"-jar", "server.jar"
|
|
||||||
];
|
|
||||||
serverExec.actions = {
|
|
||||||
stopServer(child_process) {
|
|
||||||
child_process.stdin.write("stop\n");
|
|
||||||
},
|
|
||||||
onStart(lineData, fnRegister) {
|
|
||||||
if (!(lineData.includes("INFO") && lineData.includes("Done") && lineData.includes("help"))) return;
|
|
||||||
const doneStart = new Date();
|
|
||||||
fnRegister({
|
|
||||||
serverAvaible: doneStart,
|
|
||||||
bootUp: runStart.getTime() - doneStart.getTime()
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (process.platform === "win32") serverExec.exec.exec = "bedrock_server.exe";
|
|
||||||
else if (process.platform === "darwin") throw new Error("MacOS is not supported, run in Docker or Virtual Machine");
|
|
||||||
else {
|
|
||||||
serverExec.exec.exec = path.join(serverPath.serverPath, "bedrock_server");
|
|
||||||
serverExec.exec.env = {
|
|
||||||
LD_LIBRARY_PATH: serverPath.serverPath
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if ((["android", "linux"]).includes(process.platform) && process.arch !== "x64") {
|
|
||||||
const exec = serverExec.exec.exec;
|
|
||||||
serverExec.exec.exec = undefined;
|
|
||||||
for (const command of hostArchEmulate) {
|
|
||||||
if (await childPromisses.commandExists(command, true)) {
|
|
||||||
serverExec.exec.args = [exec];
|
|
||||||
serverExec.exec.exec = command;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!serverExec.exec.exec) throw new Error("No emulator found for this platform");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const startTest = /\[.*\]\s+Server\s+started\./;
|
|
||||||
// Server actions
|
|
||||||
serverExec.actions = {
|
|
||||||
stopServer(child_process) {
|
|
||||||
child_process.stdin.write("stop\n");
|
|
||||||
},
|
|
||||||
onStart(lineData, fnRegister) {if (startTest.test(lineData)) fnRegister({serverAvaible: new Date()});},
|
|
||||||
playerActions(lineData, fnRegister) {
|
|
||||||
const playerActionsV1 = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/;
|
|
||||||
const newPlayerActions = /\[.*INFO\]\s+Player\s+(Spawned|connected|disconnected):\s+([\s\S\w]+)\s+(xuid:\s+([0-9]+))?/;
|
|
||||||
const connectTime = new Date();
|
|
||||||
if (!(newPlayerActions.test(lineData)||playerActionsV1.test(lineData))) return;
|
|
||||||
let playerName: string, action: string, xuid: string;
|
|
||||||
if (newPlayerActions.test(lineData)) {
|
|
||||||
const [, actionV2,, playerNameV2,, xuidV2] = lineData.match(newPlayerActions);
|
|
||||||
playerName = playerNameV2;
|
|
||||||
action = actionV2;
|
|
||||||
xuid = xuidV2;
|
|
||||||
} else {
|
|
||||||
const [, actionV1,, playerNameV1, xuidV1] = lineData.match(newPlayerActions);
|
|
||||||
playerName = playerNameV1;
|
|
||||||
action = actionV1;
|
|
||||||
xuid = xuidV1;
|
|
||||||
}
|
|
||||||
fnRegister({
|
|
||||||
player: playerName,
|
|
||||||
action: action === "Spawned" ? "spawned" : action === "connected" ? "join" : "leave",
|
|
||||||
actionDate: connectTime,
|
|
||||||
sessionID: serverPath.id,
|
|
||||||
more: {
|
|
||||||
xuid
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const runStart = new Date();
|
|
||||||
return createServerManeger(serverExec);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { pathOptions } from "../serverManeger.js";
|
|
||||||
|
|
||||||
export type javaRootOption = pathOptions & {
|
|
||||||
variant?: "oficial"|"Spigot"|"Paper"|"Purpur",
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function installServer(options?: javaRootOption) {
|
|
||||||
options = {variant: "oficial", ...options};
|
|
||||||
if (options?.variant === "Spigot") {
|
|
||||||
} else if (options?.variant === "Paper") {
|
|
||||||
} else if (options?.variant === "Purpur") {
|
|
||||||
} else {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default startServer;
|
|
||||||
export async function startServer(options?: javaRootOption) {}
|
|
@ -1,216 +0,0 @@
|
|||||||
import { createInterface as readline } from "node:readline";
|
|
||||||
import { promises as fs } from "node:fs";
|
|
||||||
import child_process from "node:child_process";
|
|
||||||
import { Cloud, Extends as extendFs } from "@sirherobrine23/coreutils";
|
|
||||||
import crypto from "node:crypto";
|
|
||||||
import path from "node:path";
|
|
||||||
import os from "node:os";
|
|
||||||
import EventEmitter from "node:events";
|
|
||||||
|
|
||||||
export type pathOptions = {
|
|
||||||
id?: "default"|string,
|
|
||||||
newId?: boolean,
|
|
||||||
withBuildFolder?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
export let bdsRoot = process.env.BDS_HOME?(process.env.BDS_HOME.startsWith("~")?process.env.BDS_HOME.replace("~", os.homedir()):process.env.BDS_HOME):path.join(os.homedir(), ".bdsManeger");
|
|
||||||
export async function platformPathID(platform: "bedrock"|"java", options?: pathOptions) {
|
|
||||||
if (!(["bedrock", "java"].includes(platform))) throw new Error("Invalid platform target");
|
|
||||||
options = {id: "default", ...options};
|
|
||||||
const platformRoot = path.join(bdsRoot, platform);
|
|
||||||
if (!await extendFs.exists(platformRoot)) await fs.mkdir(platformRoot, {recursive: true});
|
|
||||||
if (!options) options = {};
|
|
||||||
|
|
||||||
// Create if not exists
|
|
||||||
const foldersAndLink = await fs.readdir(platformRoot);
|
|
||||||
if (foldersAndLink.length === 0) options.newId = true;
|
|
||||||
if (options.newId) {
|
|
||||||
options.id = crypto.randomBytes(16).toString("hex");
|
|
||||||
fs.mkdir(path.join(platformRoot, options.id), {recursive: true});
|
|
||||||
if (await extendFs.exists(path.join(platformRoot, "default"))) await fs.unlink(path.join(platformRoot, "default"));
|
|
||||||
await fs.symlink(path.join(platformRoot, options.id), path.join(platformRoot, "default"));
|
|
||||||
} else if (!await extendFs.exists(path.join(platformRoot, options.id))) throw new Error("Folder ID not created!");
|
|
||||||
|
|
||||||
// Get real id
|
|
||||||
if (!(/^[A-Za-z0-9]*$/).test(options.id)) throw new Error("Invalid Platform ID");
|
|
||||||
if (options?.id === "default") options.id = path.basename(await fs.realpath(path.join(platformRoot, options.id)).catch(async () => (await fs.readdir(platformRoot)).sort().at(0)));
|
|
||||||
|
|
||||||
// Mount Paths
|
|
||||||
const serverRoot = path.join(platformRoot, options.id);
|
|
||||||
const serverPath = path.join(serverRoot, "server");
|
|
||||||
const hooksPath = path.join(serverRoot, "hooks");
|
|
||||||
const backupPath = path.join(serverRoot, "backup");
|
|
||||||
const logsPath = path.join(serverRoot, "logs");
|
|
||||||
let buildFolder: string;
|
|
||||||
if (options?.withBuildFolder) buildFolder = path.join(serverRoot, "build");
|
|
||||||
|
|
||||||
// Create folder if not exists
|
|
||||||
if (!(await extendFs.exists(serverRoot))) await fs.mkdir(serverRoot, {recursive: true});
|
|
||||||
if (!(await extendFs.exists(serverPath))) await fs.mkdir(serverPath, {recursive: true});
|
|
||||||
if (!(await extendFs.exists(hooksPath))) await fs.mkdir(hooksPath, {recursive: true});
|
|
||||||
if (!(await extendFs.exists(backupPath))) await fs.mkdir(backupPath, {recursive: true});
|
|
||||||
if (!(await extendFs.exists(logsPath))) await fs.mkdir(logsPath, {recursive: true});
|
|
||||||
if (buildFolder && !(await extendFs.exists(buildFolder))) await fs.mkdir(buildFolder, {recursive: true});
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: options?.id,
|
|
||||||
serverRoot,
|
|
||||||
serverPath,
|
|
||||||
hooksPath,
|
|
||||||
backupPath,
|
|
||||||
logsPath,
|
|
||||||
buildFolder,
|
|
||||||
platformIDs: foldersAndLink
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type playerAction = ({action: "join"|"spawned"|"leave"}|{
|
|
||||||
action: "kick"|"ban",
|
|
||||||
reason?: string,
|
|
||||||
by?: string
|
|
||||||
}) & {
|
|
||||||
player: string,
|
|
||||||
actionDate: Date,
|
|
||||||
sessionID: string
|
|
||||||
more?: any,
|
|
||||||
latestAction?: playerAction
|
|
||||||
}
|
|
||||||
|
|
||||||
export type serverConfig = {
|
|
||||||
exec: {
|
|
||||||
exec?: string,
|
|
||||||
args?: string[],
|
|
||||||
cwd?: string,
|
|
||||||
env?: NodeJS.ProcessEnv & {[key: string]: string},
|
|
||||||
},
|
|
||||||
actions?: {
|
|
||||||
stopServer?: (child_process: child_process.ChildProcess) => void,
|
|
||||||
onStart?: (lineData: string, fnRegister: (data?: {serverAvaible?: Date, bootUp?: number}) => void) => void,
|
|
||||||
playerActions?: (lineData: string, fnRegister: (data: playerAction) => void) => void,
|
|
||||||
},
|
|
||||||
maneger?: {
|
|
||||||
backup?: {
|
|
||||||
folderWatch: {local: string, remoteParent?: string}[],
|
|
||||||
} & ({
|
|
||||||
cloud: "google",
|
|
||||||
config: Cloud.googleOptions
|
|
||||||
}|{
|
|
||||||
cloud: "oracle_bucket",
|
|
||||||
config: Cloud.oracleOptions
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
declare class serverManeger extends EventEmitter {
|
|
||||||
on(event: "error", fn: (lineLog: any) => void): this;
|
|
||||||
once(event: "error", fn: (lineLog: any) => void): this;
|
|
||||||
emit(event: "error", data: any): boolean;
|
|
||||||
|
|
||||||
on(event: "log", fn: (lineLog: string) => void): this;
|
|
||||||
once(event: "log", fn: (lineLog: string) => void): this;
|
|
||||||
emit(event: "log", data: string): boolean;
|
|
||||||
|
|
||||||
on(event: "rawLog", fn: (raw: any) => void): this;
|
|
||||||
once(event: "rawLog", fn: (raw: any) => void): this;
|
|
||||||
emit(event: "rawLog", data: any): boolean;
|
|
||||||
|
|
||||||
// Player actions
|
|
||||||
on(event: "playerAction", fn: (playerAction: playerAction) => void): this;
|
|
||||||
once(event: "playerAction", fn: (playerAction: playerAction) => void): this;
|
|
||||||
emit(event: "playerAction", data: playerAction): boolean;
|
|
||||||
|
|
||||||
// Server started
|
|
||||||
on(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
|
|
||||||
once(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
|
|
||||||
emit(event: "serverStarted", data: {serverAvaible: Date, bootUp: number}): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createServerManeger(serverOptions: serverConfig): Promise<serverManeger> {
|
|
||||||
const internalStops: (() => any|void)[] = [];
|
|
||||||
if (serverOptions?.maneger?.backup) {
|
|
||||||
const { folderWatch, cloud } = serverOptions?.maneger?.backup;
|
|
||||||
if (cloud === "oracle_bucket") {
|
|
||||||
const { config } = serverOptions?.maneger?.backup;
|
|
||||||
const ociClient = await Cloud.oracleBucket(config);
|
|
||||||
for await (const folder of folderWatch) {
|
|
||||||
ociClient;
|
|
||||||
folder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const serverExec = child_process.execFile(serverOptions.exec.exec, serverOptions.exec.args ?? [], {
|
|
||||||
cwd: serverOptions.exec.cwd,
|
|
||||||
windowsHide: true,
|
|
||||||
maxBuffer: Infinity,
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
...serverOptions.exec.env
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const playerActions: playerAction[] = [];
|
|
||||||
const internalEvent = new class serverManeger extends EventEmitter {
|
|
||||||
async stopServer() {
|
|
||||||
const stopServer = serverOptions.actions?.stopServer ?? ((child_process) => child_process.kill("SIGKILL"));
|
|
||||||
await Promise.resolve(stopServer(serverExec)).catch(err => internalEvent.emit("error", err));
|
|
||||||
internalStops.forEach((fn) => Promise.resolve().then(() => fn()).catch(err => internalEvent.emit("error", err)));
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlayers() {
|
|
||||||
return playerActions ?? [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
serverExec.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
|
||||||
const stdoutReadline = readline({input: serverExec.stdout});
|
|
||||||
stdoutReadline.on("line", (line) => internalEvent.emit("log", line));
|
|
||||||
stdoutReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
|
||||||
serverExec.stdout.on("data", (data) => internalEvent.emit("rawLog", data));
|
|
||||||
|
|
||||||
const stderrReadline = readline({input: serverExec.stderr});
|
|
||||||
stderrReadline.on("line", (line) => internalEvent.emit("log", line));
|
|
||||||
stderrReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
|
||||||
serverExec.stderr.on("data", (data) => internalEvent.emit("rawLog", data));
|
|
||||||
|
|
||||||
// Server start
|
|
||||||
if (serverOptions.actions?.onStart) {
|
|
||||||
const serverStartFN = serverOptions.actions.onStart;
|
|
||||||
let lock = false;
|
|
||||||
const started = new Date();
|
|
||||||
async function register(data?: {serverAvaible?: Date, bootUp?: number}) {
|
|
||||||
if (lock) return;
|
|
||||||
const eventData = {
|
|
||||||
serverAvaible: data?.serverAvaible ?? new Date(),
|
|
||||||
bootUp: data?.bootUp ?? new Date().getTime() - started.getTime()
|
|
||||||
};
|
|
||||||
internalEvent.emit("serverStarted", eventData);
|
|
||||||
lock = true;
|
|
||||||
stderrReadline.removeListener("line", register);
|
|
||||||
stdoutReadline.removeListener("line", register);
|
|
||||||
// emit and remove new listener for serverStarted
|
|
||||||
internalEvent.removeAllListeners("serverStarted");
|
|
||||||
internalEvent.prependListener("serverStarted", () => {
|
|
||||||
internalEvent.emit("serverStarted", eventData);
|
|
||||||
internalEvent.removeAllListeners("serverStarted");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
stdoutReadline.on("line", (line) => serverStartFN(line, register));
|
|
||||||
stderrReadline.on("line", (line) => serverStartFN(line, register));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Player actions
|
|
||||||
if (serverOptions.actions?.playerActions) {
|
|
||||||
const playerFn = serverOptions.actions.playerActions;
|
|
||||||
const registerData = (data: playerAction) => {
|
|
||||||
const player = playerActions.find((player) => player.player === data.player);
|
|
||||||
if (!player) playerActions.push(data);
|
|
||||||
else {
|
|
||||||
data.latestAction = player;
|
|
||||||
playerActions[playerActions.indexOf(player)] = data;
|
|
||||||
}
|
|
||||||
internalEvent.emit("playerAction", data);
|
|
||||||
}
|
|
||||||
stdoutReadline.on("line", (line) => playerFn(line, registerData));
|
|
||||||
stderrReadline.on("line", (line) => playerFn(line, registerData));
|
|
||||||
}
|
|
||||||
|
|
||||||
return internalEvent;
|
|
||||||
}
|
|
@ -4,22 +4,21 @@
|
|||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
|
"isolatedModules": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"lib": ["ES6"]
|
"lib": [
|
||||||
|
"ESNext"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": [
|
|
||||||
"src/**/*"
|
|
||||||
],
|
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"src/**/*.test.ts",
|
"**/*.test.ts"
|
||||||
"node_modules/**/*"
|
|
||||||
],
|
],
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"esm": true
|
"esm": true
|
||||||
|
Reference in New Issue
Block a user