parent
c47264dfdb
commit
e0566ffa3e
24 changed files with 594 additions and 72 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Client._Sunrise.ServersHub;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
|
|
@ -71,6 +72,7 @@ namespace Content.Client.Entry
|
|||
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
|
||||
[Dependency] private readonly ServersHubManager _serversHubManager = default!; // Sunrise-Hub
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
|
|
@ -133,6 +135,8 @@ namespace Content.Client.Entry
|
|||
_jobRequirements.Initialize();
|
||||
_playbackMan.Initialize();
|
||||
|
||||
_serversHubManager.Initialize(); // Sunrise-Hub
|
||||
|
||||
//AUTOSCALING default Setup!
|
||||
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffX", 1080);
|
||||
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffY", 720);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Client.Administration.Managers;
|
||||
using Content.Client._Sunrise.ServersHub;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
using Content.Client.Clickable;
|
||||
|
|
@ -50,6 +51,10 @@ namespace Content.Client.IoC
|
|||
collection.Register<DocumentParsingManager>();
|
||||
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
||||
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
||||
|
||||
// Sunrise
|
||||
|
||||
collection.Register<ServersHubManager>(); // Sunrise-Hub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,54 +2,66 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:parallax="clr-namespace:Content.Client.Parallax"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:serversHub="clr-namespace:Content.Client._Sunrise.ServersHub">
|
||||
<parallax:ParallaxControl />
|
||||
<Control HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<PanelContainer StyleClasses="AngleRect" />
|
||||
<BoxContainer Orientation="Vertical" MinSize="300 200">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Margin="8 0 0 0" Text="{Loc 'connecting-title'}"
|
||||
StyleClasses="LabelHeading" VAlign="Center" />
|
||||
<Button Name="ExitButton" Text="{Loc 'connecting-exit'}"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<controls:HighDivider />
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" Margin="4 4 4 0">
|
||||
<Control VerticalExpand="True" Margin="0 0 0 8">
|
||||
<BoxContainer Orientation="Vertical" Name="ConnectingStatus">
|
||||
<Label Text="{Loc 'connecting-in-progress'}" Align="Center" />
|
||||
<!-- Who the fuck named these cont- oh wait I did -->
|
||||
<Label Name="ConnectStatus" StyleClasses="LabelSubText" Align="Center" />
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="AngleRect">
|
||||
<BoxContainer Orientation="Vertical" MinSize="300 200">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Margin="8 0 0 0" Text="{Loc 'connecting-title'}"
|
||||
StyleClasses="LabelHeading" VAlign="Center" />
|
||||
<Button Name="ExitButton" Text="{Loc 'connecting-exit'}"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" Name="ConnectFail" Visible="False">
|
||||
<RichTextLabel Name="ConnectFailReason" VerticalAlignment="Stretch"/>
|
||||
<Button Name="RetryButton" Text="{Loc 'connecting-retry'}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True" VerticalAlignment="Bottom" />
|
||||
<controls:HighDivider />
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" Margin="4 4 4 0">
|
||||
<Control VerticalExpand="True" Margin="0 0 0 8">
|
||||
<BoxContainer Orientation="Vertical" Name="ConnectingStatus">
|
||||
<Label Text="{Loc 'connecting-in-progress'}" Align="Center" />
|
||||
<!-- Who the fuck named these cont- oh wait I did -->
|
||||
<Label Name="ConnectStatus" StyleClasses="LabelSubText" Align="Center" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" Name="ConnectFail" Visible="False">
|
||||
<RichTextLabel Name="ConnectFailReason" VerticalAlignment="Stretch"/>
|
||||
<Button Name="RetryButton" Text="{Loc 'connecting-retry'}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True" VerticalAlignment="Bottom" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" Name="Disconnected">
|
||||
<Label Text="{Loc 'connecting-disconnected'}" Align="Center" />
|
||||
<Label Name="DisconnectReason" Align="Center" />
|
||||
<Button Name="ReconnectButton" Text="{Loc 'connecting-reconnect'}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True" VerticalAlignment="Bottom" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
<Label Name="ConnectingAddress" StyleClasses="LabelSubText" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" Name="Disconnected">
|
||||
<Label Text="{Loc 'connecting-disconnected'}" Align="Center" />
|
||||
<Label Name="DisconnectReason" Align="Center" />
|
||||
<Button Name="ReconnectButton" Text="{Loc 'connecting-reconnect'}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True" VerticalAlignment="Bottom" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
<Label Name="ConnectingAddress" StyleClasses="LabelSubText" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#444" ContentMarginTopOverride="2" />
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#444" ContentMarginTopOverride="2" />
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" Margin="12 0 4 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc 'connecting-tip'}" StyleClasses="LabelSubText" />
|
||||
<Label Text="{Loc 'connecting-version'}" StyleClasses="LabelSubText"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="12 0 4 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc 'connecting-tip'}" StyleClasses="LabelSubText" />
|
||||
<Label Text="{Loc 'connecting-version'}" StyleClasses="LabelSubText"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True" Margin="5 0 0 0" Name="ServersHub" MinWidth="600" MinHeight="220">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" Margin="3 3 3 3">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False" HorizontalExpand="True">
|
||||
<serversHub:ServersHub Name="ServersHubBody" Access="Public" />
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
||||
<!-- Bottom window for tips -->
|
||||
<PanelContainer Name="LoginTips" StyleClasses="AngleRect" Margin="0 10" MaxWidth="600" VerticalExpand="True" VerticalAlignment="Bottom">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Content.Client.Launcher
|
|||
[GenerateTypedNameReferences]
|
||||
public sealed partial class LauncherConnectingGui : Control
|
||||
{
|
||||
private const float RedialWaitTimeSeconds = 15f;
|
||||
private const float RedialWaitTimeSeconds = 30f; // Sunrise-edit
|
||||
private readonly LauncherConnecting _state;
|
||||
private float _waitTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
xmlns:lobbyUi="clr-namespace:Content.Client.Lobby.UI"
|
||||
xmlns:info="clr-namespace:Content.Client.Info"
|
||||
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Chat.Widgets"
|
||||
xmlns:changelog="clr-namespace:Content.Client.Changelog">
|
||||
xmlns:changelog="clr-namespace:Content.Client.Changelog"
|
||||
xmlns:serversHub="clr-namespace:Content.Client._Sunrise.ServersHub">
|
||||
<!-- Sunrise-start -->
|
||||
<!-- Background -->
|
||||
<!--<TextureRect Access="Public" VerticalExpand="True" HorizontalExpand="True" Name="Background"
|
||||
|
|
@ -26,31 +27,43 @@
|
|||
<!-- LHS Controls -->
|
||||
<BoxContainer Name="LeftSide" Orientation="Vertical" SeparationOverride="4" HorizontalExpand="True">
|
||||
<Control Name="DefaultState" VerticalExpand="True">
|
||||
<BoxContainer Name="TopLeft" Orientation="Vertical">
|
||||
<BoxContainer Name="TopLeft" Orientation="Horizontal">
|
||||
<!-- Left Top Panel -->
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalAlignment="Left" Name="LeftSideTop"
|
||||
VerticalAlignment="Top">
|
||||
<BoxContainer Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="800">
|
||||
<info:LinkBanner Name="LinkBanner" VerticalExpand="false" HorizontalAlignment="Center"
|
||||
Margin="3 3 3 3" />
|
||||
<controls:StripeBack>
|
||||
<BoxContainer Orientation="Horizontal" SeparationOverride="6" Margin="3 3 3 3">
|
||||
<cc:UICommandButton Command="observe" Name="ObserveButton" Access="Public"
|
||||
Text="{Loc 'ui-lobby-observe-button'}"
|
||||
StyleClasses="ButtonBig"
|
||||
WindowType="{x:Type lobbyUi:ObserveWarningWindow}" />
|
||||
<Label Name="StartTime"
|
||||
Access="Public"
|
||||
Align="Left"
|
||||
FontColorOverride="{x:Static maths:Color.DarkGray}"
|
||||
StyleClasses="LabelBig" HorizontalExpand="True" />
|
||||
<Button Name="ReadyButton" Access="Public" ToggleMode="True"
|
||||
Text="{Loc 'ui-lobby-ready-up-button'}"
|
||||
StyleClasses="ButtonBig" MinWidth="137" />
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalAlignment="Left" Name="LeftSideTop"
|
||||
VerticalAlignment="Top" MinWidth="600">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" MaxWidth="800">
|
||||
<info:LinkBanner Name="LinkBanner" VerticalExpand="false" HorizontalAlignment="Center"
|
||||
Margin="3 3 3 3" />
|
||||
<controls:StripeBack>
|
||||
<BoxContainer Orientation="Horizontal" SeparationOverride="6" Margin="3 3 3 3"
|
||||
HorizontalExpand="True">
|
||||
<cc:UICommandButton Command="observe" Name="ObserveButton" Access="Public"
|
||||
Text="{Loc 'ui-lobby-observe-button'}"
|
||||
StyleClasses="ButtonBig"
|
||||
WindowType="{x:Type lobbyUi:ObserveWarningWindow}" />
|
||||
<Label Name="StartTime"
|
||||
Access="Public"
|
||||
Align="Left"
|
||||
FontColorOverride="{x:Static maths:Color.DarkGray}"
|
||||
StyleClasses="LabelBig" HorizontalExpand="True" />
|
||||
<Button Name="ReadyButton" Access="Public" ToggleMode="True"
|
||||
Text="{Loc 'ui-lobby-ready-up-button'}"
|
||||
StyleClasses="ButtonBig" MinWidth="137" />
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<!-- Sunrise-edit: Servers Hub -->
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True" Margin="5 0 0 0" Name="ServersHub" MinWidth="600" MinHeight="200">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" Margin="3 3 3 3">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False" HorizontalExpand="True">
|
||||
<serversHub:ServersHub Name="ServersHubBody" Access="Public" />
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<!-- Sunrise-edit: Servers Hub -->
|
||||
</BoxContainer>
|
||||
<!-- Voting Popups -->
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="4" Name="VoteContainer"
|
||||
Access="Public" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0 8" />
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Robust.Client.UserInterface.XAML;
|
|||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Numerics;
|
||||
using Content.Client._Sunrise.ServersHub;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Content.Client.Resources;
|
||||
using Robust.Client.Graphics;
|
||||
|
|
@ -60,6 +61,9 @@ namespace Content.Client.Lobby.UI
|
|||
LocalChangelog.PanelOverride = back;
|
||||
|
||||
LobbySongPanel.PanelOverride = back;
|
||||
|
||||
ServersHub.PanelOverride = back;
|
||||
|
||||
// Sunrise-end
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Content.Client.UserInterface.Systems.Ghost.Widgets;
|
|||
using Content.Shared.Ghost;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Content.Client._Sunrise.ServersHub;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Ghost;
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ namespace Content.Client.UserInterface.Systems.Ghost;
|
|||
public sealed class GhostUIController : UIController, IOnSystemChanged<GhostSystem>
|
||||
{
|
||||
[Dependency] private readonly IEntityNetworkManager _net = default!;
|
||||
[Dependency] private readonly ServersHubManager _serversHubManager = default!;
|
||||
|
||||
[UISystemDependency] private readonly GhostSystem? _system = default;
|
||||
|
||||
|
|
@ -125,6 +127,7 @@ public sealed class GhostUIController : UIController, IOnSystemChanged<GhostSyst
|
|||
Gui.RequestWarpsPressed += RequestWarps;
|
||||
Gui.ReturnToBodyPressed += ReturnToBody;
|
||||
Gui.GhostRolesPressed += GhostRolesPressed;
|
||||
Gui.ChangeServerPressed += ChangeServerPressed;
|
||||
Gui.TargetWindow.WarpClicked += OnWarpClicked;
|
||||
Gui.TargetWindow.OnGhostnadoClicked += OnGhostnadoClicked;
|
||||
|
||||
|
|
@ -139,6 +142,7 @@ public sealed class GhostUIController : UIController, IOnSystemChanged<GhostSyst
|
|||
Gui.RequestWarpsPressed -= RequestWarps;
|
||||
Gui.ReturnToBodyPressed -= ReturnToBody;
|
||||
Gui.GhostRolesPressed -= GhostRolesPressed;
|
||||
Gui.ChangeServerPressed -= ChangeServerPressed;
|
||||
Gui.TargetWindow.WarpClicked -= OnWarpClicked;
|
||||
|
||||
Gui.Hide();
|
||||
|
|
@ -160,4 +164,9 @@ public sealed class GhostUIController : UIController, IOnSystemChanged<GhostSyst
|
|||
{
|
||||
_system?.OpenGhostRoles();
|
||||
}
|
||||
|
||||
private void ChangeServerPressed()
|
||||
{
|
||||
_serversHubManager.OpenServersHub();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
<widgets:GhostGui xmlns="https://spacestation14.io"
|
||||
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Ghost.Widgets"
|
||||
HorizontalAlignment="Center">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="ReturnToBodyButton" Text="{Loc ghost-gui-return-to-body-button}" />
|
||||
<Button Name="GhostWarpButton" Text="{Loc ghost-gui-ghost-warp-button}" />
|
||||
<Button Name="GhostRolesButton" />
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="ReturnToBodyButton" Text="{Loc ghost-gui-return-to-body-button}" />
|
||||
<Button Name="GhostWarpButton" Text="{Loc ghost-gui-ghost-warp-button}" />
|
||||
<Button Name="GhostRolesButton" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Name="ChangeServerButton" Text="{Loc ghost-gui-change-server}"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</widgets:GhostGui>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public sealed partial class GhostGui : UIWidget
|
|||
public event Action? RequestWarpsPressed;
|
||||
public event Action? ReturnToBodyPressed;
|
||||
public event Action? GhostRolesPressed;
|
||||
public event Action? ChangeServerPressed;
|
||||
|
||||
public GhostGui()
|
||||
{
|
||||
|
|
@ -26,6 +27,7 @@ public sealed partial class GhostGui : UIWidget
|
|||
GhostWarpButton.OnPressed += _ => RequestWarpsPressed?.Invoke();
|
||||
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
|
||||
ChangeServerButton.OnPressed += _ => ChangeServerPressed?.Invoke();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
|
|
|
|||
12
Content.Client/_Sunrise/ServersHub/ServersHub.xaml
Normal file
12
Content.Client/_Sunrise/ServersHub/ServersHub.xaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<controls:StripeBack>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label HorizontalExpand="True" Name="TotalPlayers" VAlign="Center"
|
||||
StyleClasses="LabelHeading" Align="Center"/>
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
<controls:ListContainer Name="ServersList" Access="Public" HorizontalExpand="True"/>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
76
Content.Client/_Sunrise/ServersHub/ServersHub.xaml.cs
Normal file
76
Content.Client/_Sunrise/ServersHub/ServersHub.xaml.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using System.Linq;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._Sunrise.ServersHub;
|
||||
using Robust.Client;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._Sunrise.ServersHub
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ServersHub : Control
|
||||
{
|
||||
[Dependency] private readonly IGameController _gameController = default!;
|
||||
[Dependency] private readonly ServersHubManager _serversHubManager = default!;
|
||||
|
||||
private Action<string>? ConnectServer { get; set; }
|
||||
|
||||
public ServersHub()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_serversHubManager.ServersDataListChanged += RefreshServersList;
|
||||
|
||||
ServersList.GenerateItem += GenerateButton;
|
||||
|
||||
RefreshServersList(_serversHubManager.ServersDataList);
|
||||
|
||||
ConnectServer += ConnectToServer;
|
||||
}
|
||||
|
||||
private void ConnectToServer(string url)
|
||||
{
|
||||
// Почему-то данная хуйня всегда будет закрывать окно игры и открывать заново, даже если подключение идет
|
||||
// к серверу идентичного билда, почему нельзя было сделать метод редиала в этом же окне - загадка.
|
||||
// Я был рад поебать позги ПЖБ но мне кажется он опять пошлет меня нахуй.
|
||||
_gameController.Redial(url);
|
||||
}
|
||||
|
||||
private void RefreshServersList(List<ServerHubEntry> servers)
|
||||
{
|
||||
var sortedServers = new List<ServerHubEntry>(servers);
|
||||
sortedServers.Sort(Compare);
|
||||
|
||||
ServersList.PopulateList(sortedServers.Select(info => new ServerListData(info))
|
||||
.ToList());
|
||||
|
||||
var totalPlayers = servers.Sum(server => server.CurrentPlayers);
|
||||
var maxPlayers = servers.Sum(server => server.MaxPlayers);
|
||||
// Очень круто показывать общее количество игроков со всех серверов, сразу видно какой проект бальшой.
|
||||
TotalPlayers.Text = $"Сейчас играет: {totalPlayers}/{maxPlayers}";
|
||||
}
|
||||
|
||||
private int Compare(ServerHubEntry x, ServerHubEntry y)
|
||||
{
|
||||
return y.CurrentPlayers.CompareTo(x.CurrentPlayers);
|
||||
}
|
||||
|
||||
private void GenerateButton(ListData data, ListContainerButton button)
|
||||
{
|
||||
if (data is not ServerListData { Info: var info})
|
||||
return;
|
||||
|
||||
var entry = new ServersHubEntry(info.Title, info.CurrentPlayers, info.MaxPlayers, info.ConnectUrl, info.CanConnect, ConnectServer);
|
||||
button.AddChild(entry);
|
||||
button.ToolTip = $"Режим: {info.Preset} | Станция: {info.StationName}";
|
||||
// Уменьшение задержки до милипиздрической ибо зумерки любят так быстро водить мышкой что чаще всего вообще
|
||||
// не знают что в игре существуют такие подсказки (Проверено на причинах блокировки ролей в лобби, они их
|
||||
// в лоб не видят)
|
||||
button.TooltipDelay = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
public record ServerListData(ServerHubEntry Info) : ListData;
|
||||
}
|
||||
29
Content.Client/_Sunrise/ServersHub/ServersHubEntry.xaml
Normal file
29
Content.Client/_Sunrise/ServersHub/ServersHubEntry.xaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<PanelContainer xmlns="https://spacestation14.io"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Name="BackgroundColorPanel">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<customControls:HSeparator/>
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
HorizontalExpand="True"
|
||||
SeparationOverride="3">
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="TitleLabel"
|
||||
SizeFlagsStretchRatio="5"
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="PlayersCountLabel"
|
||||
SizeFlagsStretchRatio="1"
|
||||
HorizontalExpand="True"
|
||||
Align="Right"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Button Name="ConnectButton"
|
||||
Text="Подключиться"
|
||||
SizeFlagsStretchRatio="3"
|
||||
MinWidth="180"/>
|
||||
<customControls:VSeparator/>
|
||||
</BoxContainer>
|
||||
<customControls:HSeparator/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
28
Content.Client/_Sunrise/ServersHub/ServersHubEntry.xaml.cs
Normal file
28
Content.Client/_Sunrise/ServersHub/ServersHubEntry.xaml.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._Sunrise.ServersHub;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ServersHubEntry : PanelContainer
|
||||
{
|
||||
private readonly Action<string>? _connectToServer;
|
||||
|
||||
public ServersHubEntry(string serverTitle, int currentPlayerCount, int maxPlayerCount, string connectUrl, bool canConnect, Action<string>? connectToServer)
|
||||
{
|
||||
_connectToServer = connectToServer;
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
TitleLabel.Text = serverTitle;
|
||||
PlayersCountLabel.Text = $"{currentPlayerCount}/{maxPlayerCount}";
|
||||
|
||||
ConnectButton.OnPressed += _ => ConnectToServer(connectUrl);
|
||||
// Нам нахуй не нужна локализация, поэтому так.
|
||||
ConnectButton.Text = canConnect ? "Подключиться" : "Вы уже здесь";
|
||||
// Банальная защита от дебила, ибо реконект к серверу на котором ты есть занимает столько же как и к другому.
|
||||
ConnectButton.Disabled = !canConnect;
|
||||
}
|
||||
|
||||
private void ConnectToServer(string url) => _connectToServer?.Invoke(url);
|
||||
}
|
||||
38
Content.Client/_Sunrise/ServersHub/ServersHubManager.cs
Normal file
38
Content.Client/_Sunrise/ServersHub/ServersHubManager.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using Content.Shared._Sunrise.ServersHub;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Client._Sunrise.ServersHub;
|
||||
|
||||
public partial class ServersHubManager
|
||||
{
|
||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||
|
||||
public event Action<List<ServerHubEntry>>? ServersDataListChanged;
|
||||
|
||||
public List<ServerHubEntry> ServersDataList = [];
|
||||
|
||||
private ServersHubUi? _menu;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgFullServerHubList>(OnServersDataChanged);
|
||||
|
||||
_menu = new ServersHubUi();
|
||||
}
|
||||
|
||||
// Ахуеть какой костыль, но явно лучше чем писать лишние 300 строк.
|
||||
public void OpenServersHub()
|
||||
{
|
||||
_menu = new ServersHubUi();
|
||||
_menu.OnClose += _menu.Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
private void OnServersDataChanged(MsgFullServerHubList msg)
|
||||
{
|
||||
// Храним всю инфу внутри данного менеджера чтобы даже если конект с сервером будет разорван у нас работал хаб,
|
||||
// и его можно было отобразить после отключения или бана.
|
||||
ServersDataList = msg.ServersHubEntries;
|
||||
ServersDataListChanged?.Invoke(ServersDataList);
|
||||
}
|
||||
}
|
||||
10
Content.Client/_Sunrise/ServersHub/ServersHubUi.xaml
Normal file
10
Content.Client/_Sunrise/ServersHub/ServersHubUi.xaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:serversHub="clr-namespace:Content.Client._Sunrise.ServersHub"
|
||||
Title="Servers Hub"
|
||||
MinSize="650 300">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" Margin="3 3 3 3">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False" HorizontalExpand="True" MinWidth="300">
|
||||
<serversHub:ServersHub Name="ServersHubBody" Access="Public" />
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
16
Content.Client/_Sunrise/ServersHub/ServersHubUi.xaml.cs
Normal file
16
Content.Client/_Sunrise/ServersHub/ServersHubUi.xaml.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._Sunrise.ServersHub;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ServersHubUi : DefaultWindow
|
||||
{
|
||||
public ServersHubUi()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
// Я не ебу что тут вообще еще должно быть, вся логика один хуй лежит внутри Control
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Server._Sunrise.GuideGenerator;
|
||||
using Content.Server._Sunrise.ServersHub;
|
||||
using Content.Server._Sunrise.TTS;
|
||||
using Content.Server.Acz;
|
||||
using Content.Server.Administration;
|
||||
|
|
@ -108,6 +109,8 @@ namespace Content.Server.Entry
|
|||
IoCManager.Resolve<ServerInfoManager>().Initialize();
|
||||
IoCManager.Resolve<ServerApi>().Initialize();
|
||||
|
||||
IoCManager.Resolve<ServersHubManager>().Initialize(); // Sunrise-Hub
|
||||
|
||||
_voteManager.Initialize();
|
||||
_updateManager.Initialize();
|
||||
_playTimeTracking.Initialize();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Server._Sunrise.ServersHub;
|
||||
using Content.Server._Sunrise.TTS;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
|
|
@ -65,6 +66,8 @@ namespace Content.Server.IoC
|
|||
IoCManager.Register<ISharedPlaytimeManager, PlayTimeTrackingManager>();
|
||||
IoCManager.Register<ServerApi>();
|
||||
IoCManager.Register<JobWhitelistManager>();
|
||||
|
||||
IoCManager.Register<ServersHubManager>(); // Sunrise-Hub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
168
Content.Server/_Sunrise/ServersHub/ServersHubManager.cs
Normal file
168
Content.Server/_Sunrise/ServersHub/ServersHubManager.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared._Sunrise.ServersHub;
|
||||
using Content.Shared._Sunrise.SunriseCCVars;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._Sunrise.ServersHub;
|
||||
|
||||
public sealed partial class ServersHubManager
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IServerNetManager _netMgr = default!;
|
||||
|
||||
private readonly List<ServerHubEntry> _serverDataList = new();
|
||||
|
||||
private List<string> _serversList = new();
|
||||
|
||||
private readonly HttpClient _httpClient = new();
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
private CancellationTokenSource _cts = new();
|
||||
|
||||
// Не уверен что надо так часто это делать.
|
||||
private readonly TimeSpan _updateRate = TimeSpan.FromSeconds(15);
|
||||
|
||||
private static readonly Regex RestrictedNameRegex = ServerNameRegex();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_sawmill = _logManager.GetSawmill("serversHub");
|
||||
|
||||
_cfg.OnValueChanged(SunriseCCVars.ServersHubList, OnServerListChanged, true);
|
||||
|
||||
Task.Run(async () => await PeriodicUpdateServerData(_cts.Token));
|
||||
|
||||
_netMgr.RegisterNetMessage<MsgFullServerHubList>();
|
||||
}
|
||||
|
||||
private void OnServerListChanged(string serverList)
|
||||
{
|
||||
_serversList = serverList.Split(',').ToList();
|
||||
}
|
||||
|
||||
// Ахуенный план, надеждный блядь как швейцарские часы нахуй.
|
||||
private async Task PeriodicUpdateServerData(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await UpdateServerData();
|
||||
await Task.Delay(_updateRate, token);
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
_sawmill.Info($"Task was cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateServerData()
|
||||
{
|
||||
_serverDataList.Clear();
|
||||
|
||||
if (_serversList.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var serverUrl in _serversList)
|
||||
{
|
||||
var data = await RefreshServerData(serverUrl);
|
||||
if (data == null)
|
||||
continue;
|
||||
|
||||
var thisServerUrl = _cfg.GetCVar(CVars.HubServerUrl);
|
||||
|
||||
var serverName = RestrictedNameRegex.Replace(data.Name, string.Empty);
|
||||
_serverDataList.Add(new ServerHubEntry(
|
||||
serverName,
|
||||
data.Map ?? "",
|
||||
data.Preset ?? "",
|
||||
data.Players,
|
||||
data.Soft_Max_Players,
|
||||
$"ss14s://{NormalizeUrl(serverUrl)}",
|
||||
NormalizeUrl(thisServerUrl) != NormalizeUrl(serverUrl)));
|
||||
}
|
||||
|
||||
SendFullPlayerList(_playerManager.Sessions);
|
||||
}
|
||||
|
||||
private string NormalizeUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
return $"{uri.Host}{uri.AbsolutePath.TrimEnd('/')}";
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
_sawmill.Error($"Invalid URL format: {url}");
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ServerDataResponse?> RefreshServerData(string url, CancellationToken cancel = default)
|
||||
{
|
||||
using var resp = await _httpClient.GetAsync($"{url}/status", cancel);
|
||||
|
||||
if (resp.StatusCode == HttpStatusCode.NotFound)
|
||||
return null;
|
||||
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
_sawmill.Error("Auth server returned bad response {StatusCode}!", resp.StatusCode);
|
||||
return null;
|
||||
}
|
||||
|
||||
var responseData = await resp.Content.ReadFromJsonAsync<ServerDataResponse>(cancellationToken: cancel);
|
||||
|
||||
return responseData;
|
||||
}
|
||||
|
||||
// Я в душе не ебу почему без _ оно не хочет парсить некоторые строки с json, но кому не похуй?
|
||||
[UsedImplicitly]
|
||||
private sealed record ServerDataResponse(
|
||||
string Name,
|
||||
string? Map,
|
||||
int Round_Id,
|
||||
int Players,
|
||||
int Soft_Max_Players,
|
||||
bool Panic_Bunker,
|
||||
int Run_Level,
|
||||
string? Preset,
|
||||
string? Round_Start_Time);
|
||||
|
||||
private void SendFullPlayerList(ICommonSession[] sessions)
|
||||
{
|
||||
var netMsg = new MsgFullServerHubList();
|
||||
netMsg.ServersHubEntries = _serverDataList;
|
||||
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
try
|
||||
{
|
||||
_netMgr.ServerSendMessage(netMsg, session.Channel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Без данного Exception любые ошибки будут происходить абсолютно незаметно потому что вызывается это в асинхронном таске.
|
||||
_sawmill.Error($"Failed to send event to {session.Name}: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"[^А-Яа-яA-Za-zёЁ0-9' \-\.\[\]—:|]")]
|
||||
private static partial Regex ServerNameRegex();
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._Sunrise.ServersHub;
|
||||
|
||||
public sealed class MsgFullServerHubList : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
|
||||
|
||||
public List<ServerHubEntry> ServersHubEntries { get; set; } = [];
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
var count = buffer.ReadInt32();
|
||||
ServersHubEntries.EnsureCapacity(count);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
ServersHubEntries.Add(new ServerHubEntry(
|
||||
buffer.ReadString(),
|
||||
buffer.ReadString(),
|
||||
buffer.ReadString(),
|
||||
buffer.ReadInt32(),
|
||||
buffer.ReadInt32(),
|
||||
buffer.ReadString(),
|
||||
buffer.ReadBoolean()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.Write(ServersHubEntries.Count);
|
||||
foreach (var server in ServersHubEntries)
|
||||
{
|
||||
buffer.Write(server.Title);
|
||||
buffer.Write(server.StationName);
|
||||
buffer.Write(server.Preset);
|
||||
buffer.Write(server.CurrentPlayers);
|
||||
buffer.Write(server.MaxPlayers);
|
||||
buffer.Write(server.ConnectUrl);
|
||||
buffer.Write(server.CanConnect);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Content.Shared/_Sunrise/ServersHub/ServerHubEntry.cs
Normal file
14
Content.Shared/_Sunrise/ServersHub/ServerHubEntry.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._Sunrise.ServersHub
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public sealed record ServerHubEntry(
|
||||
string Title,
|
||||
string StationName,
|
||||
string Preset,
|
||||
int CurrentPlayers,
|
||||
int MaxPlayers,
|
||||
string ConnectUrl,
|
||||
bool CanConnect);
|
||||
}
|
||||
|
|
@ -90,4 +90,14 @@ public sealed class SunriseCCVars
|
|||
/// </summary>
|
||||
public static readonly CVarDef<bool> PeacefulRoundEnd =
|
||||
CVarDef.Create("game.peaceful_end", true, CVar.SERVERONLY);
|
||||
|
||||
/*
|
||||
* Servers Hub
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Список серверов отображаемых в хабе. Разделяются через запятую.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> ServersHubList =
|
||||
CVarDef.Create("servers_hub.urls", "", CVar.SERVERONLY);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,3 +209,16 @@ Entries:
|
|||
type: Tweak
|
||||
id: 18
|
||||
time: '2024-06-04T07:01:10.279625+00:00'
|
||||
- author: VigersRay
|
||||
changes:
|
||||
- message: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D \u0445\u0430\u0431\
|
||||
\ \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u0432 \u043F\u0440\u043E\u0435\u043A\
|
||||
\u0442\u0430 \u0432 \u043B\u043E\u0431\u0431\u0438, \u0438\u043D\u0442\u0435\
|
||||
\u0440\u0444\u0435\u0439\u0441 \u043F\u0440\u0438\u0437\u0440\u0430\u043A\u0430\
|
||||
\ \u0438 \u043E\u043A\u043D\u043E \u0434\u0438\u0441\u043A\u043E\u043D\u0435\
|
||||
\u043A\u0442\u0430 \u0441 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\
|
||||
\u0442\u044C\u044E \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\
|
||||
\u044F."
|
||||
type: Add
|
||||
id: 19
|
||||
time: '2024-06-04T06:27:00.064518+00:00'
|
||||
|
|
|
|||
|
|
@ -30,3 +30,6 @@ ghost-roles-window-no-roles-available-label = В настоящее время
|
|||
ghost-roles-window-rules-footer = Кнопка станет доступна через { $time } секунд (эта задержка нужна, чтобы убедиться, что вы прочитали правила).
|
||||
ghost-return-to-body-title = Вернуться в тело
|
||||
ghost-return-to-body-text = Вас воскрешают! Вернуться в своё тело?
|
||||
|
||||
# Sunrise-edit
|
||||
ghost-gui-change-server = Другие сервера
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue