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); } } }