1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2024-11-25 07:42:58 +01:00

Compare commits

...

3 Commits

Author SHA1 Message Date
651a660cfc
WIP 2024-04-01 18:37:08 +02:00
5e6cb91b64
WIP 2024-04-01 18:20:33 +02:00
80d6bcbcac
Fix backups not working with Forge log format & add timeouts while waiting for server output 2024-04-01 18:13:15 +02:00
8 changed files with 69 additions and 20 deletions

View File

@ -1,4 +1,5 @@
using System.Text; using System.Collections.ObjectModel;
using System.Text;
using Phantom.Agent.Minecraft.Instance; using Phantom.Agent.Minecraft.Instance;
using Phantom.Agent.Minecraft.Java; using Phantom.Agent.Minecraft.Java;
using Phantom.Agent.Minecraft.Server; using Phantom.Agent.Minecraft.Server;
@ -11,6 +12,7 @@ public abstract class BaseLauncher : IServerLauncher {
private readonly InstanceProperties instanceProperties; private readonly InstanceProperties instanceProperties;
protected string MinecraftVersion => instanceProperties.ServerVersion; protected string MinecraftVersion => instanceProperties.ServerVersion;
protected string InstanceFolder => instanceProperties.InstanceFolder;
private protected BaseLauncher(InstanceProperties instanceProperties) { private protected BaseLauncher(InstanceProperties instanceProperties) {
this.instanceProperties = instanceProperties; this.instanceProperties = instanceProperties;
@ -51,16 +53,14 @@ public abstract class BaseLauncher : IServerLauncher {
var processConfigurator = new ProcessConfigurator { var processConfigurator = new ProcessConfigurator {
FileName = javaRuntimeExecutable.ExecutablePath, FileName = javaRuntimeExecutable.ExecutablePath,
WorkingDirectory = instanceProperties.InstanceFolder, WorkingDirectory = InstanceFolder,
RedirectInput = true, RedirectInput = true,
UseShellExecute = false UseShellExecute = false
}; };
var processArguments = processConfigurator.ArgumentList; var processArguments = processConfigurator.ArgumentList;
PrepareJvmArguments(serverJar).Build(processArguments); PrepareJvmArguments(serverJar).Build(processArguments);
processArguments.Add("-jar"); PrepareJavaProcessArguments(processArguments, serverJar.FilePath);
processArguments.Add(serverJar.FilePath);
processArguments.Add("nogui");
var process = processConfigurator.CreateProcess(); var process = processConfigurator.CreateProcess();
var instanceProcess = new InstanceProcess(instanceProperties, process); var instanceProcess = new InstanceProcess(instanceProperties, process);
@ -99,6 +99,12 @@ public abstract class BaseLauncher : IServerLauncher {
private protected virtual void CustomizeJvmArguments(JvmArgumentBuilder arguments) {} private protected virtual void CustomizeJvmArguments(JvmArgumentBuilder arguments) {}
protected virtual void PrepareJavaProcessArguments(Collection<string> processArguments, string serverJarFilePath) {
processArguments.Add("-jar");
processArguments.Add(serverJarFilePath);
processArguments.Add("nogui");
}
private protected virtual Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) { private protected virtual Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) {
return Task.FromResult(new ServerJarInfo(serverJarPath)); return Task.FromResult(new ServerJarInfo(serverJarPath));
} }

View File

@ -0,0 +1,29 @@
using System.Collections.ObjectModel;
using Phantom.Agent.Minecraft.Instance;
using Phantom.Agent.Minecraft.Java;
using Serilog;
namespace Phantom.Agent.Minecraft.Launcher.Types;
public sealed class ForgeLauncher : BaseLauncher {
public ForgeLauncher(InstanceProperties instanceProperties) : base(instanceProperties) {}
private protected override void CustomizeJvmArguments(JvmArgumentBuilder arguments) {
arguments.AddProperty("terminal.ansi", "true"); // TODO
}
protected override void PrepareJavaProcessArguments(Collection<string> processArguments, string serverJarFilePath) {
if (OperatingSystem.IsWindows()) {
processArguments.Add("@libraries/net/minecraftforge/forge/1.20.1-47.2.0/win_args.txt");
}
else {
processArguments.Add("@libraries/net/minecraftforge/forge/1.20.1-47.2.0/unix_args.txt");
}
processArguments.Add("nogui");
}
private protected override Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) {
return Task.FromResult(new ServerJarInfo(Path.Combine(InstanceFolder, "run.sh")));
}
}

View File

@ -38,7 +38,11 @@ sealed class MinecraftServerExecutableDownloader {
if (--listeners <= 0) { if (--listeners <= 0) {
Logger.Debug("Unregistered last download listener, cancelling download."); Logger.Debug("Unregistered last download listener, cancelling download.");
try {
cancellationTokenSource.Cancel(); cancellationTokenSource.Cancel();
} catch (ObjectDisposedException) {
// TODO THIS IS BAD
}
} }
else { else {
Logger.Debug("Unregistered download listener, current listener count: {Listeners}", listeners); Logger.Debug("Unregistered download listener, current listener count: {Listeners}", listeners);

View File

@ -67,6 +67,10 @@ sealed class BackupManager : IDisposable {
resultBuilder.Kind = BackupCreationResultKind.BackupCancelled; resultBuilder.Kind = BackupCreationResultKind.BackupCancelled;
logger.Warning("Backup creation was cancelled."); logger.Warning("Backup creation was cancelled.");
return null; return null;
} catch (TimeoutException) {
resultBuilder.Kind = BackupCreationResultKind.BackupTimedOut;
logger.Warning("Backup creation timed out.");
return null;
} catch (Exception e) { } catch (Exception e) {
resultBuilder.Kind = BackupCreationResultKind.UnknownError; resultBuilder.Kind = BackupCreationResultKind.UnknownError;
logger.Error(e, "Caught exception while creating an instance backup."); logger.Error(e, "Caught exception while creating an instance backup.");
@ -76,6 +80,8 @@ sealed class BackupManager : IDisposable {
await dispatcher.EnableAutomaticSaving(); await dispatcher.EnableAutomaticSaving();
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
// Ignore. // Ignore.
} catch (TimeoutException) {
logger.Warning("Timed out waiting for automatic saving to be re-enabled.");
} catch (Exception e) { } catch (Exception e) {
resultBuilder.Warnings |= BackupCreationWarnings.CouldNotRestoreAutomaticSaving; resultBuilder.Warnings |= BackupCreationWarnings.CouldNotRestoreAutomaticSaving;
logger.Error(e, "Caught exception while enabling automatic saving after creating an instance backup."); logger.Error(e, "Caught exception while enabling automatic saving after creating an instance backup.");
@ -120,6 +126,7 @@ sealed class BackupManager : IDisposable {
BackupCreationResultKind.Success => "Backup created successfully.", BackupCreationResultKind.Success => "Backup created successfully.",
BackupCreationResultKind.InstanceNotRunning => "Instance is not running.", BackupCreationResultKind.InstanceNotRunning => "Instance is not running.",
BackupCreationResultKind.BackupCancelled => "Backup cancelled.", BackupCreationResultKind.BackupCancelled => "Backup cancelled.",
BackupCreationResultKind.BackupTimedOut => "Backup timed out.",
BackupCreationResultKind.BackupAlreadyRunning => "A backup is already being created.", BackupCreationResultKind.BackupAlreadyRunning => "A backup is already being created.",
BackupCreationResultKind.BackupFileAlreadyExists => "Backup with the same name already exists.", BackupCreationResultKind.BackupFileAlreadyExists => "Backup with the same name already exists.",
BackupCreationResultKind.CouldNotCreateBackupFolder => "Could not create backup folder.", BackupCreationResultKind.CouldNotCreateBackupFolder => "Could not create backup folder.",

View File

@ -7,7 +7,7 @@ using Serilog;
namespace Phantom.Agent.Services.Backups; namespace Phantom.Agent.Services.Backups;
sealed partial class BackupServerCommandDispatcher : IDisposable { sealed partial class BackupServerCommandDispatcher : IDisposable {
[GeneratedRegex(@"^\[(?:.*?)\] \[Server thread/INFO\]: (.*?)$", RegexOptions.NonBacktracking)] [GeneratedRegex(@"^\[(?:.*?)\] \[Server thread/INFO\](?:.*?): (.*?)$", RegexOptions.NonBacktracking)]
private static partial Regex ServerThreadInfoRegex(); private static partial Regex ServerThreadInfoRegex();
private readonly ILogger logger; private readonly ILogger logger;
@ -32,18 +32,18 @@ sealed partial class BackupServerCommandDispatcher : IDisposable {
public async Task DisableAutomaticSaving() { public async Task DisableAutomaticSaving() {
await process.SendCommand(MinecraftCommand.SaveOff, cancellationToken); await process.SendCommand(MinecraftCommand.SaveOff, cancellationToken);
await automaticSavingDisabled.Task.WaitAsync(cancellationToken); await automaticSavingDisabled.Task.WaitAsync(TimeSpan.FromSeconds(30), cancellationToken);
} }
public async Task SaveAllChunks() { public async Task SaveAllChunks() {
// TODO Try if not flushing and waiting a few seconds before flushing reduces lag. // TODO Try if not flushing and waiting a few seconds before flushing reduces lag.
await process.SendCommand(MinecraftCommand.SaveAll(flush: true), cancellationToken); await process.SendCommand(MinecraftCommand.SaveAll(flush: true), cancellationToken);
await savedTheGame.Task.WaitAsync(cancellationToken); await savedTheGame.Task.WaitAsync(TimeSpan.FromMinutes(1), cancellationToken);
} }
public async Task EnableAutomaticSaving() { public async Task EnableAutomaticSaving() {
await process.SendCommand(MinecraftCommand.SaveOn, cancellationToken); await process.SendCommand(MinecraftCommand.SaveOn, cancellationToken);
await automaticSavingEnabled.Task.WaitAsync(cancellationToken); await automaticSavingEnabled.Task.WaitAsync(TimeSpan.FromMinutes(1), cancellationToken);
} }
private void OnOutput(object? sender, string? line) { private void OnOutput(object? sender, string? line) {

View File

@ -102,6 +102,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
IServerLauncher launcher = configuration.MinecraftServerKind switch { IServerLauncher launcher = configuration.MinecraftServerKind switch {
MinecraftServerKind.Vanilla => new VanillaLauncher(properties), MinecraftServerKind.Vanilla => new VanillaLauncher(properties),
MinecraftServerKind.Fabric => new FabricLauncher(properties), MinecraftServerKind.Fabric => new FabricLauncher(properties),
MinecraftServerKind.Forge => new ForgeLauncher(properties),
_ => InvalidLauncher.Instance _ => InvalidLauncher.Instance
}; };

View File

@ -1,15 +1,16 @@
namespace Phantom.Common.Data.Backups; namespace Phantom.Common.Data.Backups;
public enum BackupCreationResultKind : byte { public enum BackupCreationResultKind : byte {
UnknownError, UnknownError = 0,
Success, Success = 1,
InstanceNotRunning, InstanceNotRunning = 2,
BackupCancelled, BackupTimedOut = 3,
BackupAlreadyRunning, BackupCancelled = 4,
BackupFileAlreadyExists, BackupAlreadyRunning = 5,
CouldNotCreateBackupFolder, BackupFileAlreadyExists = 6,
CouldNotCopyWorldToTemporaryFolder, CouldNotCreateBackupFolder = 7,
CouldNotCreateWorldArchive CouldNotCopyWorldToTemporaryFolder = 8,
CouldNotCreateWorldArchive = 9
} }
public static class BackupCreationResultSummaryExtensions { public static class BackupCreationResultSummaryExtensions {

View File

@ -2,5 +2,6 @@
public enum MinecraftServerKind : ushort { public enum MinecraftServerKind : ushort {
Vanilla = 1, Vanilla = 1,
Fabric = 2 Fabric = 2,
Forge = 3
} }