Подробные изменения: - Расширен основной gameplay loop: джетпак, новые платформы, оборудование, враги, прогрессия сложности и ограничения взаимодействий игрока. - Добавлены Bootstrap-сервисы запуска приложения, защита, фокус окна, управление курсором и настройки сервисов через DI. - Добавлена COM-интеграция с технической схемой Input System, обработкой кнопок/ADC, подсветкой и консольной диагностикой. - Добавлен отдельный debug/logging модуль с каналами, обработчиками консоли и файловым выводом. - Добавлены asmdef, link.xml, EditMode/PlayMode тесты и обновлена дорожная карта проекта. Проверки: - dotnet build .\\DanroJump.Runtime.csproj --no-restore - dotnet build .\\DanroJump.Tests.EditMode.csproj --no-restore - dotnet build .\\DanroJump.Tests.PlayMode.csproj --no-restore
96 lines
3.1 KiB
C#
96 lines
3.1 KiB
C#
using System;
|
|
using System.Threading;
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
namespace DanroJump.Bootstrap
|
|
{
|
|
public sealed class StartupProtectionService
|
|
{
|
|
private readonly StartupProtectionOptions options;
|
|
private readonly IStartupLicenseChecker licenseChecker;
|
|
private readonly IStartupProtectionRuntime runtime;
|
|
|
|
public StartupProtectionService(
|
|
StartupProtectionOptions options,
|
|
IStartupLicenseChecker licenseChecker,
|
|
IStartupProtectionRuntime runtime)
|
|
{
|
|
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
|
this.licenseChecker = licenseChecker ?? throw new ArgumentNullException(nameof(licenseChecker));
|
|
this.runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
|
}
|
|
|
|
public StartupProtectionState State { get; private set; } = StartupProtectionState.NotStarted;
|
|
|
|
public async UniTask<StartupProtectionState> RunAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (State != StartupProtectionState.NotStarted)
|
|
{
|
|
return State;
|
|
}
|
|
|
|
if (ShouldSkipLicenseCheck())
|
|
{
|
|
State = StartupProtectionState.Skipped;
|
|
ApplyPresentationIfEnabled();
|
|
return State;
|
|
}
|
|
|
|
State = StartupProtectionState.Checking;
|
|
|
|
StartupLicenseResult result;
|
|
try
|
|
{
|
|
result = await licenseChecker.CheckAsync(options.LauncherName, options.CheckTimeout, cancellationToken);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
runtime.LogException(exception);
|
|
result = StartupLicenseResult.Failed(exception.Message);
|
|
}
|
|
|
|
await UniTask.SwitchToMainThread(cancellationToken);
|
|
|
|
if (result.IsValid)
|
|
{
|
|
State = StartupProtectionState.Licensed;
|
|
ApplyPresentationIfEnabled();
|
|
return State;
|
|
}
|
|
|
|
State = StartupProtectionState.Failed;
|
|
runtime.LogError(string.IsNullOrWhiteSpace(result.Message)
|
|
? "[StartupProtection] License check failed."
|
|
: $"[StartupProtection] License check failed: {result.Message}");
|
|
|
|
if (options.QuitDelay > TimeSpan.Zero)
|
|
{
|
|
await UniTask.Delay(options.QuitDelay, DelayType.DeltaTime, PlayerLoopTiming.Update, cancellationToken);
|
|
}
|
|
|
|
runtime.QuitApplication();
|
|
return State;
|
|
}
|
|
|
|
private bool ShouldSkipLicenseCheck()
|
|
{
|
|
return options.SkipInEditor && runtime.IsEditor
|
|
|| options.SkipInDevelopmentBuild && runtime.IsDevelopmentBuild;
|
|
}
|
|
|
|
private void ApplyPresentationIfEnabled()
|
|
{
|
|
if (!options.ApplyLegacyStartupPresentation || runtime.IsEditor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
runtime.ApplyLegacyStartupPresentation(options);
|
|
}
|
|
}
|
|
}
|