@dimzxzzx07/mc-headless 2.2.0 → 2.2.2

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.
@@ -37,6 +37,8 @@ exports.MinecraftServer = void 0;
37
37
  const events_1 = require("events");
38
38
  const child_process_1 = require("child_process");
39
39
  const cron = __importStar(require("node-cron"));
40
+ const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs-extra"));
40
42
  const ConfigHandler_1 = require("./ConfigHandler");
41
43
  const JavaChecker_1 = require("./JavaChecker");
42
44
  const FileUtils_1 = require("../utils/FileUtils");
@@ -49,8 +51,6 @@ const FabricEngine_1 = require("../engines/FabricEngine");
49
51
  const GeyserBridge_1 = require("../platforms/GeyserBridge");
50
52
  const ViaVersion_1 = require("../platforms/ViaVersion");
51
53
  const SkinRestorer_1 = require("../platforms/SkinRestorer");
52
- const path = __importStar(require("path"));
53
- const fs = __importStar(require("fs-extra"));
54
54
  class MinecraftServer extends events_1.EventEmitter {
55
55
  config;
56
56
  options;
@@ -63,6 +63,7 @@ class MinecraftServer extends events_1.EventEmitter {
63
63
  serverInfo;
64
64
  players = new Map();
65
65
  backupCron = null;
66
+ cleanLogsCron = null;
66
67
  startTime = null;
67
68
  memoryMonitorInterval = null;
68
69
  statsInterval = null;
@@ -78,13 +79,15 @@ class MinecraftServer extends events_1.EventEmitter {
78
79
  cpuUsage = 0;
79
80
  cgroupMemory = 0;
80
81
  cgroupCpu = 0;
82
+ isPterodactyl = false;
81
83
  constructor(userConfig = {}) {
82
84
  super();
83
85
  this.logger = Logger_1.Logger.getInstance();
84
86
  this.logger.banner();
87
+ this.detectEnvironment();
85
88
  this.options = {
86
89
  javaVersion: 'auto',
87
- usePortableJava: true,
90
+ usePortableJava: !this.isPterodactyl,
88
91
  memoryMonitor: {
89
92
  enabled: true,
90
93
  threshold: 90,
@@ -104,6 +107,8 @@ class MinecraftServer extends events_1.EventEmitter {
104
107
  },
105
108
  silentMode: true,
106
109
  statsInterval: 30000,
110
+ cleanLogsInterval: 3 * 60 * 60 * 1000,
111
+ optimizeForPterodactyl: true,
107
112
  ...userConfig
108
113
  };
109
114
  if (this.options.owners) {
@@ -114,6 +119,9 @@ class MinecraftServer extends events_1.EventEmitter {
114
119
  }
115
120
  const handler = new ConfigHandler_1.ConfigHandler(userConfig);
116
121
  this.config = handler.getConfig();
122
+ if (this.isPterodactyl && this.options.optimizeForPterodactyl) {
123
+ this.optimizeForPterodactylPanel();
124
+ }
117
125
  this.engine = this.createEngine();
118
126
  this.geyser = new GeyserBridge_1.GeyserBridge();
119
127
  this.viaVersion = new ViaVersion_1.ViaVersionManager();
@@ -134,6 +142,166 @@ class MinecraftServer extends events_1.EventEmitter {
134
142
  status: 'stopped'
135
143
  };
136
144
  this.detectCgroupLimits();
145
+ this.cleanPaperCache();
146
+ }
147
+ detectEnvironment() {
148
+ this.isPterodactyl = !!(process.env.PTERODACTYL ||
149
+ process.env.SERVER_PORT ||
150
+ process.env.SERVER_MEMORY_MAX ||
151
+ fs.existsSync('/home/container'));
152
+ if (this.isPterodactyl) {
153
+ this.logger.info('Pterodactyl environment detected');
154
+ }
155
+ }
156
+ optimizeForPterodactylPanel() {
157
+ const pterodactylPort = process.env.SERVER_PORT;
158
+ if (pterodactylPort) {
159
+ this.config.network.port = parseInt(pterodactylPort);
160
+ this.logger.info(`Using Pterodactyl port: ${pterodactylPort}`);
161
+ }
162
+ const pterodactylMemory = process.env.SERVER_MEMORY_MAX;
163
+ if (pterodactylMemory) {
164
+ this.config.memory.max = pterodactylMemory;
165
+ this.logger.info(`Using Pterodactyl memory: ${pterodactylMemory}`);
166
+ }
167
+ const pterodactylInitMemory = process.env.SERVER_MEMORY_INIT;
168
+ if (pterodactylInitMemory) {
169
+ this.config.memory.init = pterodactylInitMemory;
170
+ }
171
+ this.config.world.viewDistance = 6;
172
+ this.config.world.simulationDistance = 4;
173
+ this.logger.info('Applied Pterodactyl optimizations');
174
+ }
175
+ cleanPaperCache() {
176
+ const cachePaths = [
177
+ path.join(process.cwd(), 'plugins', '.paper-remapped'),
178
+ path.join(process.cwd(), 'plugins', '.paper-remapped', 'geyser.jar'),
179
+ path.join(process.cwd(), 'plugins', '.paper-remapped', 'ViaVersion.jar'),
180
+ path.join(process.cwd(), 'cache', 'paper-remapped')
181
+ ];
182
+ cachePaths.forEach(cachePath => {
183
+ if (fs.existsSync(cachePath)) {
184
+ this.logger.info(`Cleaning corrupt cache: ${cachePath}`);
185
+ try {
186
+ fs.rmSync(cachePath, { recursive: true, force: true });
187
+ this.logger.debug(`Cache cleaned: ${cachePath}`);
188
+ }
189
+ catch (err) {
190
+ this.logger.warning(`Failed to clean cache: ${err.message}`);
191
+ }
192
+ }
193
+ });
194
+ }
195
+ cleanOldLogs() {
196
+ const logsDir = path.join(process.cwd(), 'logs');
197
+ if (!fs.existsSync(logsDir))
198
+ return;
199
+ try {
200
+ const files = fs.readdirSync(logsDir);
201
+ const now = Date.now();
202
+ const threeHours = 3 * 60 * 60 * 1000;
203
+ files.forEach(file => {
204
+ const filePath = path.join(logsDir, file);
205
+ const stats = fs.statSync(filePath);
206
+ if (now - stats.mtimeMs > threeHours) {
207
+ fs.unlinkSync(filePath);
208
+ this.logger.debug(`Cleaned old log: ${file}`);
209
+ }
210
+ });
211
+ this.logger.info('Old logs cleaned');
212
+ }
213
+ catch (err) {
214
+ this.logger.warning(`Failed to clean logs: ${err.message}`);
215
+ }
216
+ }
217
+ generateOptimizedConfigs() {
218
+ const serverDir = process.cwd();
219
+ const paperGlobalYml = path.join(serverDir, 'paper-global.yml');
220
+ if (!fs.existsSync(paperGlobalYml)) {
221
+ const paperGlobalConfig = `# Paper Global Configuration
222
+ # Optimized by MC-Headless
223
+
224
+ chunk-loading:
225
+ autoconfig-send-distance: false
226
+ enable-frustum-priority: false
227
+ global-max-chunk-load-rate: 100
228
+ global-max-chunk-send-rate: 50
229
+
230
+ entities:
231
+ despawn-ranges:
232
+ monster:
233
+ soft: 28
234
+ hard: 96
235
+ animal:
236
+ soft: 16
237
+ hard: 32
238
+ spawn-limits:
239
+ ambient: 5
240
+ axolotls: 5
241
+ creature: 10
242
+ monster: 15
243
+ water_ambient: 5
244
+ water_creature: 5
245
+
246
+ misc:
247
+ max-entity-speed: 100
248
+ redstone-implementation: ALTERNATIVE_CURRENT
249
+
250
+ player-auto-save: 6000
251
+ player-auto-save-rate: 1200
252
+ no-tick-view-distance: 12
253
+ `;
254
+ fs.writeFileSync(paperGlobalYml, paperGlobalConfig);
255
+ this.logger.debug('Generated paper-global.yml');
256
+ }
257
+ const paperWorldDefaultsYml = path.join(serverDir, 'paper-world-defaults.yml');
258
+ if (!fs.existsSync(paperWorldDefaultsYml)) {
259
+ const paperWorldConfig = `# Paper World Defaults
260
+ # Optimized by MC-Headless
261
+
262
+ view-distance: 6
263
+ no-tick-view-distance: 12
264
+
265
+ despawn-ranges:
266
+ monster:
267
+ soft: 28
268
+ hard: 96
269
+ animal:
270
+ soft: 16
271
+ hard: 32
272
+ ambient:
273
+ soft: 16
274
+ hard: 32
275
+ `;
276
+ fs.writeFileSync(paperWorldDefaultsYml, paperWorldConfig);
277
+ this.logger.debug('Generated paper-world-defaults.yml');
278
+ }
279
+ const spigotYml = path.join(serverDir, 'spigot.yml');
280
+ if (!fs.existsSync(spigotYml)) {
281
+ const spigotConfig = `# Spigot Configuration
282
+ # Optimized by MC-Headless
283
+
284
+ entity-activation-range:
285
+ animals: 16
286
+ monsters: 24
287
+ misc: 8
288
+ water: 8
289
+
290
+ mob-spawn-range: 4
291
+
292
+ world-settings:
293
+ default:
294
+ view-distance: 6
295
+ mob-spawn-range: 4
296
+ entity-activation-range:
297
+ animals: 16
298
+ monsters: 24
299
+ misc: 8
300
+ water: 8
301
+ `;
302
+ fs.writeFileSync(spigotYml, spigotConfig);
303
+ this.logger.debug('Generated spigot.yml');
304
+ }
137
305
  }
138
306
  detectCgroupLimits() {
139
307
  try {
@@ -177,10 +345,14 @@ class MinecraftServer extends events_1.EventEmitter {
177
345
  }
178
346
  const memMax = this.parseMemory(this.config.memory.max);
179
347
  const javaVersion = this.options.javaVersion || 'auto';
348
+ const baseArgs = [
349
+ `-Xms${this.config.memory.init}`,
350
+ `-Xmx${this.config.memory.max}`,
351
+ '-XX:+UseG1GC'
352
+ ];
180
353
  let gcArgs = [];
181
354
  if (memMax >= 16384) {
182
355
  gcArgs = [
183
- '-XX:+UseG1GC',
184
356
  '-XX:+ParallelRefProcEnabled',
185
357
  '-XX:MaxGCPauseMillis=100',
186
358
  '-XX:+UnlockExperimentalVMOptions',
@@ -202,7 +374,6 @@ class MinecraftServer extends events_1.EventEmitter {
202
374
  }
203
375
  else if (memMax >= 8192) {
204
376
  gcArgs = [
205
- '-XX:+UseG1GC',
206
377
  '-XX:+ParallelRefProcEnabled',
207
378
  '-XX:MaxGCPauseMillis=150',
208
379
  '-XX:+UnlockExperimentalVMOptions',
@@ -224,7 +395,6 @@ class MinecraftServer extends events_1.EventEmitter {
224
395
  }
225
396
  else {
226
397
  gcArgs = this.config.memory.useAikarsFlags ? [
227
- '-XX:+UseG1GC',
228
398
  '-XX:+ParallelRefProcEnabled',
229
399
  '-XX:MaxGCPauseMillis=200',
230
400
  '-XX:+UnlockExperimentalVMOptions',
@@ -245,10 +415,6 @@ class MinecraftServer extends events_1.EventEmitter {
245
415
  if (javaVersion === '21') {
246
416
  gcArgs.push('--enable-preview');
247
417
  }
248
- const baseArgs = [
249
- `-Xms${this.config.memory.init}`,
250
- `-Xmx${this.config.memory.max}`
251
- ];
252
418
  return [...baseArgs, ...gcArgs];
253
419
  }
254
420
  buildEnvironment() {
@@ -268,6 +434,163 @@ class MinecraftServer extends events_1.EventEmitter {
268
434
  }
269
435
  return env;
270
436
  }
437
+ async start() {
438
+ this.logger.info(`Starting ${this.config.type} server v${this.config.version}...`);
439
+ this.cleanPaperCache();
440
+ this.generateOptimizedConfigs();
441
+ if (this.options.cleanLogsInterval && this.options.cleanLogsInterval > 0) {
442
+ this.cleanLogsCron = cron.schedule('0 */3 * * *', () => this.cleanOldLogs());
443
+ this.logger.info('Log cleanup scheduled every 3 hours');
444
+ }
445
+ if (this.owners.size > 0) {
446
+ this.logger.info(`Owners configured: ${Array.from(this.owners).join(', ')}`);
447
+ }
448
+ this.javaInfo = await JavaChecker_1.JavaChecker.ensureJava(this.config.version, this.options.usePortableJava || false);
449
+ this.javaCommand = this.javaInfo.path;
450
+ this.logger.success(`Using Java ${this.javaInfo.version} (${this.javaInfo.type}) at ${this.javaInfo.path}`);
451
+ const systemInfo = SystemDetector_1.SystemDetector.getSystemInfo();
452
+ this.logger.debug('System info:', systemInfo);
453
+ const serverDir = process.cwd();
454
+ await FileUtils_1.FileUtils.ensureServerStructure(this.config);
455
+ this.worldSize = await this.calculateWorldSize();
456
+ if (this.worldSize > 10 * 1024 * 1024 * 1024) {
457
+ this.logger.warning(`Large world detected (${(this.worldSize / 1024 / 1024 / 1024).toFixed(2)} GB). Consider increasing memory allocation.`);
458
+ }
459
+ const jarPath = await this.engine.download(this.config, serverDir);
460
+ if (this.config.type === 'forge') {
461
+ await this.engine.prepare(this.config, serverDir, jarPath);
462
+ }
463
+ else {
464
+ await this.engine.prepare(this.config, serverDir);
465
+ }
466
+ if (this.config.platform === 'all') {
467
+ await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
468
+ await this.geyser.setup(this.config);
469
+ }
470
+ if (this.options.enableViaVersion !== false) {
471
+ this.logger.info('Enabling ViaVersion for client version compatibility...');
472
+ await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
473
+ await this.viaVersion.setup(this.config);
474
+ await this.viaVersion.configureViaVersion(this.config);
475
+ if (this.options.enableViaBackwards !== false) {
476
+ this.logger.info('ViaBackwards will be installed');
477
+ }
478
+ if (this.options.enableViaRewind !== false) {
479
+ this.logger.info('ViaRewind will be installed');
480
+ }
481
+ }
482
+ if (this.options.enableSkinRestorer !== false) {
483
+ this.logger.info('Enabling SkinRestorer for player skins...');
484
+ await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
485
+ await this.skinRestorer.setup(this.config);
486
+ }
487
+ const javaArgs = this.buildJavaArgs();
488
+ const serverJar = this.engine.getServerJar(jarPath);
489
+ const serverArgs = this.engine.getServerArgs();
490
+ const fullArgs = [
491
+ ...javaArgs,
492
+ '-jar',
493
+ serverJar,
494
+ ...serverArgs
495
+ ];
496
+ if (this.options.networkOptimization?.tcpFastOpen) {
497
+ fullArgs.unshift('-Djava.net.preferIPv4Stack=true');
498
+ }
499
+ if (this.options.networkOptimization?.bungeeMode) {
500
+ fullArgs.unshift('-Dnet.kyori.adventure.text.serializer.legacy.AMPMSupport=true');
501
+ }
502
+ const env = this.buildEnvironment();
503
+ this.logger.info(`Launching: ${this.javaCommand} ${fullArgs.join(' ')}`);
504
+ this.process = (0, child_process_1.spawn)(this.javaCommand, fullArgs, {
505
+ cwd: serverDir,
506
+ env: env,
507
+ stdio: ['pipe', 'pipe', 'pipe']
508
+ });
509
+ this.serverInfo.pid = this.process.pid;
510
+ this.serverInfo.status = 'starting';
511
+ this.startTime = new Date();
512
+ if (this.options.silentMode) {
513
+ this.process.stdout.pipe(process.stdout);
514
+ this.process.stderr.pipe(process.stderr);
515
+ }
516
+ else {
517
+ this.setupLogHandlers();
518
+ }
519
+ this.process.on('exit', (code) => {
520
+ this.serverInfo.status = 'stopped';
521
+ this.logger.warning(`Server stopped with code ${code}`);
522
+ if (this.config.autoRestart && code !== 0) {
523
+ this.logger.info('Auto-restarting...');
524
+ this.start();
525
+ }
526
+ this.emit('stop', { code });
527
+ });
528
+ if (this.options.statsInterval && this.options.statsInterval > 0) {
529
+ this.statsInterval = setInterval(() => this.updateStats(), this.options.statsInterval);
530
+ }
531
+ this.monitorResources();
532
+ if (this.config.backup.enabled) {
533
+ this.setupBackups();
534
+ }
535
+ setTimeout(() => {
536
+ if (this.serverInfo.status === 'starting') {
537
+ this.serverInfo.status = 'running';
538
+ this.logger.success('Server started successfully!');
539
+ if (this.options.enableViaVersion !== false) {
540
+ this.logger.info('ViaVersion is active - players from older versions can connect');
541
+ }
542
+ if (this.options.enableSkinRestorer !== false) {
543
+ this.logger.info('SkinRestorer is active - player skins will be restored');
544
+ }
545
+ if (this.worldSize > 0) {
546
+ this.logger.info(`World size: ${(this.worldSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
547
+ }
548
+ if (this.owners.size > 0) {
549
+ this.logger.info(`Owner commands enabled with prefix: ${this.ownerCommandPrefix}`);
550
+ }
551
+ this.emit('ready', this.serverInfo);
552
+ this.startMemoryMonitor();
553
+ }
554
+ }, 10000);
555
+ return this.serverInfo;
556
+ }
557
+ setupLogHandlers() {
558
+ this.process.stdout.on('data', (data) => {
559
+ const output = data.toString();
560
+ process.stdout.write(output);
561
+ if (output.includes('joined the game')) {
562
+ const match = output.match(/(\w+) joined the game/);
563
+ if (match) {
564
+ this.playerCount++;
565
+ this.handlePlayerJoin(match[1]);
566
+ if (this.owners.has(match[1].toLowerCase())) {
567
+ this.sendCommand(`tellraw ${match[1]} {"text":"Welcome Owner! Use ${this.ownerCommandPrefix}help for commands","color":"gold"}`);
568
+ }
569
+ }
570
+ }
571
+ if (output.includes('left the game')) {
572
+ const match = output.match(/(\w+) left the game/);
573
+ if (match) {
574
+ this.playerCount--;
575
+ this.handlePlayerLeave(match[1]);
576
+ }
577
+ }
578
+ if (output.includes('<') && output.includes('>')) {
579
+ const chatMatch = output.match(/<(\w+)>\s+(.+)/);
580
+ if (chatMatch) {
581
+ const player = chatMatch[1];
582
+ const message = chatMatch[2];
583
+ if (message.startsWith(this.ownerCommandPrefix)) {
584
+ const command = message.substring(this.ownerCommandPrefix.length);
585
+ this.processOwnerCommand(player, command);
586
+ }
587
+ }
588
+ }
589
+ });
590
+ this.process.stderr.on('data', (data) => {
591
+ process.stderr.write(data.toString());
592
+ });
593
+ }
271
594
  processOwnerCommand(player, command) {
272
595
  if (!this.options.ownerCommands?.enabled)
273
596
  return;
@@ -536,154 +859,6 @@ class MinecraftServer extends events_1.EventEmitter {
536
859
  this.logger.error('Stats update error:', error);
537
860
  }
538
861
  }
539
- async start() {
540
- this.logger.info(`Starting ${this.config.type} server v${this.config.version}...`);
541
- if (this.owners.size > 0) {
542
- this.logger.info(`Owners configured: ${Array.from(this.owners).join(', ')}`);
543
- }
544
- this.javaInfo = await JavaChecker_1.JavaChecker.ensureJava(this.config.version, this.options.usePortableJava || false);
545
- this.javaCommand = this.javaInfo.path;
546
- this.logger.success(`Using Java ${this.javaInfo.version} (${this.javaInfo.type}) at ${this.javaInfo.path}`);
547
- const systemInfo = SystemDetector_1.SystemDetector.getSystemInfo();
548
- this.logger.debug('System info:', systemInfo);
549
- const serverDir = process.cwd();
550
- await FileUtils_1.FileUtils.ensureServerStructure(this.config);
551
- this.worldSize = await this.calculateWorldSize();
552
- if (this.worldSize > 10 * 1024 * 1024 * 1024) {
553
- this.logger.warning(`Large world detected (${(this.worldSize / 1024 / 1024 / 1024).toFixed(2)} GB). Consider increasing memory allocation.`);
554
- }
555
- const jarPath = await this.engine.download(this.config, serverDir);
556
- if (this.config.type === 'forge') {
557
- await this.engine.prepare(this.config, serverDir, jarPath);
558
- }
559
- else {
560
- await this.engine.prepare(this.config, serverDir);
561
- }
562
- if (this.config.platform === 'all') {
563
- await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
564
- await this.geyser.setup(this.config);
565
- }
566
- if (this.options.enableViaVersion !== false) {
567
- this.logger.info('Enabling ViaVersion for client version compatibility...');
568
- await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
569
- await this.viaVersion.setup(this.config);
570
- await this.viaVersion.configureViaVersion(this.config);
571
- if (this.options.enableViaBackwards !== false) {
572
- this.logger.info('ViaBackwards will be installed');
573
- }
574
- if (this.options.enableViaRewind !== false) {
575
- this.logger.info('ViaRewind will be installed');
576
- }
577
- }
578
- if (this.options.enableSkinRestorer !== false) {
579
- this.logger.info('Enabling SkinRestorer for player skins...');
580
- await FileUtils_1.FileUtils.ensureDir(this.config.folders.plugins);
581
- await this.skinRestorer.setup(this.config);
582
- }
583
- const javaArgs = this.buildJavaArgs();
584
- const serverJar = this.engine.getServerJar(jarPath);
585
- const serverArgs = this.engine.getServerArgs();
586
- const fullArgs = [
587
- ...javaArgs,
588
- '-jar',
589
- serverJar,
590
- ...serverArgs
591
- ];
592
- if (this.options.networkOptimization?.tcpFastOpen) {
593
- fullArgs.unshift('-Djava.net.preferIPv4Stack=true');
594
- }
595
- if (this.options.networkOptimization?.bungeeMode) {
596
- fullArgs.unshift('-Dnet.kyori.adventure.text.serializer.legacy.AMPMSupport=true');
597
- }
598
- const env = this.buildEnvironment();
599
- this.logger.info(`Launching: ${this.javaCommand} ${fullArgs.join(' ')}`);
600
- this.process = (0, child_process_1.spawn)(this.javaCommand, fullArgs, {
601
- cwd: serverDir,
602
- env: env,
603
- stdio: ['pipe', 'pipe', 'pipe']
604
- });
605
- this.serverInfo.pid = this.process.pid;
606
- this.serverInfo.status = 'starting';
607
- this.startTime = new Date();
608
- if (this.options.silentMode) {
609
- this.process.stdout.pipe(process.stdout);
610
- this.process.stderr.pipe(process.stderr);
611
- }
612
- else {
613
- this.process.stdout.on('data', (data) => {
614
- const output = data.toString();
615
- process.stdout.write(output);
616
- if (output.includes('joined the game')) {
617
- const match = output.match(/(\w+) joined the game/);
618
- if (match) {
619
- this.playerCount++;
620
- this.handlePlayerJoin(match[1]);
621
- if (this.owners.has(match[1].toLowerCase())) {
622
- this.sendCommand(`tellraw ${match[1]} {"text":"Welcome Owner! Use ${this.ownerCommandPrefix}help for commands","color":"gold"}`);
623
- }
624
- }
625
- }
626
- if (output.includes('left the game')) {
627
- const match = output.match(/(\w+) left the game/);
628
- if (match) {
629
- this.playerCount--;
630
- this.handlePlayerLeave(match[1]);
631
- }
632
- }
633
- if (output.includes('<') && output.includes('>')) {
634
- const chatMatch = output.match(/<(\w+)>\s+(.+)/);
635
- if (chatMatch) {
636
- const player = chatMatch[1];
637
- const message = chatMatch[2];
638
- if (message.startsWith(this.ownerCommandPrefix)) {
639
- const command = message.substring(this.ownerCommandPrefix.length);
640
- this.processOwnerCommand(player, command);
641
- }
642
- }
643
- }
644
- });
645
- this.process.stderr.on('data', (data) => {
646
- process.stderr.write(data.toString());
647
- });
648
- }
649
- this.process.on('exit', (code) => {
650
- this.serverInfo.status = 'stopped';
651
- this.logger.warning(`Server stopped with code ${code}`);
652
- if (this.config.autoRestart && code !== 0) {
653
- this.logger.info('Auto-restarting...');
654
- this.start();
655
- }
656
- this.emit('stop', { code });
657
- });
658
- if (this.options.statsInterval && this.options.statsInterval > 0) {
659
- this.statsInterval = setInterval(() => this.updateStats(), this.options.statsInterval);
660
- }
661
- this.monitorResources();
662
- if (this.config.backup.enabled) {
663
- this.setupBackups();
664
- }
665
- setTimeout(() => {
666
- if (this.serverInfo.status === 'starting') {
667
- this.serverInfo.status = 'running';
668
- this.logger.success('Server started successfully!');
669
- if (this.options.enableViaVersion !== false) {
670
- this.logger.info('ViaVersion is active - players from older versions can connect');
671
- }
672
- if (this.options.enableSkinRestorer !== false) {
673
- this.logger.info('SkinRestorer is active - player skins will be restored');
674
- }
675
- if (this.worldSize > 0) {
676
- this.logger.info(`World size: ${(this.worldSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
677
- }
678
- if (this.owners.size > 0) {
679
- this.logger.info(`Owner commands enabled with prefix: ${this.ownerCommandPrefix}`);
680
- }
681
- this.emit('ready', this.serverInfo);
682
- this.startMemoryMonitor();
683
- }
684
- }, 10000);
685
- return this.serverInfo;
686
- }
687
862
  startMemoryMonitor() {
688
863
  if (!this.options.memoryMonitor?.enabled)
689
864
  return;
@@ -760,6 +935,9 @@ class MinecraftServer extends events_1.EventEmitter {
760
935
  if (this.backupCron) {
761
936
  this.backupCron.stop();
762
937
  }
938
+ if (this.cleanLogsCron) {
939
+ this.cleanLogsCron.stop();
940
+ }
763
941
  if (this.memoryMonitorInterval) {
764
942
  clearInterval(this.memoryMonitorInterval);
765
943
  }
@@ -769,6 +947,7 @@ class MinecraftServer extends events_1.EventEmitter {
769
947
  if (this.config.platform === 'all') {
770
948
  this.geyser.stop();
771
949
  }
950
+ this.cleanPaperCache();
772
951
  this.logger.success('Server stopped');
773
952
  }
774
953
  sendCommand(command) {