-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #103 from Corona-Studio/sample
Add sample
- Loading branch information
Showing
14 changed files
with
669 additions
and
3 deletions.
There are no files selected for viewing
109 changes: 109 additions & 0 deletions
109
ProjBobcat/ProjBobcat.Sample/Commands/Game/GameLaunchCommands.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
using Cocona; | ||
using Microsoft.Extensions.Logging; | ||
using ProjBobcat.Class.Helper; | ||
using ProjBobcat.Class.Model; | ||
using ProjBobcat.DefaultComponent.Authenticator; | ||
|
||
namespace ProjBobcat.Sample.Commands.Game; | ||
|
||
public class GameLaunchCommands(ILogger<GameLaunchCommands> logger) | ||
{ | ||
[Command("launch", Aliases = ["run", "start", "play"], Description = "Launch the game.")] | ||
public async Task LaunchGameAsync( | ||
[Argument(Description = "Game Id")] string gameId, | ||
[Argument(Description = "Offline account name")] string displayName, | ||
[Argument(Description = "Java executable path")] string javaPath, | ||
[Range(0, 5)] [Option("gc", Description = "Garbage collection type")] int gcType = 0, | ||
[Range(1024, 1024 * 1024 * 10)] [Option("max-memory", Description = "Max memory size in MB")] uint maxMemory = 1024, | ||
[Option("title", Description = "Custom game window title (Windows only)")] string windowTitle = "Minecraft - By ProjBobcat") | ||
{ | ||
var version = GameHelper.GameCore.VersionLocator.GetGame(gameId); | ||
|
||
if (version == null) | ||
{ | ||
logger.LogCritical( | ||
"Game {GameId} not found. Please check if the game id is correct.", | ||
gameId); | ||
|
||
return; | ||
} | ||
|
||
var auth = new OfflineAuthenticator | ||
{ | ||
LauncherAccountParser = GameHelper.GameCore.VersionLocator.LauncherAccountParser!, | ||
Username = displayName | ||
}; | ||
var authResult = await auth.AuthTaskAsync(false); | ||
|
||
var args = new GameArguments | ||
{ | ||
GcType = (GcType)gcType, | ||
JavaExecutable = javaPath, | ||
MaxMemory = maxMemory | ||
}; | ||
var ls = new LaunchSettings | ||
{ | ||
Authenticator = auth, | ||
Version = gameId, | ||
GameArguments = args, | ||
GameName = version.Name, | ||
GamePath = GamePathHelper.GetVersionPath(GameHelper.GameCore.RootPath), | ||
GameResourcePath = GameHelper.GameCore.RootPath, | ||
LauncherName = "LauncherX (By ProjBobcat)", | ||
VersionInsulation = true, | ||
VersionLocator = GameHelper.GameCore.VersionLocator, | ||
WindowTitle = windowTitle, | ||
SelectedProfile = authResult.SelectedProfile | ||
}; | ||
|
||
GameHelper.GameCore.LaunchLogEventDelegate += (_, eventArgs) => | ||
{ | ||
logger.LogInformation("[{Time}] {Message}", eventArgs.ItemRunTime, eventArgs.Item); | ||
}; | ||
|
||
GameHelper.GameCore.GameExitEventDelegate += (_, eventArgs) => | ||
{ | ||
logger.LogInformation("Game exit with code {ExitCode}.", eventArgs.ExitCode); | ||
}; | ||
|
||
GameHelper.GameCore.GameLogEventDelegate += (_, eventArgs) => | ||
{ | ||
logger.LogInformation(eventArgs.RawContent); | ||
}; | ||
|
||
var result = await GameHelper.GameCore.LaunchTaskAsync(ls); | ||
var isSucceed = result.Error == null; | ||
var errorReason = result.ErrorType switch | ||
{ | ||
LaunchErrorType.AuthFailed => "AuthFailed", | ||
LaunchErrorType.DecompressFailed => "DecompressFailed", | ||
LaunchErrorType.IncompleteArguments => "IncompleteArgument", | ||
LaunchErrorType.NoJava => "NoJava", | ||
LaunchErrorType.None => "None", | ||
LaunchErrorType.OperationFailed => "OperationFailed", | ||
LaunchErrorType.Unknown => "Unknown", | ||
var x => throw new ArgumentOutOfRangeException(x.ToString()) | ||
}; | ||
var detail = isSucceed | ||
? $"Duration: {result.RunTime:g}" | ||
: $"{result.Error?.ErrorMessage ?? "Unknown"}, Reason: {errorReason}"; | ||
|
||
logger.Log(isSucceed ? LogLevel.Information : LogLevel.Critical, detail); | ||
|
||
if (!isSucceed && result.Error?.Exception != null) | ||
{ | ||
logger.LogError(result.Error?.Exception, "Exception occurred when launching game."); | ||
|
||
return; | ||
} | ||
|
||
if (result.GameProcess == null) return; | ||
|
||
logger.LogInformation("Game process started, wait for game to exit."); | ||
|
||
await result.GameProcess.WaitForExitAsync(); | ||
|
||
logger.LogInformation("Game process exited."); | ||
} | ||
} |
185 changes: 185 additions & 0 deletions
185
ProjBobcat/ProjBobcat.Sample/Commands/Game/GameManageCommands.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
using System.Collections.Immutable; | ||
using System.ComponentModel.DataAnnotations; | ||
using Cocona; | ||
using Microsoft.Extensions.Logging; | ||
using ProjBobcat.Class.Helper; | ||
using ProjBobcat.Class.Model; | ||
using ProjBobcat.Interface; | ||
using ProjBobcat.Sample.DownloadMirrors; | ||
|
||
namespace ProjBobcat.Sample.Commands.Game; | ||
|
||
public class GameManageCommands(ILogger<GameManageCommands> logger) | ||
{ | ||
[Command("search", Aliases = ["list", "find"], Description = "Search games on the local machine")] | ||
public void GetLocalGames() | ||
{ | ||
logger.LogInformation("Start searching games..."); | ||
|
||
var games = GameHelper.GameCore.VersionLocator.GetAllGames().ToImmutableList(); | ||
|
||
if (games.Count == 0) | ||
{ | ||
logger.LogWarning("No games found."); | ||
return; | ||
} | ||
|
||
foreach (var game in games) | ||
logger.LogInformation("Found game: {GameId}[{GameName}]", game.Id, game.Name); | ||
} | ||
|
||
[Command("mirrors", Description = "Get download mirrors")] | ||
public void GetDownloadMirrors() | ||
{ | ||
string[] mirrors = | ||
[ | ||
nameof(OfficialDownloadMirror), | ||
nameof(BangBangDownloadMirror), | ||
nameof(McBbsDownloadMirror) | ||
]; | ||
|
||
for (var i = 0; i < mirrors.Length; i++) | ||
{ | ||
var mirror = mirrors[i]; | ||
var mirrorName = mirror[..^"DownloadMirror".Length]; | ||
|
||
logger.LogInformation("[{Index}] {MirrorName}", i, mirrorName); | ||
} | ||
} | ||
|
||
[Command("gc", Description = "Get garbage collection types")] | ||
public void GetGcTypes() | ||
{ | ||
var arr = Enum.GetNames<GcType>(); | ||
|
||
for (var i = 0; i < arr.Length; i++) | ||
{ | ||
var name = arr[i]; | ||
|
||
logger.LogInformation("[{Index}] {Name}", i, name); | ||
} | ||
} | ||
|
||
[Command("repair", Description = "Check game files and repair them if needed")] | ||
public async Task RepairGameAsync( | ||
[Argument(Description = "Game id")] string gameId, | ||
[Range(0, 2)] | ||
[Argument("mirror", Description = "Download mirror index, use [game mirrors] to reveal mirror indexes")] | ||
int mirrorIndex = 0, | ||
[Range(1, 32)] [Argument("parallel", Description = "Parallel tasks")] | ||
int parallel = 8, | ||
[Range(1, 128)] [Argument("download-threads", Description = "Download threads")] | ||
int downloadThreads = 32, | ||
[Range(1, 16)] [Argument("download-parts", Description = "Download parts")] | ||
int downloadParts = 8, | ||
[Option("verbose", Description = "Enable verbose mode")] | ||
bool verbose = false, | ||
[Option("disable-verify", Description = "Disable file verification")] | ||
bool disableVerify = false, | ||
[Option("uncheck-version", Description = "Disable Version Info checker")] | ||
bool uncheckVersion = false, | ||
[Option("uncheck-asset", Description = "Disable Asset Info checker")] | ||
bool uncheckAsset = false, | ||
[Option("uncheck-lib", Description = "Disable Library checker")] | ||
bool uncheckLib = false) | ||
{ | ||
logger.LogInformation("Start repairing game {GameId}...", gameId); | ||
|
||
var versionInfo = GameHelper.GameCore.VersionLocator.GetGame(gameId); | ||
IDownloadMirror mirror = mirrorIndex switch | ||
{ | ||
0 => new OfficialDownloadMirror(), | ||
1 => new BangBangDownloadMirror(), | ||
2 => new McBbsDownloadMirror(), | ||
_ => throw new ArgumentOutOfRangeException(nameof(mirrorIndex)) | ||
}; | ||
|
||
if (versionInfo == null) | ||
{ | ||
logger.LogCritical( | ||
"Game {GameId} not found. Please check if the game id is correct.", | ||
gameId); | ||
|
||
return; | ||
} | ||
|
||
var resolvers = new List<IResourceInfoResolver>(); | ||
|
||
if (!uncheckVersion) | ||
resolvers.Add(GameHelper.GetVersionInfoResolver(versionInfo)); | ||
if (!uncheckAsset) | ||
{ | ||
logger.LogInformation("Start to fetch Version Manifest from remote..."); | ||
|
||
var vm = await GameHelper.GetVersionManifestAsync(mirror); | ||
|
||
if (vm == null) | ||
{ | ||
logger.LogCritical( | ||
"Failed to fetch Version Manifest from remote. Please check your network connection."); | ||
return; | ||
} | ||
|
||
resolvers.Add(GameHelper.GetAssetInfoResolver(versionInfo, vm, mirror)); | ||
} | ||
|
||
if (!uncheckLib) | ||
resolvers.Add(GameHelper.GetLibraryInfoResolver(versionInfo, mirror)); | ||
|
||
if (resolvers.Count == 0) | ||
{ | ||
logger.LogWarning("No resolver enabled. Please check your command."); | ||
return; | ||
} | ||
|
||
foreach (var resolver in resolvers) | ||
logger.LogInformation("Resolver enabled: {Resolver}", resolver.GetType().Name); | ||
|
||
var completer = GameHelper.GetResourceCompleter( | ||
resolvers, | ||
parallel, | ||
downloadThreads, | ||
downloadParts, | ||
!disableVerify); | ||
|
||
if (verbose) | ||
{ | ||
completer.GameResourceInfoResolveStatus += (_, args) => | ||
{ | ||
logger.LogInformation("[{Progress:P2}] {Message}", args.Progress, args.Status); | ||
}; | ||
} | ||
|
||
var progressVal = 0d; | ||
|
||
completer.DownloadFileChangedEvent += (_, args) => { progressVal = args.ProgressPercentage; }; | ||
|
||
completer.DownloadFileCompletedEvent += (sender, args) => | ||
{ | ||
if (sender is not DownloadFile file) return; | ||
if (args.Error != null) | ||
logger.LogError(args.Error, "Failed to download file {FileName}", file.FileName); | ||
var isSuccess = args.Success == true ? "Success" : "Failed"; | ||
var retry = file.RetryCount == 0 | ||
? null | ||
: $"<Retry - {file.RetryCount}>"; | ||
var fileName = file.FileName; | ||
var speed = DownloadHelper.AutoFormatSpeedString(args.AverageSpeed); | ||
var pD = $"<{file.FileType}>{retry}{isSuccess} {fileName} [{speed}]"; | ||
logger.LogInformation("[{Progress:P}] {ProgressDetail}", progressVal, pD); | ||
}; | ||
|
||
logger.LogInformation("Start to check and download game {GameId}...", gameId); | ||
|
||
var rCResult = await completer.CheckAndDownloadTaskAsync(); | ||
|
||
if (rCResult.TaskStatus == TaskResultStatus.Error || (rCResult.Value?.IsLibDownloadFailed ?? false)) | ||
logger.LogCritical("Failed to repair game {GameId}.", gameId); | ||
else | ||
logger.LogInformation("Game {GameId} repaired.", gameId); | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
ProjBobcat/ProjBobcat.Sample/Commands/SystemInfoCommands.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using System.Runtime.InteropServices; | ||
using System.Runtime.Versioning; | ||
using Cocona; | ||
using Microsoft.Extensions.Logging; | ||
using ProjBobcat.Class.Helper; | ||
|
||
namespace ProjBobcat.Sample.Commands; | ||
|
||
public class SystemInfoCommands(ILogger<SystemInfoCommands> logger) | ||
{ | ||
[SupportedOSPlatform("windows10.0.10586")] | ||
[SupportedOSPlatform(nameof(OSPlatform.OSX))] | ||
[Command("running-native", Description = "Check if the current process is running on native platform.")] | ||
public void CheckCpuTranslation() | ||
{ | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | ||
{ | ||
logger.LogError("This command is not supported on Linux."); | ||
return; | ||
} | ||
|
||
logger.LogInformation("Is running under translation: {IsRunningUnderTranslation}", | ||
SystemInfoHelper.IsRunningUnderTranslation()); | ||
} | ||
|
||
[SupportedOSPlatform(nameof(OSPlatform.Windows))] | ||
[SupportedOSPlatform(nameof(OSPlatform.OSX))] | ||
[SupportedOSPlatform(nameof(OSPlatform.Linux))] | ||
[Command("find-java", Description = "Search Java on the local machine")] | ||
public async Task SearchJavaAsync( | ||
[Option("d", Description = "Enable deep search")] bool deepSearch) | ||
{ | ||
logger.LogInformation("Searching Java..."); | ||
|
||
await foreach(var java in SystemInfoHelper.FindJava(deepSearch)) | ||
logger.LogInformation("Found Java: {JavaPath}", java); | ||
} | ||
|
||
[Command("arch", Description = "Get system arch")] | ||
public void CheckSystemArch() | ||
{ | ||
logger.LogInformation("System arch: {SystemArch}", SystemInfoHelper.GetSystemArch()); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
ProjBobcat/ProjBobcat.Sample/Commands/SystemMetricsCommands.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using Cocona; | ||
using Microsoft.Extensions.Logging; | ||
using ProjBobcat.Class.Helper; | ||
|
||
namespace ProjBobcat.Sample.Commands; | ||
|
||
public class SystemMetricsCommands(ILogger<SystemMetricsCommands> logger) | ||
{ | ||
[Command("cpu", Description = "Get CPU usage")] | ||
public async Task GetCpuUsageAsync( | ||
[Argument(Description = "Sample count")] int sampleCount = 6) | ||
{ | ||
for (var i = 0; i < sampleCount; i++) | ||
{ | ||
var cpuUsage = SystemInfoHelper.GetProcessorUsage(); | ||
logger.LogInformation("CPU usage: {CpuUsage}", cpuUsage); | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(1)); | ||
} | ||
} | ||
|
||
[Command("mem", Description = "Get memory usage")] | ||
public async Task GetMemoryUsageAsync( | ||
[Argument(Description = "Sample count")] int sampleCount = 6) | ||
{ | ||
for (var i = 0; i < sampleCount; i++) | ||
{ | ||
var memUsage = SystemInfoHelper.GetMemoryUsage(); | ||
logger.LogInformation("Memory usage: {MemoryUsage}", memUsage); | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(1)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Cocona; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace ProjBobcat.Sample.Commands; | ||
|
||
public class TestCommand(ILogger<TestCommand> logger) | ||
{ | ||
readonly ILogger _logger = logger; | ||
|
||
[Command("hello")] | ||
public void Hello() | ||
{ | ||
_logger.LogInformation("Hello from Cocona."); | ||
} | ||
} |
Oops, something went wrong.