using System.Collections.Generic;
namespace Luneraria.Core
{
/// Roles of a session (lune_session.gd Role).
public enum LuneRole { Offline, Host, Client }
/// One lobby row: peer 0 is a bot, peer 1 the host.
public sealed class LobbyEntry
{
public int Peer;
public int Slot;
public string Name = "";
public bool Ready;
public bool Bot;
public LobbyEntry Clone() { return (LobbyEntry)MemberwiseClone(); }
}
/// Result of a session intent (Godot returns a Dictionary with ok, message, pending).
public struct SessionResult
{
public bool Ok;
public string Message;
public bool Pending;
public SessionResult(bool ok, string message, bool pending = false)
{
Ok = ok;
Message = message;
Pending = pending;
}
}
/// One player row of the public state; Draft is set only for the receiving seat.
public sealed class NetPlayerRow
{
public int Slot;
public string Name = "";
public bool IsHuman;
public int Gold;
public bool Ready;
public int Earned;
public int Spent;
public int NextSeq;
public List Roster = new List();
public HeroState Hero;
public List Bookings = new List();
/// Private draft of the receiving seat only; null for every other seat.
public Draft Draft;
/// Undo stack size of the receiving seat (0 for others).
public int Undo;
}
/// Public state of the match for one seat (rpc_state).
public sealed class NetState
{
public Phase Phase;
public int Round;
public int Winner;
public string EndNote = "";
public Dictionary BuildingHp = new Dictionary();
public BossState Boss = new BossState();
public Settlement LastSettlement;
public List DestroyedCores = new List();
public List Players = new List();
}
/// A mobile unit as it crosses the wire (rpc_combat_begin / rpc_units_spawned).
public sealed class NetUnitRecord
{
public int Id;
public string Kind = "";
public int Team;
public int TeamIndex;
public int OwnerSlot = -1;
public string Uid = "";
public string Lane = "";
public string Zone = "";
public UnitDef Def = new UnitDef();
public double X;
public double Y;
public double Facing;
public double Hp;
public double MaxHp;
public bool Alive;
}
///
/// Outbound session messages (the Godot RPCs). A transport or a test recorder implements this;
/// without a link the session still runs offline and for in-process host tests.
///
public interface ILuneNetLink
{
/// Reliable message to one peer (1 = host).
void Send(int peer, string kind, object payload);
/// Unreliable ordered combat frame to one peer.
void SendFrame(int peer, int serial, double elapsed, float[] units, float[] buildingHp);
}
/// Frames carry 13 floats per mobile unit (lune_session.gd FRAME_STRIDE).
public static class LuneNet
{
public const int DefaultPort = 24571;
public const int MaxClients = 5;
public const int Protocol = 4;
/// Seconds between combat snapshots the host sends.
public const double FrameInterval = 0.05;
public const int FrameStride = 13;
public const string KHello = "hello";
public const string KSubmit = "submit";
public const string KReady = "ready";
public const string KRefused = "refused";
public const string KFeedback = "feedback";
public const string KSetup = "setup";
public const string KState = "state";
public const string KLobby = "lobby";
public const string KCombatBegin = "combat_begin";
public const string KUnitsSpawned = "units_spawned";
}
}