Files
wwdpublic/Content.Client/_White/CustomGhosts/UI/CustomGhostsWindow.xaml.cs
RedFoxIV 50b19259b8 Re: ghost (#849)
* it just works

* why hasn't it catastrophically failed yet

* not just gotta do the ui

oh god the ui

* that was easier than expected

* a devious misdirection

* touchups

* svin

* loc+fix

* touchups

* shitfix

* touchups x3

* for further use

* i hate this piece of shit engine

* touchups x4

* ribbit

also i'm retarded x2

* big tard energy

* bb

* rabbitson

* ?

* forgor

* k

* whoops

* fug
2025-09-27 08:38:24 +03:00

200 lines
7.2 KiB
C#

using Content.Client.Lobby;
using Content.Shared._White.CustomGhostSystem;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
using System.Numerics;
namespace Content.Client._White.CustomGhosts.UI;
[GenerateTypedNameReferences]
public sealed partial class CustomGhostsWindow : DefaultWindow
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly ISharedPlayerManager _player = default!;
[Dependency] private readonly IClientPreferencesManager _pref = default!;
[Dependency] private readonly IClientConsoleHost _conhost = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IEntitySystemManager _entSys = default!;
private readonly SpriteSystem _sprite = default!;
private List<EntityUid> _previewEntities = new();
private List<Control> _hidden = new();
private Button _currentActive = default!;
private Dictionary<string, List<CustomGhostPrototype>> _allGhosts = new(); // won't include ghosts that are ckey-locked
private ProtoId<CustomGhostPrototype> _currentGhostProtoId;
public CustomGhostsWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entSys.GetEntitySystem<SpriteSystem>();
_currentGhostProtoId = _pref.Preferences?.CustomGhost.Id ?? "default";
ShowAllCheckBox.OnToggled += ToggleVisibility;
OnClose += () => { foreach (var ent in _previewEntities) { _entMan.TryQueueDeleteEntity(ent); } };
BuildList();
}
private void BuildList()
{
var allghostprotos = _proto.EnumeratePrototypes<CustomGhostPrototype>();
allghostprotos = allghostprotos.OrderBy(item => item.DisplayName);
foreach (var ghostProto in allghostprotos)
_allGhosts.GetOrNew(ghostProto.Category).Add(ghostProto);
var categories = _allGhosts.Keys.Order();
foreach (var category in categories)
{
var label = AddCategoryLabel(category);
var ghosts = _allGhosts[category];
bool allHidden = true;
List<CustomGhostButton> buttons = new();
foreach (var ghostProto in ghosts)
if (AddButton(ghostProto) is CustomGhostButton button) // todo: consider moving AddChild from AddButton to here, to avoid this weird label juggling
buttons.Add(button); // also do something about this stupid button visibility double checking
if (buttons.Count == 0)
{
ScrollBox.RemoveChild(label);
continue;
}
if (buttons.All(button => !button.Visible)) // not visible by default means the ghost is locked, and if all ghosts in a single category are locked, hide that category divider
{
label.Visible = false;
_hidden.Add(label);
}
}
}
private CustomGhostButton? AddButton(CustomGhostPrototype ghostProto) // is not guaranteed to actually add a button, lol
{
bool available = ghostProto.CanUse(_player.LocalSession!, out string fullFailReason, out bool canSee);
if (!canSee) // skip button creation altogether
return null;
var button = new CustomGhostButton();
ScrollBox.AddChild(button);
button.ActualButton.Name = ghostProto.ID;
// Can't use EntityPrototypeView since its UpdateEntity method is private
// so i have to do what it does manually
// therefore there is no reason to use it over SpriteView
var ghostEnt = _entMan.Spawn(ghostProto.GhostEntityPrototype);
_previewEntities.Add(ghostEnt);
_sprite.ForceUpdate(ghostEnt);
_sprite.SetVisible(ghostEnt, true); // counters ghost invisibility bullshit
button.EntityTextureRects.SetEntity(ghostEnt);
button.EntityLabel.Text = ghostProto.DisplayName;
button.ActualButton.ToolTip = ghostProto.DisplayDesc;
if (_currentGhostProtoId == ghostProto.ID)
{
button.ActualButton.Pressed = true;
_currentActive = button.ActualButton;
}
button.ActualButton.OnPressed += OnPressed;
if (available)
return button;
button.Modulate = Color.Red;
button.Visible = false;
button.ActualButton.Disabled = true;
button.ActualButton.ToolTip += $"\n\n{Loc.GetString("custom-ghost-window-tooltip-to-unlock")}{fullFailReason}";
_hidden.Add(button);
return button;
}
private Label AddCategoryLabel(string text)
{
var label = new Label()
{
StyleClasses = { "FancyWindowTitle" }
};
label.Text = $"-- {Loc.GetString($"custom-ghost-category-{text}")} --";
ScrollBox.AddChild(label);
return label;
}
private void OnPressed(BaseButton.ButtonEventArgs args)
{
var protoId = args.Button.Name!;
if (protoId == _currentGhostProtoId)
{
args.Button.Pressed = true; // i don't want to figure out how to properly cancel this event, yet
return;
}
_currentActive.Pressed = false;
_currentGhostProtoId = protoId;
_currentActive = (Button) args.Button;
_pref.SetCustomGhost(protoId);
_conhost.ExecuteCommand($"setcustomghost {CommandParsing.Escape(protoId)}"); // I implemented the commands first as a test, so i'll be using them now. It's dumb, but it works okay.
}
private void ToggleVisibility(BaseButton.ButtonToggledEventArgs args)
{
foreach (var button in _hidden)
{
button.Visible = args.Pressed;
}
}
// shamelessly stolen from EntitySpawnButton
public sealed class CustomGhostButton : Control
{
public Button ActualButton { get; private set; }
public Label EntityLabel { get; private set; }
public SpriteView EntityTextureRects { get; private set; }
public CustomGhostButton()
{
AddChild(ActualButton = new Button
{
ToggleMode = true,
HorizontalExpand = true
});
AddChild(new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Children =
{
(EntityTextureRects = new SpriteView
{
SetSize = new Vector2(32, 32),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Stretch = SpriteView.StretchMode.Fill
}),
(EntityLabel = new Label
{
VerticalAlignment = VAlignment.Center,
HorizontalExpand = true,
Text = "sp00ky",
ClipText = true
})
}
});
}
}
}