using System;
using System.Collections.Generic;
namespace Luneraria.Core
{
///
/// In-process transport for two (or more) LuneSession instances (the loopback of
/// tools/luneraria/net_pair.gd without processes). Messages are delivered synchronously in
/// send order; frames go through the same path with SendFrame. Peer 1 is the host. A node
/// implements ILuneNetLink for exactly one peer and routes through the hub.
///
public sealed class LuneLoopback
{
sealed class Node : ILuneNetLink
{
readonly LuneLoopback _hub;
readonly int _peer;
public LuneSession Session;
public Node(LuneLoopback hub, int peer)
{
_hub = hub;
_peer = peer;
}
public void Send(int peer, string kind, object payload)
{
_hub.Deliver(_peer, peer, kind, payload);
}
public void SendFrame(int peer, int serial, double elapsed, float[] units, float[] buildingHp)
{
_hub.DeliverFrame(_peer, peer, serial, elapsed, units, buildingHp);
}
}
readonly Dictionary _nodes = new Dictionary();
/// Every message that left a peer (tests, diagnostics).
public readonly List Log = new List();
/// Attaches a session under a peer id and returns the session for chaining.
public LuneSession Attach(int peer, LuneSession session)
{
var node = new Node(this, peer) { Session = session };
_nodes[peer] = node;
session.Link = node;
return session;
}
/// Drops a peer and tells the authority (bot takeover, never a core loss).
public void Detach(int peer)
{
Node node;
if (!_nodes.TryGetValue(peer, out node))
return;
_nodes.Remove(peer);
if (node.Session != null)
{
node.Session.Link = null;
node.Session.Connected = false;
}
foreach (Node other in _nodes.Values)
{
if (other.Session != null && other.Session.IsAuthority())
other.Session.OnPeerDisconnected(peer);
}
}
/// True while the hub still knows the peer.
public bool Has(int peer) { return _nodes.ContainsKey(peer); }
void Deliver(int from, int to, string kind, object payload)
{
Log.Add(from + "→" + to + " " + kind);
Node node;
if (!_nodes.TryGetValue(to, out node) || node.Session == null)
return;
node.Session.OnMessage(from, kind, payload);
}
void DeliverFrame(int from, int to, int serial, double elapsed, float[] units, float[] buildingHp)
{
Node node;
if (!_nodes.TryGetValue(to, out node) || node.Session == null)
return;
node.Session.OnFrame(from, serial, elapsed, units, buildingHp);
}
}
}