ported from perforce
This commit is contained in:
139
RobotAndDonkey.Game/Execution/GameRuntime.cs
Normal file
139
RobotAndDonkey.Game/Execution/GameRuntime.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using RobotAndDonkey.Game.Execution.Commands;
|
||||
using RobotAndDonkey.Game.Execution.Requests;
|
||||
using RobotAndDonkey.Game.Execution.Results;
|
||||
using RobotAndDonkey.Game.GameState;
|
||||
using RobotAndDonkey.Game.Intents;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
|
||||
namespace RobotAndDonkey.Game.Execution;
|
||||
|
||||
public sealed record GameEvent(long Sequence, DateTimeOffset Time, object Payload);
|
||||
|
||||
public sealed record NextStepIssued(Request Step);
|
||||
|
||||
public sealed record StepApplied(ImmutableArray<Result> Results);
|
||||
|
||||
public sealed record StepRejected(Guid RequestId, string Reason);
|
||||
|
||||
public sealed record StateChanged;
|
||||
|
||||
public sealed record GameOver(string Reason);
|
||||
|
||||
public sealed class GameRuntime
|
||||
{
|
||||
public event EventHandler<GameEvent>? Published;
|
||||
|
||||
public void Start(CoreLoop coreLoop)
|
||||
{
|
||||
lock (m_Gate)
|
||||
{
|
||||
m_CoreLoop = coreLoop;
|
||||
Publish(new StateChanged());
|
||||
IssueNextStepLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void Submit(Command command, CancellationToken ct = default)
|
||||
{
|
||||
lock (m_Gate)
|
||||
{
|
||||
if (m_CoreLoop == null)
|
||||
{
|
||||
Publish(new StepRejected(command.RequestId, "No core loop started."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ExpectedRequest is null)
|
||||
{
|
||||
Publish(new StepRejected(command.RequestId, "No step expected (game over or not started)."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ExpectedRequest.RequestId != command.RequestId)
|
||||
{
|
||||
Publish(new StepRejected(command.RequestId, "Command does not match the expected step."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ExpectedRequest.IsCommandCompatible(command))
|
||||
{
|
||||
Publish(new StepRejected(command.RequestId, "Command not compatible with the current step."));
|
||||
return;
|
||||
}
|
||||
|
||||
var results = command.Execute(m_CoreLoop, false, false);
|
||||
|
||||
Publish(new StepApplied([..results]));
|
||||
Publish(new StateChanged());
|
||||
|
||||
IssueNextStepLocked();
|
||||
}
|
||||
}
|
||||
|
||||
private void IssueNextStepLocked()
|
||||
{
|
||||
m_ExpectedRequest = NextRequest();
|
||||
|
||||
if (m_ExpectedRequest is null)
|
||||
Publish(new GameOver("No more steps."));
|
||||
else
|
||||
Publish(new NextStepIssued(m_ExpectedRequest));
|
||||
}
|
||||
|
||||
private Request? NextRequest()
|
||||
{
|
||||
var coreLoop = m_CoreLoop!;
|
||||
switch (coreLoop.RunPhase)
|
||||
{
|
||||
case ERunPhase.Init:
|
||||
{
|
||||
const ERunPhase firstPhase = ERunPhase.ExecuteProgram;
|
||||
coreLoop.ResetShop();
|
||||
new EnterPreview().Run(Guid.Empty, coreLoop, [], []);
|
||||
// DEBUG
|
||||
// const ERunPhase firstPhase = ERunPhase.DrawGlitch;
|
||||
coreLoop.RunPhase = firstPhase;
|
||||
goto case firstPhase;
|
||||
}
|
||||
case ERunPhase.DrawGlitch:
|
||||
{
|
||||
return DrawGlitchRequest.Create(coreLoop);
|
||||
}
|
||||
case ERunPhase.Improve:
|
||||
{
|
||||
return ImproveRequest.Create(coreLoop);
|
||||
}
|
||||
case ERunPhase.Gamble:
|
||||
{
|
||||
return GambleRequest.Create(coreLoop);
|
||||
}
|
||||
case ERunPhase.BufferOverflow:
|
||||
{
|
||||
return BufferOverflowRequest.Create(coreLoop);
|
||||
}
|
||||
case ERunPhase.ExecuteProgram:
|
||||
{
|
||||
return ExecuteProgramRequest.Create(coreLoop);
|
||||
}
|
||||
case ERunPhase.Scoring:
|
||||
{
|
||||
return ScoringRequest.Create(coreLoop);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Publish(object payload)
|
||||
{
|
||||
Published?.Invoke(this, new(Interlocked.Increment(ref m_Sequence), DateTimeOffset.UtcNow, payload));
|
||||
}
|
||||
|
||||
private CoreLoop? m_CoreLoop;
|
||||
|
||||
private readonly Lock m_Gate = new();
|
||||
private Request? m_ExpectedRequest;
|
||||
private long m_Sequence;
|
||||
}
|
||||
Reference in New Issue
Block a user