diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index da9d4d693a..21c3070b80 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,7 +15,6 @@ /Content.*/GameTicking/ @moonheart08 @EmoGarbage404 /Resources/ServerInfo/ @moonheart08 @Chief-Engineer /Resources/ServerInfo/Guidebook/ @moonheart08 @EmoGarbage404 -/Resources/ServerInfo/Guidebook/ServerRules/ @Chief-Engineer /Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer /Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer @@ -24,7 +23,6 @@ /Resources/Prototypes/Body/ @DrSmugleaf # suffering /Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf /Resources/Prototypes/Entities/Mobs/Species/ @DrSmugleaf -/Resources/Prototypes/Guidebook/rules.yml @Chief-Engineer /Content.*/Body/ @DrSmugleaf /Content.YAMLLinter @DrSmugleaf /Content.Shared/Damage/ @DrSmugleaf diff --git a/Content.Benchmarks/PvsBenchmark.cs b/Content.Benchmarks/PvsBenchmark.cs index fa7f9d4542..0b4dd90762 100644 --- a/Content.Benchmarks/PvsBenchmark.cs +++ b/Content.Benchmarks/PvsBenchmark.cs @@ -1,17 +1,19 @@ #nullable enable using System; +using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Content.IntegrationTests; using Content.IntegrationTests.Pair; -using Content.Server.Mind; using Content.Server.Warps; using Robust.Server.GameObjects; using Robust.Shared; using Robust.Shared.Analyzers; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; using Robust.Shared.Map; +using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Random; @@ -56,20 +58,15 @@ public class PvsBenchmark _pair.Server.CfgMan.SetCVar(CVars.NetPvsAsync, false); _sys = _entMan.System(); - SetupAsync().Wait(); - } - - private async Task SetupAsync() - { // Spawn the map _pair.Server.ResolveDependency().SetSeed(42); - await _pair.Server.WaitPost(() => + _pair.Server.WaitPost(() => { var success = _entMan.System().TryLoad(_mapId, Map, out _); if (!success) throw new Exception("Map load failed"); _pair.Server.MapMan.DoMapInitialize(_mapId); - }); + }).Wait(); // Get list of ghost warp positions _spawns = _entMan.AllComponentsList() @@ -79,19 +76,17 @@ public class PvsBenchmark Array.Resize(ref _players, PlayerCount); - // Spawn "Players" - _players = await _pair.Server.AddDummySessions(PlayerCount); - await _pair.Server.WaitPost(() => + // Spawn "Players". + _pair.Server.WaitPost(() => { - var mind = _pair.Server.System(); for (var i = 0; i < PlayerCount; i++) { var pos = _spawns[i % _spawns.Length]; var uid =_entMan.SpawnEntity("MobHuman", pos); _pair.Server.ConsoleHost.ExecuteCommand($"setoutfit {_entMan.GetNetEntity(uid)} CaptainGear"); - mind.ControlMob(_players[i].UserId, uid); + _players[i] = new DummySession{AttachedEntity = uid}; } - }); + }).Wait(); // Repeatedly move players around so that they "explore" the map and see lots of entities. // This will populate their PVS data with out-of-view entities. @@ -173,4 +168,20 @@ public class PvsBenchmark }).Wait(); _pair.Server.PvsTick(_players); } + + private sealed class DummySession : ICommonSession + { + public SessionStatus Status => SessionStatus.InGame; + public EntityUid? AttachedEntity {get; set; } + public NetUserId UserId => default; + public string Name => string.Empty; + public short Ping => default; + public INetChannel Channel { get; set; } = default!; + public LoginType AuthType => default; + public HashSet ViewSubscriptions { get; } = new(); + public DateTime ConnectedTime { get; set; } + public SessionState State => default!; + public SessionData Data => default!; + public bool ClientSide { get; set; } + } } diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml index ea89916ba8..fb68e6c790 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml @@ -1,21 +1,15 @@  + xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"> - - - - - - - + + + + diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs index 90559707f9..a5c3008436 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs @@ -1,7 +1,5 @@ using Content.Client.Station; -using Content.Client.UserInterface.Controls; using Robust.Client.AutoGenerated; -using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.XAML; using Robust.Shared.Map.Components; @@ -12,20 +10,20 @@ namespace Content.Client.Administration.UI.Tabs.ObjectsTab; [GenerateTypedNameReferences] public sealed partial class ObjectsTab : Control { - [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly EntityManager _entityManager = default!; [Dependency] private readonly IGameTiming _timing = default!; private readonly List _objects = new(); - private readonly List _selections = new(); - private bool _ascending = false; // Set to false for descending order by default - private ObjectsTabHeader.Header _headerClicked = ObjectsTabHeader.Header.ObjectName; - private readonly Color _altColor = Color.FromHex("#292B38"); - private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); + private List _selections = new(); - public event Action? OnEntryKeyBindDown; + public event Action? OnEntryKeyBindDown; - private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(2); - private TimeSpan _nextUpdate; + // Listen I could either have like 4 different event subscribers (for map / grid / station changes) and manage their lifetimes in AdminUIController + // OR + // I can do this. + private TimeSpan _updateFrequency = TimeSpan.FromSeconds(2); + + private TimeSpan _nextUpdate = TimeSpan.FromSeconds(2); public ObjectsTab() { @@ -44,30 +42,6 @@ public sealed partial class ObjectsTab : Control ObjectTypeOptions.AddItem(Enum.GetName((ObjectsTabSelection)type)!); } - ListHeader.OnHeaderClicked += HeaderClicked; - SearchList.SearchBar = SearchLineEdit; - SearchList.GenerateItem += GenerateButton; - SearchList.DataFilterCondition += DataFilterCondition; - - RefreshObjectList(); - // Set initial selection and refresh the list to apply the initial sort order - var defaultSelection = ObjectsTabSelection.Grids; - ObjectTypeOptions.SelectId((int)defaultSelection); // Set the default selection - RefreshObjectList(defaultSelection); // Refresh the list with the default selection - - // Initialize the next update time - _nextUpdate = TimeSpan.Zero; - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - - if (_timing.CurTime < _nextUpdate) - return; - - _nextUpdate = _timing.CurTime + _updateFrequency; - RefreshObjectList(); } @@ -107,72 +81,32 @@ public sealed partial class ObjectsTab : Control throw new ArgumentOutOfRangeException(nameof(selection), selection, null); } - entities.Sort((a, b) => + foreach (var control in _objects) { - var valueA = GetComparableValue(a, _headerClicked); - var valueB = GetComparableValue(b, _headerClicked); - return _ascending ? Comparer.Default.Compare(valueA, valueB) : Comparer.Default.Compare(valueB, valueA); - }); - - var listData = new List(); - for (int index = 0; index < entities.Count; index++) - { - var info = entities[index]; - listData.Add(new ObjectsListData(info, $"{info.Name} {info.Entity}", index % 2 == 0 ? _altColor : _defaultColor)); + ObjectList.RemoveChild(control); } - SearchList.PopulateList(listData); + _objects.Clear(); + + foreach (var (name, nent) in entities) + { + var ctrl = new ObjectsTabEntry(name, nent); + _objects.Add(ctrl); + ObjectList.AddChild(ctrl); + ctrl.OnKeyBindDown += args => OnEntryKeyBindDown?.Invoke(ctrl, args); + } } - private void GenerateButton(ListData data, ListContainerButton button) + protected override void FrameUpdate(FrameEventArgs args) { - if (data is not ObjectsListData { Info: var info, BackgroundColor: var backgroundColor }) + base.FrameUpdate(args); + + if (_timing.CurTime < _nextUpdate) return; - var entry = new ObjectsTabEntry(info.Name, info.Entity, new StyleBoxFlat { BackgroundColor = backgroundColor }); - button.ToolTip = $"{info.Name}, {info.Entity}"; + // I do not care for precision. + _nextUpdate = _timing.CurTime + _updateFrequency; - // Add key binding event handler - entry.OnKeyBindDown += args => OnEntryKeyBindDown?.Invoke(args, data); - - button.AddChild(entry); - } - - private bool DataFilterCondition(string filter, ListData listData) - { - if (listData is not ObjectsListData { FilteringString: var filteringString }) - return false; - - // If the filter is empty, do not filter out any entries - if (string.IsNullOrEmpty(filter)) - return true; - - return filteringString.Contains(filter, StringComparison.CurrentCultureIgnoreCase); - } - - private object GetComparableValue((string Name, NetEntity Entity) entity, ObjectsTabHeader.Header header) - { - return header switch - { - ObjectsTabHeader.Header.ObjectName => entity.Name, - ObjectsTabHeader.Header.EntityID => entity.Entity.ToString(), - _ => entity.Name - }; - } - - private void HeaderClicked(ObjectsTabHeader.Header header) - { - if (_headerClicked == header) - { - _ascending = !_ascending; - } - else - { - _headerClicked = header; - _ascending = true; - } - - ListHeader.UpdateHeaderSymbols(_headerClicked, _ascending); RefreshObjectList(); } @@ -184,4 +118,3 @@ public sealed partial class ObjectsTab : Control } } -public record ObjectsListData((string Name, NetEntity Entity) Info, string FilteringString, Color BackgroundColor) : ListData; diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml index 83c4cc5697..0f6975e365 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml @@ -1,6 +1,6 @@ - + + @@ -14,4 +14,4 @@ HorizontalExpand="True" ClipText="True"/> - + diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml.cs index aab06c6ccd..c9b2cd8b57 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml.cs @@ -1,21 +1,19 @@ using Robust.Client.AutoGenerated; -using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; namespace Content.Client.Administration.UI.Tabs.ObjectsTab; [GenerateTypedNameReferences] -public sealed partial class ObjectsTabEntry : PanelContainer +public sealed partial class ObjectsTabEntry : ContainerButton { public NetEntity AssocEntity; - public ObjectsTabEntry(string name, NetEntity nent, StyleBox styleBox) + public ObjectsTabEntry(string name, NetEntity nent) { RobustXamlLoader.Load(this); AssocEntity = nent; EIDLabel.Text = nent.ToString(); NameLabel.Text = name; - BackgroundColorPanel.PanelOverride = styleBox; } } diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml deleted file mode 100644 index 71a1f5c7bc..0000000000 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml.cs deleted file mode 100644 index 3a91b5b948..0000000000 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Input; - -namespace Content.Client.Administration.UI.Tabs.ObjectsTab -{ - [GenerateTypedNameReferences] - public sealed partial class ObjectsTabHeader : Control - { - public event Action
? OnHeaderClicked; - - private const string ArrowUp = "↑"; - private const string ArrowDown = "↓"; - - public ObjectsTabHeader() - { - RobustXamlLoader.Load(this); - - ObjectNameLabel.OnKeyBindDown += ObjectNameClicked; - EntityIDLabel.OnKeyBindDown += EntityIDClicked; - } - - public Label GetHeader(Header header) - { - return header switch - { - Header.ObjectName => ObjectNameLabel, - Header.EntityID => EntityIDLabel, - _ => throw new ArgumentOutOfRangeException(nameof(header), header, null) - }; - } - - public void ResetHeaderText() - { - ObjectNameLabel.Text = Loc.GetString("object-tab-object-name"); - EntityIDLabel.Text = Loc.GetString("object-tab-entity-id"); - } - - public void UpdateHeaderSymbols(Header headerClicked, bool ascending) - { - ResetHeaderText(); - var arrow = ascending ? ArrowUp : ArrowDown; - GetHeader(headerClicked).Text += $" {arrow}"; - } - - private void HeaderClicked(GUIBoundKeyEventArgs args, Header header) - { - if (args.Function != EngineKeyFunctions.UIClick) - { - return; - } - - OnHeaderClicked?.Invoke(header); - args.Handle(); - } - - private void ObjectNameClicked(GUIBoundKeyEventArgs args) - { - HeaderClicked(args, Header.ObjectName); - } - - private void EntityIDClicked(GUIBoundKeyEventArgs args) - { - HeaderClicked(args, Header.EntityID); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - ObjectNameLabel.OnKeyBindDown -= ObjectNameClicked; - EntityIDLabel.OnKeyBindDown -= EntityIDClicked; - } - } - - public enum Header - { - ObjectName, - EntityID - } - } -} diff --git a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs index 826945e7cc..a8bfaddecf 100644 --- a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs @@ -53,7 +53,6 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data); RefreshPlayerList(_adminSystem.PlayerList); - } #region Antag Overlay @@ -111,9 +110,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab _players = players; PlayerCount.Text = $"Players: {_playerMan.PlayerCount}"; - var filteredPlayers = players.Where(info => _showDisconnected || info.Connected).ToList(); - - var sortedPlayers = new List(filteredPlayers); + var sortedPlayers = new List(players); sortedPlayers.Sort(Compare); UpdateHeaderSymbols(); diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index 453658bebf..66000a8457 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -27,7 +27,6 @@ namespace Content.Client.Construction [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; - [Dependency] private readonly ExamineSystemShared _examineSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; @@ -196,8 +195,9 @@ namespace Content.Client.Construction if (GhostPresent(loc)) return false; + // This InRangeUnobstructed should probably be replaced with "is there something blocking us in that tile?" var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager, _transformSystem)); - if (!_examineSystem.InRangeUnOccluded(user, loc, 20f, predicate: predicate)) + if (!_interactionSystem.InRangeUnobstructed(user, loc, 20f, predicate: predicate)) return false; if (!CheckConstructionConditions(prototype, loc, dir, user, showPopup: true)) diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml index 322e4e66a9..eec5c229cb 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml @@ -8,7 +8,7 @@ - + diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs index 9f3d5695bb..ad19bc30f4 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs @@ -23,6 +23,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow private readonly ItemSlotsSystem _itemSlots; private readonly FlatpackSystem _flatpack; private readonly MaterialStorageSystem _materialStorage; + private readonly SpriteSystem _spriteSystem; private readonly EntityUid _owner; @@ -30,6 +31,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow public const string NoBoardEffectId = "FlatpackerNoBoardEffect"; private EntityUid? _currentBoard = EntityUid.Invalid; + private EntityUid? _machinePreview; public event Action? PackButtonPressed; @@ -41,6 +43,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow _itemSlots = _entityManager.System(); _flatpack = _entityManager.System(); _materialStorage = _entityManager.System(); + _spriteSystem = _entityManager.System(); _owner = uid; @@ -54,10 +57,17 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow { base.FrameUpdate(args); + if (_machinePreview is not { } && _entityManager.Deleted(_machinePreview)) + { + _machinePreview = null; + MachineSprite.SetEntity(_machinePreview); + } + if (!_entityManager.TryGetComponent(_owner, out var flatpacker) || !_itemSlots.TryGetSlot(_owner, flatpacker.SlotId, out var itemSlot)) return; + MachineBoardComponent? machineBoardComp = null; if (flatpacker.Packing) { PackButton.Disabled = true; @@ -65,10 +75,11 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow else if (_currentBoard != null) { Dictionary cost; - if (_entityManager.TryGetComponent(_currentBoard, out var machineBoardComp)) + if (_entityManager.TryGetComponent(_currentBoard, out machineBoardComp) && + machineBoardComp.Prototype is not null) cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, machineBoardComp)); else - cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), null); + cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker)); PackButton.Disabled = !_materialStorage.CanChangeMaterialAmount(_owner, cost); } @@ -76,6 +87,9 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow if (_currentBoard == itemSlot.Item) return; + if (_machinePreview != null) + _entityManager.DeleteEntity(_machinePreview); + _currentBoard = itemSlot.Item; CostHeaderLabel.Visible = _currentBoard != null; InsertLabel.Visible = _currentBoard == null; @@ -85,32 +99,35 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow string? prototype = null; Dictionary? cost = null; - if (_entityManager.TryGetComponent(_currentBoard, out var newMachineBoardComp)) + if (machineBoardComp != null || _entityManager.TryGetComponent(_currentBoard, out machineBoardComp)) { - prototype = newMachineBoardComp.Prototype; - cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, newMachineBoardComp)); + prototype = machineBoardComp.Prototype; + cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, machineBoardComp)); } else if (_entityManager.TryGetComponent(_currentBoard, out var computerBoard)) { prototype = computerBoard.Prototype; - cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), null); + cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker)); } if (prototype is not null && cost is not null) { var proto = _prototypeManager.Index(prototype); - MachineSprite.SetPrototype(prototype); + _machinePreview = _entityManager.Spawn(proto.ID); + _spriteSystem.ForceUpdate(_machinePreview.Value); MachineNameLabel.SetMessage(proto.Name); CostLabel.SetMarkup(GetCostString(cost)); } } else { - MachineSprite.SetPrototype(NoBoardEffectId); + _machinePreview = _entityManager.Spawn(NoBoardEffectId); CostLabel.SetMessage(Loc.GetString("flatpacker-ui-no-board-label")); MachineNameLabel.SetMessage(" "); PackButton.Disabled = true; } + + MachineSprite.SetEntity(_machinePreview); } private string GetCostString(Dictionary costs) @@ -132,7 +149,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow ("amount", amountText), ("material", Loc.GetString(matProto.Name))); - msg.TryAddMarkup(text, out _); + msg.AddMarkup(text); if (i != orderedCosts.Length - 1) msg.PushNewline(); @@ -140,4 +157,12 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow return msg.ToMarkup(); } + + public override void Close() + { + base.Close(); + + _entityManager.DeleteEntity(_machinePreview); + _machinePreview = null; + } } diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index bc3b9b6dec..452b091ea6 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -2,9 +2,11 @@ using Content.Client.Administration.Managers; using Content.Client.Changelog; using Content.Client.Chat.Managers; using Content.Client.Eui; +using Content.Client.Flash; using Content.Client.Fullscreen; using Content.Client.GhostKick; using Content.Client.Guidebook; +using Content.Client.Info; using Content.Client.Input; using Content.Client.IoC; using Content.Client.Launcher; @@ -51,6 +53,7 @@ namespace Content.Client.Entry [Dependency] private readonly IScreenshotHook _screenshotHook = default!; [Dependency] private readonly FullscreenHook _fullscreenHook = default!; [Dependency] private readonly ChangelogManager _changelogManager = default!; + [Dependency] private readonly RulesManager _rulesManager = default!; [Dependency] private readonly ViewportManager _viewportManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IInputManager _inputManager = default!; @@ -123,6 +126,7 @@ namespace Content.Client.Entry _screenshotHook.Initialize(); _fullscreenHook.Initialize(); _changelogManager.Initialize(); + _rulesManager.Initialize(); _viewportManager.Initialize(); _ghostKick.Initialize(); _extendedDisconnectInformation.Initialize(); diff --git a/Content.Client/GameTicking/Managers/ClientGameTicker.cs b/Content.Client/GameTicking/Managers/ClientGameTicker.cs index fcf5ae91a4..309db2eb4e 100644 --- a/Content.Client/GameTicking/Managers/ClientGameTicker.cs +++ b/Content.Client/GameTicking/Managers/ClientGameTicker.cs @@ -4,12 +4,10 @@ using Content.Client.Lobby; using Content.Client.RoundEnd; using Content.Shared.GameTicking; using Content.Shared.GameWindow; -using Content.Shared.Roles; using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.State; using Robust.Client.UserInterface; -using Robust.Shared.Prototypes; namespace Content.Client.GameTicking.Managers { @@ -19,9 +17,10 @@ namespace Content.Client.GameTicking.Managers [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IClientAdminManager _admin = default!; [Dependency] private readonly IClyde _clyde = default!; + [Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; - private Dictionary, int?>> _jobsAvailable = new(); + private Dictionary> _jobsAvailable = new(); private Dictionary _stationNames = new(); [ViewVariables] public bool AreWeReady { get; private set; } @@ -33,13 +32,13 @@ namespace Content.Client.GameTicking.Managers [ViewVariables] public TimeSpan StartTime { get; private set; } [ViewVariables] public new bool Paused { get; private set; } - [ViewVariables] public IReadOnlyDictionary, int?>> JobsAvailable => _jobsAvailable; + [ViewVariables] public IReadOnlyDictionary> JobsAvailable => _jobsAvailable; [ViewVariables] public IReadOnlyDictionary StationNames => _stationNames; public event Action? InfoBlobUpdated; public event Action? LobbyStatusUpdated; public event Action? LobbyLateJoinStatusUpdated; - public event Action, int?>>>? LobbyJobsAvailableUpdated; + public event Action>>? LobbyJobsAvailableUpdated; public override void Initialize() { @@ -70,7 +69,7 @@ namespace Content.Client.GameTicking.Managers // reading the console. E.g., logs like this one could leak the nuke station/grid: // > Grid NT-Arrivals 1101 (122/n25896) changed parent. Old parent: map 10 (121/n25895). New parent: FTL (123/n26470) #if !DEBUG - EntityManager.System().Log.Level = _admin.IsAdmin() ? LogLevel.Info : LogLevel.Warning; + _map.Log.Level = _admin.IsAdmin() ? LogLevel.Info : LogLevel.Warning; #endif } diff --git a/Content.Client/Guidebook/Components/GuideHelpComponent.cs b/Content.Client/Guidebook/Components/GuideHelpComponent.cs index bb1d30bbc1..db19bb9dcc 100644 --- a/Content.Client/Guidebook/Components/GuideHelpComponent.cs +++ b/Content.Client/Guidebook/Components/GuideHelpComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Guidebook; -using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Client.Guidebook.Components; @@ -14,8 +13,9 @@ public sealed partial class GuideHelpComponent : Component /// What guides to include show when opening the guidebook. The first entry will be used to select the currently /// selected guidebook. /// - [DataField(required: true)] - public List> Guides = new(); + [DataField("guides", customTypeSerializer: typeof(PrototypeIdListSerializer), required: true)] + [ViewVariables] + public List Guides = new(); /// /// Whether or not to automatically include the children of the given guides. diff --git a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml index b52eacfa72..8dbfde3c47 100644 --- a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml +++ b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml @@ -2,7 +2,7 @@ xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls" xmlns:fancyTree="clr-namespace:Content.Client.UserInterface.Controls.FancyTree" xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls" - SetSize="850 700" + SetSize="750 700" MinSize="100 200" Resizable="True" Title="{Loc 'guidebook-window-title'}"> @@ -18,16 +18,12 @@ Name="SearchBar" PlaceHolder="{Loc 'guidebook-filter-placeholder-text'}" HorizontalExpand="True" - Margin="0 5 10 5"> + Margin="0 5 10 5"> - - public sealed partial class DocumentParsingManager { - [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IReflectionManager _reflectionManager = default!; - [Dependency] private readonly IResourceManager _resourceManager = default!; [Dependency] private readonly ISandboxHelper _sandboxHelper = default!; private readonly Dictionary> _tagControlParsers = new(); @@ -42,21 +37,6 @@ public sealed partial class DocumentParsingManager ControlParser = SkipWhitespaces.Then(_controlParser.Many()); } - public bool TryAddMarkup(Control control, ProtoId entryId, bool log = true) - { - if (!_prototype.TryIndex(entryId, out var entry)) - return false; - - using var file = _resourceManager.ContentFileReadText(entry.Text); - return TryAddMarkup(control, file.ReadToEnd(), log); - } - - public bool TryAddMarkup(Control control, GuideEntry entry, bool log = true) - { - using var file = _resourceManager.ContentFileReadText(entry.Text); - return TryAddMarkup(control, file.ReadToEnd(), log); - } - public bool TryAddMarkup(Control control, string text, bool log = true) { try diff --git a/Content.Shared/Guidebook/GuideEntry.cs b/Content.Client/Guidebook/GuideEntry.cs similarity index 67% rename from Content.Shared/Guidebook/GuideEntry.cs rename to Content.Client/Guidebook/GuideEntry.cs index d39e6c9315..3f9ce31ad0 100644 --- a/Content.Shared/Guidebook/GuideEntry.cs +++ b/Content.Client/Guidebook/GuideEntry.cs @@ -1,13 +1,8 @@ using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; using Robust.Shared.Utility; -namespace Content.Shared.Guidebook; - -[Prototype("guideEntry")] -public sealed partial class GuideEntryPrototype : GuideEntry, IPrototype -{ - public string ID => Id; -} +namespace Content.Client.Guidebook; [Virtual] public class GuideEntry @@ -15,7 +10,7 @@ public class GuideEntry /// /// The file containing the contents of this guide. /// - [DataField(required: true)] public ResPath Text = default!; + [DataField("text", required: true)] public ResPath Text = default!; /// /// The unique id for this guide. @@ -26,27 +21,31 @@ public class GuideEntry /// /// The name of this guide. This gets localized. /// - [DataField(required: true)] public string Name = default!; + [DataField("name", required: true)] public string Name = default!; /// /// The "children" of this guide for when guides are shown in a tree / table of contents. /// - [DataField] - public List> Children = new(); + [DataField("children", customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List Children = new(); /// /// Enable filtering of items. /// - [DataField] public bool FilterEnabled = default!; - - [DataField] public bool RuleEntry; + [DataField("filterEnabled")] public bool FilterEnabled = default!; /// /// Priority for sorting top-level guides when shown in a tree / table of contents. /// If the guide is the child of some other guide, the order simply determined by the order of children in . /// - [DataField] public int Priority = 0; + [DataField("priority")] public int Priority = 0; [DataField] public bool CrystallPunkAllowed = false; } + +[Prototype("guideEntry")] +public sealed partial class GuideEntryPrototype : GuideEntry, IPrototype +{ + public string ID => Id; +} diff --git a/Content.Client/Guidebook/GuidebookSystem.cs b/Content.Client/Guidebook/GuidebookSystem.cs index 9bc44aa916..a0532294d6 100644 --- a/Content.Client/Guidebook/GuidebookSystem.cs +++ b/Content.Client/Guidebook/GuidebookSystem.cs @@ -2,7 +2,6 @@ using System.Linq; using Content.Client.Guidebook.Components; using Content.Client.Light; using Content.Client.Verbs; -using Content.Shared.Guidebook; using Content.Shared.Interaction; using Content.Shared.Light.Components; using Content.Shared.Speech; @@ -35,12 +34,7 @@ public sealed class GuidebookSystem : EntitySystem [Dependency] private readonly IPrototypeManager _proto = default!; //CrystallPunk guidebook filter - public event Action>, - List>?, - ProtoId?, - bool, - ProtoId?>? OnGuidebookOpen; - + public event Action, List?, string?, bool, string?>? OnGuidebookOpen; public const string GuideEmbedTag = "GuideEmbeded"; private EntityUid _defaultUser; @@ -105,7 +99,7 @@ public sealed class GuidebookSystem : EntitySystem }); } - public void OpenHelp(List> guides) + public void OpenHelp(List guides) { OnGuidebookOpen?.Invoke(guides, null, null, true, guides[0]); } diff --git a/Content.Client/Info/InfoSystem.cs b/Content.Client/Info/InfoSystem.cs new file mode 100644 index 0000000000..b697994981 --- /dev/null +++ b/Content.Client/Info/InfoSystem.cs @@ -0,0 +1,25 @@ +using Content.Shared.Info; +using Robust.Shared.Log; + +namespace Content.Client.Info; + +public sealed class InfoSystem : EntitySystem +{ + public RulesMessage Rules = new RulesMessage("Server Rules", "The server did not send any rules."); + [Dependency] private readonly RulesManager _rules = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnRulesReceived); + Log.Debug("Requested server info."); + RaiseNetworkEvent(new RequestRulesMessage()); + } + + private void OnRulesReceived(RulesMessage message, EntitySessionEventArgs eventArgs) + { + Log.Debug("Received server rules."); + Rules = message; + _rules.UpdateRules(); + } +} diff --git a/Content.Client/Info/RulesAndInfoWindow.cs b/Content.Client/Info/RulesAndInfoWindow.cs index b9131dcb3c..7a763a1d6f 100644 --- a/Content.Client/Info/RulesAndInfoWindow.cs +++ b/Content.Client/Info/RulesAndInfoWindow.cs @@ -1,8 +1,10 @@ using System.Numerics; using Content.Client.UserInterface.Systems.EscapeMenu; +using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Configuration; using Robust.Shared.ContentPack; namespace Content.Client.Info @@ -10,6 +12,7 @@ namespace Content.Client.Info public sealed class RulesAndInfoWindow : DefaultWindow { [Dependency] private readonly IResourceManager _resourceManager = default!; + [Dependency] private readonly RulesManager _rules = default!; public RulesAndInfoWindow() { @@ -19,14 +22,8 @@ namespace Content.Client.Info var rootContainer = new TabContainer(); - var rulesList = new RulesControl - { - Margin = new Thickness(10) - }; - var tutorialList = new Info - { - Margin = new Thickness(10) - }; + var rulesList = new Info(); + var tutorialList = new Info(); rootContainer.AddChild(rulesList); rootContainer.AddChild(tutorialList); @@ -34,6 +31,7 @@ namespace Content.Client.Info TabContainer.SetTabTitle(rulesList, Loc.GetString("ui-info-tab-rules")); TabContainer.SetTabTitle(tutorialList, Loc.GetString("ui-info-tab-tutorial")); + AddSection(rulesList, _rules.RulesSection()); PopulateTutorial(tutorialList); Contents.AddChild(rootContainer); diff --git a/Content.Client/Info/RulesControl.xaml b/Content.Client/Info/RulesControl.xaml index 04fa719123..3b24764688 100644 --- a/Content.Client/Info/RulesControl.xaml +++ b/Content.Client/Info/RulesControl.xaml @@ -1,18 +1,6 @@ - - - - - - -