@dimzxzzx07/mc-headless 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -0
- package/dist/core/ConfigHandler.d.ts +12 -0
- package/dist/core/ConfigHandler.d.ts.map +1 -0
- package/dist/core/ConfigHandler.js +118 -0
- package/dist/core/ConfigHandler.js.map +1 -0
- package/dist/core/JavaChecker.d.ts +8 -0
- package/dist/core/JavaChecker.d.ts.map +1 -0
- package/dist/core/JavaChecker.js +68 -0
- package/dist/core/JavaChecker.js.map +1 -0
- package/dist/core/MinecraftServer.d.ts +28 -0
- package/dist/core/MinecraftServer.d.ts.map +1 -0
- package/dist/core/MinecraftServer.js +312 -0
- package/dist/core/MinecraftServer.js.map +1 -0
- package/dist/core/ServerManager.d.ts +30 -0
- package/dist/core/ServerManager.d.ts.map +1 -0
- package/dist/core/ServerManager.js +203 -0
- package/dist/core/ServerManager.js.map +1 -0
- package/dist/engines/Downloader.d.ts +16 -0
- package/dist/engines/Downloader.d.ts.map +1 -0
- package/dist/engines/Downloader.js +159 -0
- package/dist/engines/Downloader.js.map +1 -0
- package/dist/engines/FabricEngine.d.ts +11 -0
- package/dist/engines/FabricEngine.d.ts.map +1 -0
- package/dist/engines/FabricEngine.js +70 -0
- package/dist/engines/FabricEngine.js.map +1 -0
- package/dist/engines/ForgeEngine.d.ts +11 -0
- package/dist/engines/ForgeEngine.d.ts.map +1 -0
- package/dist/engines/ForgeEngine.js +84 -0
- package/dist/engines/ForgeEngine.js.map +1 -0
- package/dist/engines/PaperEngine.d.ts +11 -0
- package/dist/engines/PaperEngine.d.ts.map +1 -0
- package/dist/engines/PaperEngine.js +88 -0
- package/dist/engines/PaperEngine.js.map +1 -0
- package/dist/engines/ServerEngine.d.ts +10 -0
- package/dist/engines/ServerEngine.d.ts.map +1 -0
- package/dist/engines/ServerEngine.js +3 -0
- package/dist/engines/ServerEngine.js.map +1 -0
- package/dist/engines/VanillaEngine.d.ts +11 -0
- package/dist/engines/VanillaEngine.d.ts.map +1 -0
- package/dist/engines/VanillaEngine.js +70 -0
- package/dist/engines/VanillaEngine.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/platforms/BedrockServer.d.ts +30 -0
- package/dist/platforms/BedrockServer.d.ts.map +1 -0
- package/dist/platforms/BedrockServer.js +301 -0
- package/dist/platforms/BedrockServer.js.map +1 -0
- package/dist/platforms/GeyserBridge.d.ts +9 -0
- package/dist/platforms/GeyserBridge.d.ts.map +1 -0
- package/dist/platforms/GeyserBridge.js +98 -0
- package/dist/platforms/GeyserBridge.js.map +1 -0
- package/dist/platforms/JavaServer.d.ts +27 -0
- package/dist/platforms/JavaServer.d.ts.map +1 -0
- package/dist/platforms/JavaServer.js +237 -0
- package/dist/platforms/JavaServer.js.map +1 -0
- package/dist/types/index.d.ts +80 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/FileUtils.d.ts +20 -0
- package/dist/utils/FileUtils.d.ts.map +1 -0
- package/dist/utils/FileUtils.js +172 -0
- package/dist/utils/FileUtils.js.map +1 -0
- package/dist/utils/Logger.d.ts +26 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +91 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/PropertiesParser.d.ts +7 -0
- package/dist/utils/PropertiesParser.d.ts.map +1 -0
- package/dist/utils/PropertiesParser.js +124 -0
- package/dist/utils/PropertiesParser.js.map +1 -0
- package/dist/utils/SystemDetector.d.ts +14 -0
- package/dist/utils/SystemDetector.d.ts.map +1 -0
- package/dist/utils/SystemDetector.js +152 -0
- package/dist/utils/SystemDetector.js.map +1 -0
- package/package.json +51 -0
- package/src/core/ConfigHandler.ts +136 -0
- package/src/core/JavaChecker.ts +71 -0
- package/src/core/MinecraftServer.ts +326 -0
- package/src/core/ServerManager.ts +196 -0
- package/src/engines/Downloader.ts +144 -0
- package/src/engines/FabricEngine.ts +49 -0
- package/src/engines/ForgeEngine.ts +65 -0
- package/src/engines/PaperEngine.ts +68 -0
- package/src/engines/ServerEngine.ts +10 -0
- package/src/engines/VanillaEngine.ts +49 -0
- package/src/index.ts +83 -0
- package/src/platforms/BedrockServer.ts +311 -0
- package/src/platforms/GeyserBridge.ts +83 -0
- package/src/platforms/JavaServer.ts +241 -0
- package/src/scripts/detect-os.sh +56 -0
- package/src/scripts/install-java.sh +38 -0
- package/src/types/index.ts +89 -0
- package/src/utils/FileUtils.ts +162 -0
- package/src/utils/Logger.ts +97 -0
- package/src/utils/PropertiesParser.ts +126 -0
- package/src/utils/SystemDetector.ts +127 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "Installing Java for Minecraft Server..."
|
|
4
|
+
|
|
5
|
+
if [ -f /etc/os-release ]; then
|
|
6
|
+
. /etc/os-release
|
|
7
|
+
OS=$ID
|
|
8
|
+
elif [ -n "$TERMUX_VERSION" ]; then
|
|
9
|
+
OS="termux"
|
|
10
|
+
else
|
|
11
|
+
OS="unknown"
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
case $OS in
|
|
15
|
+
ubuntu|debian)
|
|
16
|
+
apt update
|
|
17
|
+
apt install -y openjdk-17-jre-headless
|
|
18
|
+
;;
|
|
19
|
+
centos|rhel)
|
|
20
|
+
yum install -y java-17-openjdk-headless
|
|
21
|
+
;;
|
|
22
|
+
fedora)
|
|
23
|
+
dnf install -y java-17-openjdk-headless
|
|
24
|
+
;;
|
|
25
|
+
arch)
|
|
26
|
+
pacman -S --noconfirm jre17-openjdk-headless
|
|
27
|
+
;;
|
|
28
|
+
termux)
|
|
29
|
+
pkg install -y openjdk-17
|
|
30
|
+
;;
|
|
31
|
+
*)
|
|
32
|
+
echo "Unsupported OS. Please install Java 17 manually."
|
|
33
|
+
exit 1
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
|
|
37
|
+
echo "Java installation completed."
|
|
38
|
+
java -version
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export type Platform = 'java' | 'bedrock' | 'all';
|
|
2
|
+
export type ServerType = 'paper' | 'purpur' | 'vanilla' | 'spigot' | 'forge' | 'fabric';
|
|
3
|
+
export type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard';
|
|
4
|
+
export type Gamemode = 'survival' | 'creative' | 'adventure' | 'spectator';
|
|
5
|
+
|
|
6
|
+
export interface MinecraftConfig {
|
|
7
|
+
platform: Platform;
|
|
8
|
+
version: string;
|
|
9
|
+
type: ServerType;
|
|
10
|
+
autoAcceptEula: boolean;
|
|
11
|
+
|
|
12
|
+
memory: {
|
|
13
|
+
init: string;
|
|
14
|
+
max: string;
|
|
15
|
+
useAikarsFlags: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
network: {
|
|
19
|
+
port: number;
|
|
20
|
+
bedrockPort?: number;
|
|
21
|
+
ip: string;
|
|
22
|
+
onlineMode: boolean;
|
|
23
|
+
motd: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
world: {
|
|
27
|
+
difficulty: Difficulty;
|
|
28
|
+
hardcore: boolean;
|
|
29
|
+
gamemode: Gamemode;
|
|
30
|
+
seed?: string;
|
|
31
|
+
maxPlayers: number;
|
|
32
|
+
viewDistance: number;
|
|
33
|
+
levelName: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
folders: {
|
|
37
|
+
addons: string;
|
|
38
|
+
mods: string;
|
|
39
|
+
plugins: string;
|
|
40
|
+
world: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
autoRestart: boolean;
|
|
44
|
+
backup: {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
interval: string;
|
|
47
|
+
path: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ServerInfo {
|
|
52
|
+
pid: number;
|
|
53
|
+
ip: string;
|
|
54
|
+
port: number;
|
|
55
|
+
bedrockPort?: number;
|
|
56
|
+
version: string;
|
|
57
|
+
type: ServerType;
|
|
58
|
+
platform: Platform;
|
|
59
|
+
players: number;
|
|
60
|
+
maxPlayers: number;
|
|
61
|
+
uptime: number;
|
|
62
|
+
memory: {
|
|
63
|
+
used: number;
|
|
64
|
+
max: number;
|
|
65
|
+
};
|
|
66
|
+
status: 'starting' | 'running' | 'stopping' | 'stopped' | 'crashed';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface DownloadInfo {
|
|
70
|
+
url: string;
|
|
71
|
+
fileName: string;
|
|
72
|
+
size?: number;
|
|
73
|
+
sha1?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface BackupInfo {
|
|
77
|
+
path: string;
|
|
78
|
+
size: number;
|
|
79
|
+
createdAt: Date;
|
|
80
|
+
type: 'full' | 'world' | 'plugins';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface Player {
|
|
84
|
+
name: string;
|
|
85
|
+
uuid: string;
|
|
86
|
+
ip: string;
|
|
87
|
+
ping: number;
|
|
88
|
+
connectedAt: Date;
|
|
89
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import * as fs from 'fs-extra';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as tar from 'tar';
|
|
4
|
+
const AdmZip = require('adm-zip');
|
|
5
|
+
import { Logger } from './Logger';
|
|
6
|
+
|
|
7
|
+
export class FileUtils {
|
|
8
|
+
private static logger = Logger.getInstance();
|
|
9
|
+
|
|
10
|
+
public static async ensureDir(dir: string): Promise<void> {
|
|
11
|
+
await fs.ensureDir(dir);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static async writeFile(filePath: string, data: string | Buffer): Promise<void> {
|
|
15
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
16
|
+
await fs.writeFile(filePath, data);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static async readFile(filePath: string): Promise<Buffer> {
|
|
20
|
+
return fs.readFile(filePath);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public static async fileExists(filePath: string): Promise<boolean> {
|
|
24
|
+
return fs.pathExists(filePath);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static async deleteFile(filePath: string): Promise<void> {
|
|
28
|
+
if (await fs.pathExists(filePath)) {
|
|
29
|
+
await fs.remove(filePath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public static async deleteFolder(folderPath: string): Promise<void> {
|
|
34
|
+
if (await fs.pathExists(folderPath)) {
|
|
35
|
+
await fs.remove(folderPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static async copyFile(source: string, destination: string): Promise<void> {
|
|
40
|
+
await fs.ensureDir(path.dirname(destination));
|
|
41
|
+
await fs.copy(source, destination);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public static async moveFile(source: string, destination: string): Promise<void> {
|
|
45
|
+
await fs.ensureDir(path.dirname(destination));
|
|
46
|
+
await fs.move(source, destination, { overwrite: true });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static async listFiles(dir: string, pattern?: RegExp): Promise<string[]> {
|
|
50
|
+
if (!await fs.pathExists(dir)) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const files = await fs.readdir(dir);
|
|
55
|
+
|
|
56
|
+
if (pattern) {
|
|
57
|
+
return files.filter(f => pattern.test(f));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return files;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static async getFileSize(filePath: string): Promise<number> {
|
|
64
|
+
const stat = await fs.stat(filePath);
|
|
65
|
+
return stat.size;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public static async extractZip(zipPath: string, destPath: string): Promise<void> {
|
|
69
|
+
this.logger.debug(`Extracting ${zipPath} to ${destPath}`);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const zip = new AdmZip(zipPath);
|
|
73
|
+
zip.extractAllTo(destPath, true);
|
|
74
|
+
this.logger.debug('Extraction complete');
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logger.error('Failed to extract zip:', error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public static async extractTar(tarPath: string, destPath: string): Promise<void> {
|
|
82
|
+
this.logger.debug(`Extracting ${tarPath} to ${destPath}`);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await tar.extract({
|
|
86
|
+
file: tarPath,
|
|
87
|
+
cwd: destPath
|
|
88
|
+
});
|
|
89
|
+
this.logger.debug('Extraction complete');
|
|
90
|
+
} catch (error) {
|
|
91
|
+
this.logger.error('Failed to extract tar:', error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public static async createBackup(sourcePath: string, backupPath: string): Promise<void> {
|
|
97
|
+
this.logger.info(`Creating backup of ${sourcePath} to ${backupPath}`);
|
|
98
|
+
|
|
99
|
+
await fs.ensureDir(path.dirname(backupPath));
|
|
100
|
+
|
|
101
|
+
if (await fs.pathExists(sourcePath)) {
|
|
102
|
+
await fs.copy(sourcePath, backupPath);
|
|
103
|
+
const size = await this.getFileSize(backupPath);
|
|
104
|
+
this.logger.success(`Backup created: ${backupPath} (${size} bytes)`);
|
|
105
|
+
} else {
|
|
106
|
+
this.logger.warning(`Source path not found: ${sourcePath}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public static async writeProperties(filePath: string, properties: Record<string, any>): Promise<void> {
|
|
111
|
+
const lines: string[] = [];
|
|
112
|
+
|
|
113
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
114
|
+
if (value !== undefined && value !== null) {
|
|
115
|
+
lines.push(`${key}=${value}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await this.writeFile(filePath, lines.join('\n'));
|
|
120
|
+
this.logger.debug(`Properties written to ${filePath}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public static async readProperties(filePath: string): Promise<Record<string, string>> {
|
|
124
|
+
if (!await this.fileExists(filePath)) {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
129
|
+
const properties: Record<string, string> = {};
|
|
130
|
+
|
|
131
|
+
for (const line of content.split('\n')) {
|
|
132
|
+
const trimmed = line.trim();
|
|
133
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
134
|
+
const eq = trimmed.indexOf('=');
|
|
135
|
+
if (eq > 0) {
|
|
136
|
+
const key = trimmed.substring(0, eq).trim();
|
|
137
|
+
const value = trimmed.substring(eq + 1).trim();
|
|
138
|
+
properties[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return properties;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public static async ensureServerStructure(config: any): Promise<void> {
|
|
147
|
+
const folders = [
|
|
148
|
+
config.folders.addons,
|
|
149
|
+
config.folders.mods,
|
|
150
|
+
config.folders.plugins,
|
|
151
|
+
config.folders.world,
|
|
152
|
+
path.join(process.cwd(), 'logs'),
|
|
153
|
+
path.join(process.cwd(), 'backups')
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const folder of folders) {
|
|
157
|
+
await this.ensureDir(folder);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.logger.debug('Server structure created');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export enum LogLevel {
|
|
4
|
+
DEBUG = 0,
|
|
5
|
+
INFO = 1,
|
|
6
|
+
SUCCESS = 2,
|
|
7
|
+
WARNING = 3,
|
|
8
|
+
ERROR = 4,
|
|
9
|
+
NONE = 5
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Logger {
|
|
13
|
+
private static instance: Logger;
|
|
14
|
+
private logLevel: LogLevel = LogLevel.INFO;
|
|
15
|
+
private logFile: string | null = null;
|
|
16
|
+
private fs: any;
|
|
17
|
+
|
|
18
|
+
private constructor() {
|
|
19
|
+
try {
|
|
20
|
+
this.fs = require('fs-extra');
|
|
21
|
+
} catch {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static getInstance(): Logger {
|
|
25
|
+
if (!Logger.instance) {
|
|
26
|
+
Logger.instance = new Logger();
|
|
27
|
+
}
|
|
28
|
+
return Logger.instance;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public setLogLevel(level: LogLevel): void {
|
|
32
|
+
this.logLevel = level;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public setLogFile(filePath: string): void {
|
|
36
|
+
this.logFile = filePath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private log(level: LogLevel, message: string, ...args: any[]): void {
|
|
40
|
+
if (level < this.logLevel) return;
|
|
41
|
+
|
|
42
|
+
const timestamp = new Date().toISOString();
|
|
43
|
+
const levelName = LogLevel[level];
|
|
44
|
+
|
|
45
|
+
let coloredMessage = '';
|
|
46
|
+
switch (level) {
|
|
47
|
+
case LogLevel.DEBUG:
|
|
48
|
+
coloredMessage = chalk.gray(`[${timestamp}] [${levelName}] ${message}`);
|
|
49
|
+
break;
|
|
50
|
+
case LogLevel.INFO:
|
|
51
|
+
coloredMessage = chalk.cyan(`[${timestamp}] [${levelName}] ${message}`);
|
|
52
|
+
break;
|
|
53
|
+
case LogLevel.SUCCESS:
|
|
54
|
+
coloredMessage = chalk.green(`[${timestamp}] [${levelName}] ${message}`);
|
|
55
|
+
break;
|
|
56
|
+
case LogLevel.WARNING:
|
|
57
|
+
coloredMessage = chalk.yellow(`[${timestamp}] [${levelName}] ${message}`);
|
|
58
|
+
break;
|
|
59
|
+
case LogLevel.ERROR:
|
|
60
|
+
coloredMessage = chalk.red(`[${timestamp}] [${levelName}] ${message}`);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(coloredMessage, ...args);
|
|
65
|
+
|
|
66
|
+
if (this.logFile && this.fs) {
|
|
67
|
+
const logMessage = `[${timestamp}] [${levelName}] ${message} ${args.map(a => JSON.stringify(a)).join(' ')}\n`;
|
|
68
|
+
this.fs.appendFileSync(this.logFile, logMessage);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public debug(message: string, ...args: any[]): void {
|
|
73
|
+
this.log(LogLevel.DEBUG, message, ...args);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public info(message: string, ...args: any[]): void {
|
|
77
|
+
this.log(LogLevel.INFO, message, ...args);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public success(message: string, ...args: any[]): void {
|
|
81
|
+
this.log(LogLevel.SUCCESS, message, ...args);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public warning(message: string, ...args: any[]): void {
|
|
85
|
+
this.log(LogLevel.WARNING, message, ...args);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public error(message: string, ...args: any[]): void {
|
|
89
|
+
this.log(LogLevel.ERROR, message, ...args);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public banner(): void {
|
|
93
|
+
console.log(chalk.cyan(`
|
|
94
|
+
Mc Headless - Powered By Dimzxzzx07
|
|
95
|
+
`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export class PropertiesParser {
|
|
2
|
+
public static parse(content: string): Record<string, string> {
|
|
3
|
+
const properties: Record<string, string> = {};
|
|
4
|
+
const lines = content.split('\n');
|
|
5
|
+
|
|
6
|
+
for (const line of lines) {
|
|
7
|
+
const trimmed = line.trim();
|
|
8
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
9
|
+
const eqIndex = trimmed.indexOf('=');
|
|
10
|
+
if (eqIndex > 0) {
|
|
11
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
12
|
+
const value = trimmed.substring(eqIndex + 1).trim();
|
|
13
|
+
properties[key] = value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return properties;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static stringify(properties: Record<string, any>): string {
|
|
22
|
+
const lines: string[] = [];
|
|
23
|
+
|
|
24
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
25
|
+
if (value !== undefined && value !== null) {
|
|
26
|
+
lines.push(`${key}=${value}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return lines.join('\n');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public static generateServerProperties(config: any): Record<string, any> {
|
|
34
|
+
return {
|
|
35
|
+
'allow-flight': false,
|
|
36
|
+
'allow-nether': true,
|
|
37
|
+
'broadcast-console-to-ops': true,
|
|
38
|
+
'broadcast-rcon-to-ops': true,
|
|
39
|
+
'difficulty': config.world.difficulty,
|
|
40
|
+
'enable-command-block': false,
|
|
41
|
+
'enable-jmx-monitoring': false,
|
|
42
|
+
'enable-query': false,
|
|
43
|
+
'enable-rcon': false,
|
|
44
|
+
'enable-status': true,
|
|
45
|
+
'enforce-secure-profile': true,
|
|
46
|
+
'enforce-whitelist': false,
|
|
47
|
+
'entity-broadcast-range-percentage': 100,
|
|
48
|
+
'force-gamemode': false,
|
|
49
|
+
'function-permission-level': 2,
|
|
50
|
+
'gamemode': config.world.gamemode,
|
|
51
|
+
'generate-structures': true,
|
|
52
|
+
'generator-settings': '',
|
|
53
|
+
'hardcore': config.world.hardcore,
|
|
54
|
+
'hide-online-players': false,
|
|
55
|
+
'initial-disabled-packs': '',
|
|
56
|
+
'initial-enabled-packs': 'vanilla',
|
|
57
|
+
'level-name': config.world.levelName,
|
|
58
|
+
'level-seed': config.world.seed || '',
|
|
59
|
+
'level-type': 'minecraft\\:normal',
|
|
60
|
+
'max-chained-neighbor-updates': 1000000,
|
|
61
|
+
'max-players': config.world.maxPlayers,
|
|
62
|
+
'max-tick-time': 60000,
|
|
63
|
+
'max-world-size': 29999984,
|
|
64
|
+
'motd': config.network.motd,
|
|
65
|
+
'network-compression-threshold': 256,
|
|
66
|
+
'online-mode': config.network.onlineMode,
|
|
67
|
+
'op-permission-level': 4,
|
|
68
|
+
'player-idle-timeout': 0,
|
|
69
|
+
'prevent-proxy-connections': false,
|
|
70
|
+
'pvp': true,
|
|
71
|
+
'query.port': 25565,
|
|
72
|
+
'rate-limit': 0,
|
|
73
|
+
'rcon.password': '',
|
|
74
|
+
'rcon.port': 25575,
|
|
75
|
+
'require-resource-pack': false,
|
|
76
|
+
'resource-pack': '',
|
|
77
|
+
'resource-pack-id': '',
|
|
78
|
+
'resource-pack-prompt': '',
|
|
79
|
+
'resource-pack-sha1': '',
|
|
80
|
+
'server-ip': config.network.ip,
|
|
81
|
+
'server-port': config.network.port,
|
|
82
|
+
'simulation-distance': config.world.viewDistance,
|
|
83
|
+
'spawn-animals': true,
|
|
84
|
+
'spawn-monsters': true,
|
|
85
|
+
'spawn-npcs': true,
|
|
86
|
+
'spawn-protection': 16,
|
|
87
|
+
'sync-chunk-writes': true,
|
|
88
|
+
'text-filtering-config': '',
|
|
89
|
+
'use-native-transport': true,
|
|
90
|
+
'view-distance': config.world.viewDistance,
|
|
91
|
+
'white-list': false
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public static generateBedrockProperties(config: any): Record<string, any> {
|
|
96
|
+
return {
|
|
97
|
+
'server-name': config.network.motd.replace(/§./g, ''),
|
|
98
|
+
'gamemode': config.world.gamemode,
|
|
99
|
+
'difficulty': config.world.difficulty,
|
|
100
|
+
'allow-cheats': false,
|
|
101
|
+
'max-players': config.world.maxPlayers,
|
|
102
|
+
'online-mode': config.network.onlineMode,
|
|
103
|
+
'white-list': false,
|
|
104
|
+
'server-port': config.network.bedrockPort || 19132,
|
|
105
|
+
'server-portv6': 19133,
|
|
106
|
+
'level-name': config.world.levelName,
|
|
107
|
+
'level-seed': config.world.seed || '',
|
|
108
|
+
'level-type': 'DEFAULT',
|
|
109
|
+
'enable-query': true,
|
|
110
|
+
'enable-rcon': false,
|
|
111
|
+
'rcon-port': 25575,
|
|
112
|
+
'rcon-password': '',
|
|
113
|
+
'max-threads': 8,
|
|
114
|
+
'tick-distance': 4,
|
|
115
|
+
'default-player-permission-level': 'member',
|
|
116
|
+
'texturepack-required': false,
|
|
117
|
+
'content-log-file-enabled': false,
|
|
118
|
+
'compression-threshold': 1,
|
|
119
|
+
'server-authoritative-movement': 'server-auth',
|
|
120
|
+
'player-movement-score-threshold': 20,
|
|
121
|
+
'player-movement-distance-threshold': 0.3,
|
|
122
|
+
'player-movement-duration-threshold-in-ms': 500,
|
|
123
|
+
'correct-player-movement': false
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
|
|
4
|
+
export type OSType = 'linux' | 'darwin' | 'windows' | 'android' | 'unknown';
|
|
5
|
+
export type DistroType = 'ubuntu' | 'debian' | 'centos' | 'fedora' | 'arch' | 'termux' | 'unknown';
|
|
6
|
+
|
|
7
|
+
export class SystemDetector {
|
|
8
|
+
public static getOS(): OSType {
|
|
9
|
+
const platform = os.platform();
|
|
10
|
+
|
|
11
|
+
if (platform === 'linux') {
|
|
12
|
+
if (process.env.TERMUX_VERSION || process.env.PREFIX === '/data/data/com.termux/files/usr') {
|
|
13
|
+
return 'android';
|
|
14
|
+
}
|
|
15
|
+
return 'linux';
|
|
16
|
+
} else if (platform === 'darwin') {
|
|
17
|
+
return 'darwin';
|
|
18
|
+
} else if (platform === 'win32') {
|
|
19
|
+
return 'windows';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return 'unknown';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static getDistro(): DistroType {
|
|
26
|
+
const osType = this.getOS();
|
|
27
|
+
|
|
28
|
+
if (osType === 'android') {
|
|
29
|
+
return 'termux';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (osType === 'linux') {
|
|
33
|
+
try {
|
|
34
|
+
const osRelease = execSync('cat /etc/os-release').toString();
|
|
35
|
+
|
|
36
|
+
if (osRelease.includes('Ubuntu')) return 'ubuntu';
|
|
37
|
+
if (osRelease.includes('Debian')) return 'debian';
|
|
38
|
+
if (osRelease.includes('CentOS')) return 'centos';
|
|
39
|
+
if (osRelease.includes('Fedora')) return 'fedora';
|
|
40
|
+
if (osRelease.includes('Arch')) return 'arch';
|
|
41
|
+
} catch {}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return 'unknown';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public static hasJava(): boolean {
|
|
48
|
+
try {
|
|
49
|
+
execSync('java -version', { stdio: 'ignore' });
|
|
50
|
+
return true;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public static getJavaVersion(): string | null {
|
|
57
|
+
try {
|
|
58
|
+
const output = execSync('java -version 2>&1').toString();
|
|
59
|
+
const match = output.match(/version "([^"]+)"/);
|
|
60
|
+
return match ? match[1] : null;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public static getArch(): string {
|
|
67
|
+
return os.arch();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public static getTotalMemory(): number {
|
|
71
|
+
return os.totalmem() / (1024 * 1024 * 1024);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public static getCPUCores(): number {
|
|
75
|
+
return os.cpus().length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public static getSystemInfo(): any {
|
|
79
|
+
return {
|
|
80
|
+
os: this.getOS(),
|
|
81
|
+
distro: this.getDistro(),
|
|
82
|
+
arch: this.getArch(),
|
|
83
|
+
memoryGB: this.getTotalMemory(),
|
|
84
|
+
cpuCores: this.getCPUCores(),
|
|
85
|
+
hostname: os.hostname(),
|
|
86
|
+
platform: os.platform(),
|
|
87
|
+
release: os.release(),
|
|
88
|
+
hasJava: this.hasJava(),
|
|
89
|
+
javaVersion: this.getJavaVersion()
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public static getJavaInstallCommand(): string {
|
|
94
|
+
const osType = this.getOS();
|
|
95
|
+
const distro = this.getDistro();
|
|
96
|
+
|
|
97
|
+
if (osType === 'android') {
|
|
98
|
+
return 'pkg install openjdk-17 -y';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (osType === 'linux') {
|
|
102
|
+
switch (distro) {
|
|
103
|
+
case 'ubuntu':
|
|
104
|
+
case 'debian':
|
|
105
|
+
return 'apt update && apt install openjdk-17-jre-headless -y';
|
|
106
|
+
case 'centos':
|
|
107
|
+
return 'yum install java-17-openjdk-headless -y';
|
|
108
|
+
case 'fedora':
|
|
109
|
+
return 'dnf install java-17-openjdk-headless -y';
|
|
110
|
+
case 'arch':
|
|
111
|
+
return 'pacman -S jre17-openjdk-headless --noconfirm';
|
|
112
|
+
default:
|
|
113
|
+
return 'echo "Please install Java 17 manually"';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (osType === 'darwin') {
|
|
118
|
+
return 'brew install openjdk@17';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (osType === 'windows') {
|
|
122
|
+
return 'Please download Java 17 from https://adoptium.net';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return 'echo "Unable to determine Java installation command"';
|
|
126
|
+
}
|
|
127
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"noImplicitAny": true,
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"noImplicitReturns": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*"],
|
|
22
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
23
|
+
}
|