Files
TeslaSuite/Console/TeslaConsole/MungaGame.cs
T
CydandClaude Opus 4.8 548550b312 Initial commit: TeslaSuite monorepo (TeslaConsole + TeslaLauncher)
Co-locate the two cockpit-pod projects into a single repository:

- Console/  : TeslaConsole, the net48 WinForms operator console (decompiled
              reconstruction) plus its differential + catalog test suite.
- Launcher/ : TeslaLauncher, the net6 pod-side Service + Agent rewrite.

Adds a combined TeslaSuite.sln, root README documenting the shared wire
contract (and its current duplication, the main follow-up), and a root
.gitignore. Histories were not preserved per request; this is a fresh start
from the current working state of both projects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 14:43:28 -05:00

365 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Munga.Net;
namespace TeslaConsole;
public class MungaGame
{
private readonly object mInternalLock = new object();
private readonly Pod mPod;
private Image mImage;
private string mStatusMessage;
private MungaSocket mSocket;
private DateTime mNextStateQuery = DateTime.MinValue;
private ApplicationState? mAppState;
private ApplicationID? mAppID;
private DateTime mEggDelayTimer = DateTime.MinValue;
private DateTime mEggSent = DateTime.MinValue;
private bool mEggAck;
private MungaConnectionState mState;
private readonly List<object> mRequestors = new List<object>();
private Form mOwner;
public Image Image => mImage;
public string StatusMessage => mStatusMessage;
public Pod Pod => mPod;
public ApplicationState? AppState => mAppState;
public ApplicationID? AppID => mAppID;
public DateTime EggDelayTimer
{
get
{
return mEggDelayTimer;
}
set
{
mEggDelayTimer = value;
}
}
public DateTime EggSent
{
get
{
return mEggSent;
}
set
{
mEggSent = value;
}
}
public bool EggAcknowledged => mEggAck;
public MungaConnectionState State
{
get
{
lock (mInternalLock)
{
if (mState == MungaConnectionState.Connected)
{
if (mSocket != null && mSocket.Connected)
{
return MungaConnectionState.Connected;
}
Disconnect();
}
return mState;
}
}
private set
{
lock (mInternalLock)
{
mState = value;
}
}
}
public bool Requested
{
get
{
lock (mInternalLock)
{
return mRequestors.Count > 0;
}
}
}
public bool IsOwned
{
get
{
if (mOwner != null && mOwner.IsDisposed)
{
mOwner = null;
}
return mOwner != null;
}
}
public event EventHandler OnPodStatusUpdated;
public void QueryStateIfNeeded()
{
DateTime now = DateTime.Now;
if (mNextStateQuery < now)
{
Send(0, 1, new StateQueryMessage(1));
mNextStateQuery = now.AddSeconds(1.0);
}
}
public bool IsPodAppState(ApplicationID app, ApplicationState state)
{
return IsPodAppState(app, new ApplicationState[1] { state });
}
public bool IsPodAppState(ApplicationID app, IEnumerable<ApplicationState> states)
{
if (IsPodOperational(app))
{
foreach (ApplicationState state in states)
{
if (mAppState.Value == state)
{
return true;
}
}
}
return false;
}
public bool IsPodOperational(ApplicationID app)
{
if (State == MungaConnectionState.Connected && mAppID.HasValue && mAppID.Value == app)
{
return mAppState.HasValue;
}
return false;
}
public void MakeRequested(object requestor)
{
lock (mInternalLock)
{
if (!mRequestors.Contains(requestor))
{
mRequestors.Add(requestor);
if (mRequestors.Count == 1)
{
Connect();
}
}
}
}
public void ReleaseRequest(object requestor)
{
lock (mInternalLock)
{
if (mRequestors.Contains(requestor))
{
mRequestors.Remove(requestor);
if (mRequestors.Count == 0)
{
Disconnect();
}
}
}
}
public bool IsOwner(Form owner)
{
if (mOwner != null && mOwner.IsDisposed)
{
mOwner = null;
}
return mOwner == owner;
}
public void TakeOwnership(Form owner)
{
lock (mInternalLock)
{
if (mOwner == null)
{
mOwner = owner;
ForceStatusUpdate();
}
}
}
public void ReleaseOwnership(Form owner)
{
lock (mInternalLock)
{
if (mOwner == owner)
{
mOwner = null;
ForceStatusUpdate();
}
}
}
public MungaGame(Pod pod)
{
mPod = pod;
}
public void SetStatus(Image img, string statusMessage)
{
lock (mInternalLock)
{
if (mImage != img || mStatusMessage != statusMessage)
{
mImage = img;
mStatusMessage = statusMessage;
ForceStatusUpdate();
}
}
}
private void ForceStatusUpdate()
{
if (this.OnPodStatusUpdated != null)
{
this.OnPodStatusUpdated(this, EventArgs.Empty);
}
}
private void Connect()
{
lock (mInternalLock)
{
if (State != 0)
{
return;
}
State = MungaConnectionState.Connecting;
ShutdownSocket();
mSocket = new MungaSocket();
mSocket.BeginConnect(mPod.IPAddress, 1501, delegate(IAsyncResult ar)
{
lock (mInternalLock)
{
try
{
mSocket.EndConnect(ar);
State = MungaConnectionState.Connected;
}
catch
{
Disconnect();
}
}
}, null);
}
}
private void Disconnect()
{
lock (mInternalLock)
{
State = MungaConnectionState.Disconnected;
mAppState = null;
mAppID = null;
mNextStateQuery = DateTime.MinValue;
ShutdownSocket();
if (Requested)
{
Connect();
}
}
}
private void ShutdownSocket()
{
if (mSocket != null)
{
try
{
mSocket.Shutdown();
}
catch
{
}
mSocket = null;
}
}
public MetaMessage Receive()
{
lock (mInternalLock)
{
try
{
MetaMessage metaMessage = mSocket.Receive();
if (metaMessage != null)
{
if (metaMessage.Message is StateResponseMessage)
{
StateResponseMessage stateResponseMessage = (StateResponseMessage)metaMessage.Message;
mAppID = stateResponseMessage.Application;
if (stateResponseMessage.ApplicationState == ApplicationState.WaitingForEgg && stateResponseMessage.ApplicationState != mAppState)
{
mEggDelayTimer = DateTime.Now.AddSeconds(5.0);
mEggSent = DateTime.MinValue;
mEggAck = false;
}
mAppState = stateResponseMessage.ApplicationState;
}
else if (metaMessage.Message is AcknowledgeEggFileMessage)
{
mEggAck = true;
}
}
return metaMessage;
}
catch
{
Disconnect();
return null;
}
}
}
public void Send(int gameID, int fromHost, MungaMessage message)
{
lock (mInternalLock)
{
try
{
mSocket.Send(gameID, fromHost, message);
}
catch
{
Disconnect();
}
}
}
}