Re-organize all projects (#4166)
This commit is contained in:
130
Content.Server/EUI/BaseEui.cs
Normal file
130
Content.Server/EUI/BaseEui.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Content.Server.EUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class to implement server-side for an EUI.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An EUI is a system for making a relatively-easy connection between client and server
|
||||
/// for the purposes of UIs.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// An equivalently named class much exist server side for an EUI to work.
|
||||
/// It will be instantiated, opened and closed automatically.
|
||||
/// </remarks>
|
||||
public abstract class BaseEui
|
||||
{
|
||||
private bool _isStateDirty = false;
|
||||
|
||||
/// <summary>
|
||||
/// The player that this EUI is open for.
|
||||
/// </summary>
|
||||
public IPlayerSession Player { get; private set; } = default!;
|
||||
public bool IsShutDown { get; private set; }
|
||||
public EuiManager Manager { get; private set; } = default!;
|
||||
public uint Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the UI has been opened. Do initializing logic here.
|
||||
/// </summary>
|
||||
public virtual void Opened()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the UI has been closed.
|
||||
/// </summary>
|
||||
public virtual void Closed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a message comes in from the client.
|
||||
/// </summary>
|
||||
public virtual void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the current UI state as dirty and queue for an update.
|
||||
/// </summary>
|
||||
/// <seealso cref="GetNewState"/>
|
||||
public void StateDirty()
|
||||
{
|
||||
if (_isStateDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isStateDirty = true;
|
||||
Manager.QueueStateUpdate(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called some time after <see cref="StateDirty"/> has been called
|
||||
/// to get a new UI state that can be sent to the client.
|
||||
/// </summary>
|
||||
public virtual EuiStateBase GetNewState()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to the client-side EUI.
|
||||
/// </summary>
|
||||
public void SendMessage(EuiMessageBase message)
|
||||
{
|
||||
var netMgr = IoCManager.Resolve<IServerNetManager>();
|
||||
var msg = netMgr.CreateNetMessage<MsgEuiMessage>();
|
||||
msg.Id = Id;
|
||||
msg.Message = message;
|
||||
|
||||
netMgr.ServerSendMessage(msg, Player.ConnectedClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the EUI, breaking the connection between client and server.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
Manager.CloseEui(this);
|
||||
}
|
||||
|
||||
internal void Shutdown()
|
||||
{
|
||||
Closed();
|
||||
IsShutDown = true;
|
||||
}
|
||||
|
||||
internal void DoStateUpdate()
|
||||
{
|
||||
_isStateDirty = false;
|
||||
|
||||
var state = GetNewState();
|
||||
|
||||
var netMgr = IoCManager.Resolve<IServerNetManager>();
|
||||
var msg = netMgr.CreateNetMessage<MsgEuiState>();
|
||||
msg.Id = Id;
|
||||
msg.State = state;
|
||||
|
||||
netMgr.ServerSendMessage(msg, Player.ConnectedClient);
|
||||
}
|
||||
|
||||
internal void Initialize(EuiManager manager, IPlayerSession player, uint id)
|
||||
{
|
||||
Manager = manager;
|
||||
Player = player;
|
||||
Id = id;
|
||||
Opened();
|
||||
}
|
||||
}
|
||||
}
|
||||
143
Content.Server/EUI/EuiManager.cs
Normal file
143
Content.Server/EUI/EuiManager.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Content.Server.EUI
|
||||
{
|
||||
public sealed class EuiManager : IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
[Dependency] private readonly IServerNetManager _net = default!;
|
||||
|
||||
private readonly Dictionary<IPlayerSession, PlayerEuiData> _playerData =
|
||||
new();
|
||||
|
||||
private readonly Queue<(IPlayerSession player, uint id)> _stateUpdateQueue =
|
||||
new Queue<(IPlayerSession, uint id)>();
|
||||
|
||||
private sealed class PlayerEuiData
|
||||
{
|
||||
public uint NextId = 1;
|
||||
public readonly Dictionary<uint, BaseEui> OpenUIs = new();
|
||||
}
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_players.PlayerStatusChanged += PlayerStatusChanged;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgEuiCtl>(MsgEuiCtl.NAME);
|
||||
_net.RegisterNetMessage<MsgEuiState>(MsgEuiState.NAME);
|
||||
_net.RegisterNetMessage<MsgEuiMessage>(MsgEuiMessage.NAME, RxMsgMessage);
|
||||
}
|
||||
|
||||
public void SendUpdates()
|
||||
{
|
||||
while (_stateUpdateQueue.TryDequeue(out var tuple))
|
||||
{
|
||||
var (player, id) = tuple;
|
||||
|
||||
// Check that UI and player still exist.
|
||||
// COULD have been removed in the mean time.
|
||||
if (!_playerData.TryGetValue(player, out var plyDat) || !plyDat.OpenUIs.TryGetValue(id, out var ui))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ui.DoStateUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenEui(BaseEui eui, IPlayerSession player)
|
||||
{
|
||||
if (eui.Id != 0)
|
||||
{
|
||||
throw new ArgumentException("That EUI is already open!");
|
||||
}
|
||||
|
||||
var data = _playerData[player];
|
||||
var newId = data.NextId++;
|
||||
eui.Initialize(this, player, newId);
|
||||
|
||||
data.OpenUIs.Add(newId, eui);
|
||||
|
||||
var msg = _net.CreateNetMessage<MsgEuiCtl>();
|
||||
msg.Id = newId;
|
||||
msg.Type = MsgEuiCtl.CtlType.Open;
|
||||
msg.OpenType = eui.GetType().Name;
|
||||
|
||||
_net.ServerSendMessage(msg, player.ConnectedClient);
|
||||
}
|
||||
|
||||
public void CloseEui(BaseEui eui)
|
||||
{
|
||||
eui.Shutdown();
|
||||
_playerData[eui.Player].OpenUIs.Remove(eui.Id);
|
||||
|
||||
var msg = _net.CreateNetMessage<MsgEuiCtl>();
|
||||
msg.Id = eui.Id;
|
||||
msg.Type = MsgEuiCtl.CtlType.Close;
|
||||
_net.ServerSendMessage(msg, eui.Player.ConnectedClient);
|
||||
}
|
||||
|
||||
private void RxMsgMessage(MsgEuiMessage message)
|
||||
{
|
||||
if (!_players.TryGetSessionByChannel(message.MsgChannel, out var ply))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_playerData.TryGetValue(ply, out var dat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dat.OpenUIs.TryGetValue(message.Id, out var eui))
|
||||
{
|
||||
Logger.WarningS("eui", $"Got EUI message from player {ply} for non-existing UI {message.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
eui.HandleMessage(message.Message);
|
||||
}
|
||||
|
||||
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus == SessionStatus.Connected)
|
||||
{
|
||||
_playerData.Add(e.Session, new PlayerEuiData());
|
||||
}
|
||||
else if (e.NewStatus == SessionStatus.Disconnected)
|
||||
{
|
||||
if (_playerData.TryGetValue(e.Session, out var plyDat))
|
||||
{
|
||||
// Gracefully close all open UIs.
|
||||
foreach (var ui in plyDat.OpenUIs.Values)
|
||||
{
|
||||
ui.Closed();
|
||||
}
|
||||
|
||||
_playerData.Remove(e.Session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueStateUpdate(BaseEui eui)
|
||||
{
|
||||
DebugTools.Assert(eui.Id != 0, "EUI has not been opened yet.");
|
||||
DebugTools.Assert(!eui.IsShutDown, "EUI has been closed.");
|
||||
|
||||
_stateUpdateQueue.Enqueue((eui.Player, eui.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user