A failed start is decided in RunStart.Launch; the scene steps nothing without a live run #26
4 changed files with 72 additions and 14 deletions
|
|
@ -106,6 +106,9 @@ public class ActionGameManager : MonoBehaviour
|
|||
}
|
||||
|
||||
public static Galaxy CurrentGalaxy;
|
||||
// Whether a run is live: a failed start and a finished run both clear the galaxy, and the scene's update paths (this
|
||||
// manager's, the renderer's) step and draw nothing without one.
|
||||
public static bool RunLive => CurrentGalaxy != null;
|
||||
// The scenario a new run starts from: MainMenu.Launch sets it, and StartGame's new-run branch consumes it once.
|
||||
public static Scenario PendingScenario;
|
||||
|
||||
|
|
@ -854,21 +857,12 @@ public class ActionGameManager : MonoBehaviour
|
|||
var scenario = PendingScenario;
|
||||
PendingScenario = null;
|
||||
var failures = new List<string>();
|
||||
RunStart.Staged staged = null;
|
||||
try
|
||||
var staged = RunStart.Launch(() => RunSave.Replace(CultCache, () =>
|
||||
{
|
||||
staged = RunSave.Replace(CultCache, () =>
|
||||
{
|
||||
RunStart.GenerateArena(ItemManager, Settings.ZoneSettings, Settings.PlanetSettings, CurrentGalaxy, scenario);
|
||||
PopulateLevel(CurrentGalaxy.Entrance);
|
||||
return RunStart.Stage(ItemManager, Zone, scenario, Settings.StartingHullName, Settings.TutorialGenerationSettings, failures);
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
failures.Add(exception.Message);
|
||||
}
|
||||
RunStart.GenerateArena(ItemManager, Settings.ZoneSettings, Settings.PlanetSettings, CurrentGalaxy, scenario);
|
||||
PopulateLevel(CurrentGalaxy.Entrance);
|
||||
return RunStart.Stage(ItemManager, Zone, scenario, Settings.StartingHullName, Settings.TutorialGenerationSettings, failures);
|
||||
}), failures, Debug.LogException);
|
||||
|
||||
if (staged == null)
|
||||
{
|
||||
|
|
@ -1348,6 +1342,7 @@ public class ActionGameManager : MonoBehaviour
|
|||
|
||||
void Update()
|
||||
{
|
||||
if (!RunLive) return;
|
||||
if(!_paused)
|
||||
{
|
||||
_time += Time.deltaTime;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,21 @@ public static class RunStart
|
|||
itemManager, zoneSettings, planetSettings, galaxy, galaxy.Entrance, galaxy.IsPrelude, scenario.Ambient);
|
||||
}
|
||||
|
||||
// Runs a start and answers whether it produced a run: null, with the reason in `failures`, when `start` throws or
|
||||
// returns nothing. The caller shows the failure and clears its run; nothing past a null may run the game.
|
||||
public static Staged Launch(Func<Staged> start, List<string> failures, Action<Exception> log = null)
|
||||
{
|
||||
Staged staged = null;
|
||||
try { staged = start(); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
log?.Invoke(exception);
|
||||
failures.Add(exception.Message);
|
||||
}
|
||||
if (staged == null && failures.Count == 0) failures.Add("the start produced no run");
|
||||
return staged;
|
||||
}
|
||||
|
||||
// Runs the scenario's Stage, then admits its player and everything it placed: each entity's stance set both ways
|
||||
// with the player, a pilot for each piloted one. Returns null, with every failure listed and the arena unchanged,
|
||||
// unless the whole scenario staged.
|
||||
|
|
|
|||
|
|
@ -508,6 +508,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (!ActionGameManager.RunLive) return;
|
||||
Map.Draw(Zone, ActionGameManager.Clock.Lead);
|
||||
}
|
||||
|
||||
|
|
@ -550,6 +551,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
|
||||
void Update()
|
||||
{
|
||||
if (!ActionGameManager.RunLive) return;
|
||||
var lead = ActionGameManager.Clock.Lead;
|
||||
GravityLowering.Lower(Zone, lead, ref _gravityWells);
|
||||
foreach (var loot in _floatingItems.Values)
|
||||
|
|
|
|||
46
tests/Aetheria.Shared.Tests/RunLaunchTests.cs
Normal file
46
tests/Aetheria.Shared.Tests/RunLaunchTests.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
// RunStart.Launch decides whether a start produced a run; the game scene halts on its answer (a failed start clears the
|
||||
// galaxy, and a scene with no galaxy steps nothing). Kills: a start that throws or returns nothing reading as a run, a
|
||||
// failure with no reason to show on the menu, a thrown exception that is neither logged nor listed, and a start that
|
||||
// worked being reported failed.
|
||||
public sealed class RunLaunchTests
|
||||
{
|
||||
[Fact]
|
||||
public void AStartThatThrowsIsNoRunAndSaysWhy()
|
||||
{
|
||||
var failures = new List<string>();
|
||||
var logged = new List<Exception>();
|
||||
var staged = RunStart.Launch(() => throw new InvalidOperationException("the arena would not generate"), failures, logged.Add);
|
||||
Assert.Null(staged);
|
||||
Assert.Equal(new[] { "the arena would not generate" }, failures);
|
||||
Assert.Single(logged);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStartThatReturnsNothingIsNoRunAndKeepsItsOwnReasons()
|
||||
{
|
||||
var failures = new List<string>();
|
||||
Assert.Null(RunStart.Launch(() => { failures.Add("player: the scenario places no player"); return null; }, failures));
|
||||
Assert.Equal(new[] { "player: the scenario places no player" }, failures);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStartThatReturnsNothingAndSaysNothingStillGivesAReason()
|
||||
{
|
||||
var failures = new List<string>();
|
||||
Assert.Null(RunStart.Launch(() => null, failures));
|
||||
Assert.Single(failures);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStartThatStagedIsARunWithNoFailures()
|
||||
{
|
||||
var failures = new List<string>();
|
||||
var made = new RunStart.Staged();
|
||||
Assert.Same(made, RunStart.Launch(() => made, failures));
|
||||
Assert.Empty(failures);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue