diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
index ea2f77d457..83dc42c4a4 100644
--- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
+++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
@@ -4,14 +4,14 @@
MinSize="400 225">
-
-
+
+
-
+
-
+
diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj
index 125bbac00d..d5fd1d341e 100644
--- a/Content.Client/Content.Client.csproj
+++ b/Content.Client/Content.Client.csproj
@@ -25,9 +25,6 @@
-
-
-
diff --git a/Content.Client/Ghost/GhostSystem.cs b/Content.Client/Ghost/GhostSystem.cs
index 94872a58ef..f4f7e3459f 100644
--- a/Content.Client/Ghost/GhostSystem.cs
+++ b/Content.Client/Ghost/GhostSystem.cs
@@ -99,8 +99,8 @@ namespace Content.Client.Ghost
if (args.Handled)
return;
- Popup.PopupEntity(Loc.GetString("ghost-gui-toggle-ghost-visibility-popup"), args.Performer);
-
+ var locId = GhostVisibility ? "ghost-gui-toggle-ghost-visibility-popup-off" : "ghost-gui-toggle-ghost-visibility-popup-on";
+ Popup.PopupEntity(Loc.GetString(locId), args.Performer);
if (uid == _playerManager.LocalEntity)
ToggleGhostVisibility();
diff --git a/Content.Client/Launcher/LauncherConnecting.cs b/Content.Client/Launcher/LauncherConnecting.cs
index 29b241ae5d..33d31cc52d 100644
--- a/Content.Client/Launcher/LauncherConnecting.cs
+++ b/Content.Client/Launcher/LauncherConnecting.cs
@@ -19,6 +19,7 @@ namespace Content.Client.Launcher
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly IClipboardManager _clipboard = default!;
private LauncherConnectingGui? _control;
@@ -58,7 +59,7 @@ namespace Content.Client.Launcher
protected override void Startup()
{
- _control = new LauncherConnectingGui(this, _random, _prototypeManager, _cfg);
+ _control = new LauncherConnectingGui(this, _random, _prototypeManager, _cfg, _clipboard);
_userInterfaceManager.StateRoot.AddChild(_control);
diff --git a/Content.Client/Launcher/LauncherConnectingGui.xaml b/Content.Client/Launcher/LauncherConnectingGui.xaml
index 3734fa5b3a..2cb349d4e7 100644
--- a/Content.Client/Launcher/LauncherConnectingGui.xaml
+++ b/Content.Client/Launcher/LauncherConnectingGui.xaml
@@ -18,21 +18,38 @@
-
-
+
-
+
+
+
+
-
+
-
+
+
+
+
diff --git a/Content.Client/Launcher/LauncherConnectingGui.xaml.cs b/Content.Client/Launcher/LauncherConnectingGui.xaml.cs
index 5015b710eb..cf89f98095 100644
--- a/Content.Client/Launcher/LauncherConnectingGui.xaml.cs
+++ b/Content.Client/Launcher/LauncherConnectingGui.xaml.cs
@@ -28,14 +28,16 @@ namespace Content.Client.Launcher
private readonly IRobustRandom _random;
private readonly IPrototypeManager _prototype;
private readonly IConfigurationManager _cfg;
+ private readonly IClipboardManager _clipboard;
public LauncherConnectingGui(LauncherConnecting state, IRobustRandom random,
- IPrototypeManager prototype, IConfigurationManager config)
+ IPrototypeManager prototype, IConfigurationManager config, IClipboardManager clipboard)
{
_state = state;
_random = random;
_prototype = prototype;
_cfg = config;
+ _clipboard = clipboard;
RobustXamlLoader.Load(this);
@@ -44,8 +46,11 @@ namespace Content.Client.Launcher
Stylesheet = IoCManager.Resolve().SheetSpace;
ChangeLoginTip();
- ReconnectButton.OnPressed += ReconnectButtonPressed;
RetryButton.OnPressed += ReconnectButtonPressed;
+ ReconnectButton.OnPressed += ReconnectButtonPressed;
+
+ CopyButton.OnPressed += CopyButtonPressed;
+ CopyButtonDisconnected.OnPressed += CopyButtonDisconnectedPressed;
ExitButton.OnPressed += _ => _state.Exit();
var addr = state.Address;
@@ -78,6 +83,24 @@ namespace Content.Client.Launcher
_state.RetryConnect();
}
+ private void CopyButtonPressed(BaseButton.ButtonEventArgs args)
+ {
+ CopyText(ConnectFailReason.Text);
+ }
+
+ private void CopyButtonDisconnectedPressed(BaseButton.ButtonEventArgs args)
+ {
+ CopyText(DisconnectReason.Text);
+ }
+
+ private void CopyText(string? text)
+ {
+ if (!string.IsNullOrEmpty(text))
+ {
+ _clipboard.SetText(text);
+ }
+ }
+
private void ConnectFailReasonChanged(string? reason)
{
ConnectFailReason.SetMessage(reason == null
diff --git a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs
index 0b8720add2..64ead32586 100644
--- a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs
+++ b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs
@@ -35,6 +35,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
public bool ShowIFF { get; set; } = true;
public bool ShowDocks { get; set; } = true;
+ public bool RotateWithEntity { get; set; } = true;
///
/// Raised if the user left-clicks on the radar control with the relevant entitycoordinates.
@@ -109,6 +110,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
ActualRadarRange = Math.Clamp(ActualRadarRange, WorldMinRange, WorldMaxRange);
+ RotateWithEntity = state.RotateWithEntity;
+
_docks = state.Docks;
}
@@ -138,7 +141,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
var mapPos = _transform.ToMapCoordinates(_coordinates.Value);
var offset = _coordinates.Value.Position;
var posMatrix = Matrix3Helpers.CreateTransform(offset, _rotation.Value);
- var (_, ourEntRot, ourEntMatrix) = _transform.GetWorldPositionRotationMatrix(_coordinates.Value.EntityId);
+ var ourEntRot = RotateWithEntity ? _transform.GetWorldRotation(xform) : _rotation.Value;
+ var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert);
diff --git a/Content.Client/Silicons/StationAi/StationAiOverlay.cs b/Content.Client/Silicons/StationAi/StationAiOverlay.cs
new file mode 100644
index 0000000000..efa1b8dbef
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiOverlay.cs
@@ -0,0 +1,119 @@
+using System.Numerics;
+using Content.Shared.Silicons.StationAi;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Enums;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Silicons.StationAi;
+
+public sealed class StationAiOverlay : Overlay
+{
+ [Dependency] private readonly IClyde _clyde = default!;
+ [Dependency] private readonly IEntityManager _entManager = default!;
+ [Dependency] private readonly IPlayerManager _player = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+
+ public override OverlaySpace Space => OverlaySpace.WorldSpace;
+
+ private readonly HashSet _visibleTiles = new();
+
+ private IRenderTexture? _staticTexture;
+ private IRenderTexture? _stencilTexture;
+
+ public StationAiOverlay()
+ {
+ IoCManager.InjectDependencies(this);
+ }
+
+ protected override void Draw(in OverlayDrawArgs args)
+ {
+ if (_stencilTexture?.Texture.Size != args.Viewport.Size)
+ {
+ _staticTexture?.Dispose();
+ _stencilTexture?.Dispose();
+ _stencilTexture = _clyde.CreateRenderTarget(args.Viewport.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "station-ai-stencil");
+ _staticTexture = _clyde.CreateRenderTarget(args.Viewport.Size,
+ new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
+ name: "station-ai-static");
+ }
+
+ var worldHandle = args.WorldHandle;
+
+ var worldBounds = args.WorldBounds;
+
+ var playerEnt = _player.LocalEntity;
+ _entManager.TryGetComponent(playerEnt, out TransformComponent? playerXform);
+ var gridUid = playerXform?.GridUid ?? EntityUid.Invalid;
+ _entManager.TryGetComponent(gridUid, out MapGridComponent? grid);
+
+ var invMatrix = args.Viewport.GetWorldToLocalMatrix();
+
+ if (grid != null)
+ {
+ // TODO: Pass in attached entity's grid.
+ // TODO: Credit OD on the moved to code
+ // TODO: Call the moved-to code here.
+
+ _visibleTiles.Clear();
+ var lookups = _entManager.System();
+ var xforms = _entManager.System();
+ _entManager.System().GetView((gridUid, grid), worldBounds, _visibleTiles);
+
+ var gridMatrix = xforms.GetWorldMatrix(gridUid);
+ var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
+
+ // Draw visible tiles to stencil
+ worldHandle.RenderInRenderTarget(_stencilTexture!, () =>
+ {
+ worldHandle.SetTransform(matty);
+
+ foreach (var tile in _visibleTiles)
+ {
+ var aabb = lookups.GetLocalBounds(tile, grid.TileSize);
+ worldHandle.DrawRect(aabb, Color.White);
+ }
+ },
+ Color.Transparent);
+
+ // Once this is gucci optimise rendering.
+ worldHandle.RenderInRenderTarget(_staticTexture!,
+ () =>
+ {
+ worldHandle.SetTransform(invMatrix);
+ var shader = _proto.Index("CameraStatic").Instance();
+ worldHandle.UseShader(shader);
+ worldHandle.DrawRect(worldBounds, Color.White);
+ },
+ Color.Black);
+ }
+ // Not on a grid
+ else
+ {
+ worldHandle.RenderInRenderTarget(_stencilTexture!, () =>
+ {
+ },
+ Color.Transparent);
+
+ worldHandle.RenderInRenderTarget(_staticTexture!,
+ () =>
+ {
+ worldHandle.SetTransform(Matrix3x2.Identity);
+ worldHandle.DrawRect(worldBounds, Color.Black);
+ }, Color.Black);
+ }
+
+ // Use the lighting as a mask
+ worldHandle.UseShader(_proto.Index("StencilMask").Instance());
+ worldHandle.DrawTextureRect(_stencilTexture!.Texture, worldBounds);
+
+ // Draw the static
+ worldHandle.UseShader(_proto.Index("StencilDraw").Instance());
+ worldHandle.DrawTextureRect(_staticTexture!.Texture, worldBounds);
+
+ worldHandle.SetTransform(Matrix3x2.Identity);
+ worldHandle.UseShader(null);
+
+ }
+}
diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.cs b/Content.Client/Silicons/StationAi/StationAiSystem.cs
new file mode 100644
index 0000000000..2ed0617525
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiSystem.cs
@@ -0,0 +1,80 @@
+using Content.Shared.Silicons.StationAi;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Player;
+
+namespace Content.Client.Silicons.StationAi;
+
+public sealed partial class StationAiSystem : EntitySystem
+{
+ [Dependency] private readonly IOverlayManager _overlayMgr = default!;
+ [Dependency] private readonly IPlayerManager _player = default!;
+
+ private StationAiOverlay? _overlay;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ // InitializeAirlock();
+ // InitializePowerToggle();
+
+ SubscribeLocalEvent(OnAiAttached);
+ SubscribeLocalEvent(OnAiDetached);
+ SubscribeLocalEvent(OnAiOverlayInit);
+ SubscribeLocalEvent(OnAiOverlayRemove);
+ }
+
+ private void OnAiOverlayInit(Entity ent, ref ComponentInit args)
+ {
+ var attachedEnt = _player.LocalEntity;
+
+ if (attachedEnt != ent.Owner)
+ return;
+
+ AddOverlay();
+ }
+
+ private void OnAiOverlayRemove(Entity ent, ref ComponentRemove args)
+ {
+ var attachedEnt = _player.LocalEntity;
+
+ if (attachedEnt != ent.Owner)
+ return;
+
+ RemoveOverlay();
+ }
+
+ private void AddOverlay()
+ {
+ if (_overlay != null)
+ return;
+
+ _overlay = new StationAiOverlay();
+ _overlayMgr.AddOverlay(_overlay);
+ }
+
+ private void RemoveOverlay()
+ {
+ if (_overlay == null)
+ return;
+
+ _overlayMgr.RemoveOverlay(_overlay);
+ _overlay = null;
+ }
+
+ private void OnAiAttached(Entity ent, ref LocalPlayerAttachedEvent args)
+ {
+ AddOverlay();
+ }
+
+ private void OnAiDetached(Entity ent, ref LocalPlayerDetachedEvent args)
+ {
+ RemoveOverlay();
+ }
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ _overlayMgr.RemoveOverlay();
+ }
+}
diff --git a/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs b/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs
index 5d7a775104..49a2fba898 100644
--- a/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs
+++ b/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs
@@ -21,6 +21,7 @@ using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
+using Robust.Shared.Player;
using Robust.Shared.Utility;
using static Content.Client.Inventory.ClientInventorySystem;
@@ -399,6 +400,9 @@ public sealed class InventoryUIController : UIController, IOnStateEntered
+
, IOnSystemChanged
{
+ [Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly ILightManager _light = default!;
[Dependency] private readonly IClientAdminManager _admin = default!;
+ [Dependency] private readonly IPlayerManager _player = default!;
[UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!;
[UISystemDependency] private readonly MarkerSystem _marker = default!;
@@ -116,6 +121,21 @@ public sealed class SandboxUIController : UIController, IOnStateChanged
+ {
+ var player = _player.LocalEntity;
+
+ if (player == null)
+ return;
+
+ var pnent = EntityManager.GetNetEntity(player.Value);
+
+ // Need NetworkedAddComponent but engine PR.
+ if (args.Button.Pressed)
+ _console.ExecuteCommand($"addcomp {pnent.Id} StationAiOverlay");
+ else
+ _console.ExecuteCommand($"rmcomp {pnent.Id} StationAiOverlay");
+ };
_window.RespawnButton.OnPressed += _ => _sandbox.Respawn();
_window.SpawnTilesButton.OnPressed += _ => TileSpawningController.ToggleWindow();
_window.SpawnEntitiesButton.OnPressed += _ => EntitySpawningController.ToggleWindow();
diff --git a/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml b/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml
index 64367ea27a..05e65cf29c 100644
--- a/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml
+++ b/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml
@@ -4,6 +4,7 @@
Title="{Loc sandbox-window-title}"
Resizable="False">
+
diff --git a/Content.Client/VendingMachines/UI/VendingMachineItem.xaml b/Content.Client/VendingMachines/UI/VendingMachineItem.xaml
new file mode 100644
index 0000000000..a665b72c73
--- /dev/null
+++ b/Content.Client/VendingMachines/UI/VendingMachineItem.xaml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/Content.Client/VendingMachines/UI/VendingMachineItem.xaml.cs b/Content.Client/VendingMachines/UI/VendingMachineItem.xaml.cs
new file mode 100644
index 0000000000..a7212934fd
--- /dev/null
+++ b/Content.Client/VendingMachines/UI/VendingMachineItem.xaml.cs
@@ -0,0 +1,19 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.VendingMachines.UI;
+
+[GenerateTypedNameReferences]
+public sealed partial class VendingMachineItem : BoxContainer
+{
+ public VendingMachineItem(EntProtoId entProto, string text)
+ {
+ RobustXamlLoader.Load(this);
+
+ ItemPrototype.SetPrototype(entProto);
+
+ NameLabel.Text = text;
+ }
+}
diff --git a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml
index 1fcb1a7898..f43f4bdc36 100644
--- a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml
+++ b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml
@@ -2,17 +2,10 @@
xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
- xmlns:style="clr-namespace:Content.Client.Stylesheets">
-
-
-
-
+ xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
+
+
+
diff --git a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs
index 136642e063..d978b3837f 100644
--- a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs
+++ b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs
@@ -1,14 +1,13 @@
using System.Numerics;
using Content.Shared.VendingMachines;
using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
-using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
-using Content.Shared.IdentityManagement;
-using Robust.Shared.Timing;
+using Robust.Client.UserInterface;
+using Content.Client.UserInterface.Controls;
+using Robust.Client.Graphics;
namespace Content.Client.VendingMachines.UI
{
@@ -16,12 +15,10 @@ namespace Content.Client.VendingMachines.UI
public sealed partial class VendingMachineMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IEntityManager _entityManager = default!;
- private readonly Dictionary _dummies = [];
+ public event Action? OnItemSelected;
- public event Action? OnItemSelected;
- public event Action? OnSearchChanged;
+ private readonly StyleBoxFlat _styleBox = new() { BackgroundColor = new Color(70, 73, 102) };
public VendingMachineMenu()
{
@@ -30,106 +27,90 @@ namespace Content.Client.VendingMachines.UI
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
- SearchBar.OnTextChanged += _ =>
- {
- OnSearchChanged?.Invoke(SearchBar.Text);
- };
-
- VendingContents.OnItemSelected += args =>
- {
- OnItemSelected?.Invoke(args);
- };
+ VendingContents.SearchBar = SearchBar;
+ VendingContents.DataFilterCondition += DataFilterCondition;
+ VendingContents.GenerateItem += GenerateButton;
+ VendingContents.ItemKeyBindDown += (args, data) => OnItemSelected?.Invoke(args, data);
}
- protected override void Dispose(bool disposing)
+ private bool DataFilterCondition(string filter, ListData data)
{
- base.Dispose(disposing);
+ if (data is not VendorItemsListData { ItemText: var text })
+ return false;
- // Don't clean up dummies during disposal or we'll just have to spawn them again
- if (!disposing)
+ if (string.IsNullOrEmpty(filter))
+ return true;
+
+ return text.Contains(filter, StringComparison.CurrentCultureIgnoreCase);
+ }
+
+ private void GenerateButton(ListData data, ListContainerButton button)
+ {
+ if (data is not VendorItemsListData { ItemProtoID: var protoID, ItemText: var text })
return;
- // Delete any dummy items we spawned
- foreach (var entity in _dummies.Values)
- {
- _entityManager.QueueDeleteEntity(entity);
- }
- _dummies.Clear();
+ button.AddChild(new VendingMachineItem(protoID, text));
+
+ button.ToolTip = text;
+ button.StyleBoxOverride = _styleBox;
}
///
/// Populates the list of available items on the vending machine interface
/// and sets icons based on their prototypes
///
- public void Populate(List inventory, out List filteredInventory, string? filter = null)
+ public void Populate(List inventory)
{
- filteredInventory = new();
-
- if (inventory.Count == 0)
+ if (inventory.Count == 0 && VendingContents.Visible)
{
- VendingContents.Clear();
- var outOfStockText = Loc.GetString("vending-machine-component-try-eject-out-of-stock");
- VendingContents.AddItem(outOfStockText);
- SetSizeAfterUpdate(outOfStockText.Length, VendingContents.Count);
+ SearchBar.Visible = false;
+ VendingContents.Visible = false;
+
+ var outOfStockLabel = new Label()
+ {
+ Text = Loc.GetString("vending-machine-component-try-eject-out-of-stock"),
+ Margin = new Thickness(4, 4),
+ HorizontalExpand = true,
+ VerticalAlignment = VAlignment.Stretch,
+ HorizontalAlignment = HAlignment.Center
+ };
+
+ MainContainer.AddChild(outOfStockLabel);
+
+ SetSizeAfterUpdate(outOfStockLabel.Text.Length, 0);
+
return;
}
- while (inventory.Count != VendingContents.Count)
- {
- if (inventory.Count > VendingContents.Count)
- VendingContents.AddItem(string.Empty);
- else
- VendingContents.RemoveAt(VendingContents.Count - 1);
- }
-
var longestEntry = string.Empty;
- var spriteSystem = IoCManager.Resolve().GetEntitySystem();
+ var listData = new List();
- var filterCount = 0;
for (var i = 0; i < inventory.Count; i++)
{
var entry = inventory[i];
- var vendingItem = VendingContents[i - filterCount];
- vendingItem.Text = string.Empty;
- vendingItem.Icon = null;
- if (!_dummies.TryGetValue(entry.ID, out var dummy))
- {
- dummy = _entityManager.Spawn(entry.ID);
- _dummies.Add(entry.ID, dummy);
- }
-
- var itemName = Identity.Name(dummy, _entityManager);
- Texture? icon = null;
- if (_prototypeManager.TryIndex(entry.ID, out var prototype))
- {
- icon = spriteSystem.GetPrototypeIcon(prototype).Default;
- }
-
- // search filter
- if (!string.IsNullOrEmpty(filter) &&
- !itemName.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))
- {
- VendingContents.Remove(vendingItem);
- filterCount++;
+ if (!_prototypeManager.TryIndex(entry.ID, out var prototype))
continue;
- }
- if (itemName.Length > longestEntry.Length)
- longestEntry = itemName;
+ var itemText = $"{prototype.Name} [{entry.Amount}]";
- vendingItem.Text = $"{itemName} [{entry.Amount}]";
- vendingItem.Icon = icon;
- filteredInventory.Add(i);
+ if (itemText.Length > longestEntry.Length)
+ longestEntry = itemText;
+
+ listData.Add(new VendorItemsListData(prototype.ID, itemText, i));
}
+ VendingContents.PopulateList(listData);
+
SetSizeAfterUpdate(longestEntry.Length, inventory.Count);
}
private void SetSizeAfterUpdate(int longestEntryLength, int contentCount)
{
- SetSize = new Vector2(Math.Clamp((longestEntryLength + 2) * 12, 250, 300),
+ SetSize = new Vector2(Math.Clamp((longestEntryLength + 2) * 12, 250, 400),
Math.Clamp(contentCount * 50, 150, 350));
}
}
}
+
+public record VendorItemsListData(EntProtoId ItemProtoID, string ItemText, int ItemIndex) : ListData;
diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs
index eafab84ed6..797360d171 100644
--- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs
+++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs
@@ -1,6 +1,9 @@
+using Content.Client.UserInterface.Controls;
using Content.Client.VendingMachines.UI;
using Content.Shared.VendingMachines;
+using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
+using Robust.Shared.Input;
using System.Linq;
using Robust.Client.UserInterface;
@@ -14,9 +17,6 @@ namespace Content.Client.VendingMachines
[ViewVariables]
private List _cachedInventory = new();
- [ViewVariables]
- private List _cachedFilteredIndex = new();
-
public VendingMachineBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
@@ -34,9 +34,10 @@ namespace Content.Client.VendingMachines
_menu.Title = EntMan.GetComponent(Owner).EntityName;
_menu.OnItemSelected += OnItemSelected;
- _menu.OnSearchChanged += OnSearchChanged;
- _menu.Populate(_cachedInventory, out _cachedFilteredIndex);
+ _menu.Populate(_cachedInventory);
+
+ _menu.OpenCenteredLeft();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -48,15 +49,21 @@ namespace Content.Client.VendingMachines
_cachedInventory = newState.Inventory;
- _menu?.Populate(_cachedInventory, out _cachedFilteredIndex, _menu.SearchBar.Text);
+ _menu?.Populate(_cachedInventory);
}
- private void OnItemSelected(ItemList.ItemListSelectedEventArgs args)
+ private void OnItemSelected(GUIBoundKeyEventArgs args, ListData data)
{
+ if (args.Function != EngineKeyFunctions.UIClick)
+ return;
+
+ if (data is not VendorItemsListData { ItemIndex: var itemIndex })
+ return;
+
if (_cachedInventory.Count == 0)
return;
- var selectedItem = _cachedInventory.ElementAtOrDefault(_cachedFilteredIndex.ElementAtOrDefault(args.ItemIndex));
+ var selectedItem = _cachedInventory.ElementAtOrDefault(itemIndex);
if (selectedItem == null)
return;
@@ -77,10 +84,5 @@ namespace Content.Client.VendingMachines
_menu.OnClose -= Close;
_menu.Dispose();
}
-
- private void OnSearchChanged(string? filter)
- {
- _menu?.Populate(_cachedInventory, out _cachedFilteredIndex, filter);
- }
}
}
diff --git a/Content.Client/Voting/UI/VotePopup.xaml b/Content.Client/Voting/UI/VotePopup.xaml
index 39817bd553..fd40d7b790 100644
--- a/Content.Client/Voting/UI/VotePopup.xaml
+++ b/Content.Client/Voting/UI/VotePopup.xaml
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/Content.Client/Voting/UI/VotePopup.xaml.cs b/Content.Client/Voting/UI/VotePopup.xaml.cs
index e82675eeba..6bcd18165a 100644
--- a/Content.Client/Voting/UI/VotePopup.xaml.cs
+++ b/Content.Client/Voting/UI/VotePopup.xaml.cs
@@ -8,6 +8,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
+using Robust.Shared.Utility;
namespace Content.Client.Voting.UI
{
@@ -48,7 +49,7 @@ namespace Content.Client.Voting.UI
public void UpdateData()
{
- VoteTitle.Text = _vote.Title;
+ VoteTitle.SetMessage(FormattedMessage.FromUnformatted(_vote.Title));
VoteCaller.Text = Loc.GetString("ui-vote-created", ("initiator", _vote.Initiator));
for (var i = 0; i < _voteButtons.Length; i++)
diff --git a/Content.Packaging/ServerPackaging.cs b/Content.Packaging/ServerPackaging.cs
index 60f388f85d..711dbd5be3 100644
--- a/Content.Packaging/ServerPackaging.cs
+++ b/Content.Packaging/ServerPackaging.cs
@@ -22,6 +22,7 @@ public static class ServerPackaging
new PlatformReg("win-x86", "Windows", false),
new PlatformReg("linux-x86", "Linux", false),
new PlatformReg("linux-arm", "Linux", false),
+ new PlatformReg("freebsd-x64", "FreeBSD", false),
};
private static List PlatformRids => Platforms
diff --git a/Content.Server.Database/Migrations/Postgres/20240606121555_ban_notify_trigger.Designer.cs b/Content.Server.Database/Migrations/Postgres/20240606121555_ban_notify_trigger.Designer.cs
new file mode 100644
index 0000000000..2f06e5ff98
--- /dev/null
+++ b/Content.Server.Database/Migrations/Postgres/20240606121555_ban_notify_trigger.Designer.cs
@@ -0,0 +1,1913 @@
+//
+using System;
+using System.Net;
+using System.Text.Json;
+using Content.Server.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NpgsqlTypes;
+
+#nullable disable
+
+namespace Content.Server.Database.Migrations.Postgres
+{
+ [DbContext(typeof(PostgresServerDbContext))]
+ [Migration("20240606121555_ban_notify_trigger")]
+ partial class ban_notify_trigger
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Content.Server.Database.Admin", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property("AdminRankId")
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ b.Property("Title")
+ .HasColumnType("text")
+ .HasColumnName("title");
+
+ b.HasKey("UserId")
+ .HasName("PK_admin");
+
+ b.HasIndex("AdminRankId")
+ .HasDatabaseName("IX_admin_admin_rank_id");
+
+ b.ToTable("admin", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_flag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AdminId")
+ .HasColumnType("uuid")
+ .HasColumnName("admin_id");
+
+ b.Property("Flag")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flag");
+
+ b.Property("Negative")
+ .HasColumnType("boolean")
+ .HasColumnName("negative");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_flag");
+
+ b.HasIndex("AdminId")
+ .HasDatabaseName("IX_admin_flag_admin_id");
+
+ b.HasIndex("Flag", "AdminId")
+ .IsUnique();
+
+ b.ToTable("admin_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
+ {
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("Id")
+ .HasColumnType("integer")
+ .HasColumnName("admin_log_id");
+
+ b.Property("Date")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("date");
+
+ b.Property("Impact")
+ .HasColumnType("smallint")
+ .HasColumnName("impact");
+
+ b.Property("Json")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("json");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("message");
+
+ b.Property("Type")
+ .HasColumnType("integer")
+ .HasColumnName("type");
+
+ b.HasKey("RoundId", "Id")
+ .HasName("PK_admin_log");
+
+ b.HasIndex("Date");
+
+ b.HasIndex("Message")
+ .HasAnnotation("Npgsql:TsVectorConfig", "english");
+
+ NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Message"), "GIN");
+
+ b.HasIndex("Type")
+ .HasDatabaseName("IX_admin_log_type");
+
+ b.ToTable("admin_log", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
+ {
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("LogId")
+ .HasColumnType("integer")
+ .HasColumnName("log_id");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.HasKey("RoundId", "LogId", "PlayerUserId")
+ .HasName("PK_admin_log_player");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_log_player_player_user_id");
+
+ b.ToTable("admin_log_player", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminMessage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_messages_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Dismissed")
+ .HasColumnType("boolean")
+ .HasColumnName("dismissed");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("Seen")
+ .HasColumnType("boolean")
+ .HasColumnName("seen");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_messages");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_messages_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_messages_round_id");
+
+ b.ToTable("admin_messages", null, t =>
+ {
+ t.HasCheckConstraint("NotDismissedAndSeen", "NOT dismissed OR seen");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminNote", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_notes_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property("LastEditedAt")
+ .IsRequired()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("Secret")
+ .HasColumnType("boolean")
+ .HasColumnName("secret");
+
+ b.Property("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_notes");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_notes_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_notes_round_id");
+
+ b.ToTable("admin_notes", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank");
+
+ b.ToTable("admin_rank", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_flag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AdminRankId")
+ .HasColumnType("integer")
+ .HasColumnName("admin_rank_id");
+
+ b.Property("Flag")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flag");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_rank_flag");
+
+ b.HasIndex("AdminRankId");
+
+ b.HasIndex("Flag", "AdminRankId")
+ .IsUnique();
+
+ b.ToTable("admin_rank_flag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("admin_watchlists_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("uuid")
+ .HasColumnName("created_by_id");
+
+ b.Property("Deleted")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("uuid")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property("LastEditedAt")
+ .IsRequired()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasMaxLength(4096)
+ .HasColumnType("character varying(4096)")
+ .HasColumnName("message");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.HasKey("Id")
+ .HasName("PK_admin_watchlists");
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("DeletedById");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_admin_watchlists_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_admin_watchlists_round_id");
+
+ b.ToTable("admin_watchlists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Antag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("antag_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AntagName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("antag_name");
+
+ b.Property("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_antag");
+
+ b.HasIndex("ProfileId", "AntagName")
+ .IsUnique();
+
+ b.ToTable("antag", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("assigned_user_id_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_assigned_user_id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("assigned_user_id", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("connection_log_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .IsRequired()
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property("Denied")
+ .HasColumnType("smallint")
+ .HasColumnName("denied");
+
+ b.Property("HWId")
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b.Property("ServerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("server_id");
+
+ b.Property("Time")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("time");
+
+ b.Property("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("PK_connection_log");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_connection_log_server_id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("connection_log", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Job", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("job_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("JobName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("job_name");
+
+ b.Property("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("priority");
+
+ b.Property("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.HasKey("Id")
+ .HasName("PK_job");
+
+ b.HasIndex("ProfileId");
+
+ b.HasIndex("ProfileId", "JobName")
+ .IsUnique();
+
+ b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority")
+ .IsUnique()
+ .HasFilter("priority = 3");
+
+ b.ToTable("job", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.PlayTime", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("play_time_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("PlayerId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_id");
+
+ b.Property("TimeSpent")
+ .HasColumnType("interval")
+ .HasColumnName("time_spent");
+
+ b.Property("Tracker")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("tracker");
+
+ b.HasKey("Id")
+ .HasName("PK_play_time");
+
+ b.HasIndex("PlayerId", "Tracker")
+ .IsUnique();
+
+ b.ToTable("play_time", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Player", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("player_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("FirstSeenTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("first_seen_time");
+
+ b.Property("LastReadRules")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_read_rules");
+
+ b.Property("LastSeenAddress")
+ .IsRequired()
+ .HasColumnType("inet")
+ .HasColumnName("last_seen_address");
+
+ b.Property("LastSeenHWId")
+ .HasColumnType("bytea")
+ .HasColumnName("last_seen_hwid");
+
+ b.Property("LastSeenTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_seen_time");
+
+ b.Property("LastSeenUserName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("last_seen_user_name");
+
+ b.Property("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_player");
+
+ b.HasAlternateKey("UserId")
+ .HasName("ak_player_user_id");
+
+ b.HasIndex("LastSeenUserName");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("player", null, t =>
+ {
+ t.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Preference", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("preference_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AdminOOCColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("admin_ooc_color");
+
+ b.Property("SelectedCharacterSlot")
+ .HasColumnType("integer")
+ .HasColumnName("selected_character_slot");
+
+ b.Property("UserId")
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("PK_preference");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("preference", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Profile", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Age")
+ .HasColumnType("integer")
+ .HasColumnName("age");
+
+ b.Property("CharacterName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("char_name");
+
+ b.Property("EyeColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("eye_color");
+
+ b.Property("FacialHairColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("facial_hair_color");
+
+ b.Property("FacialHairName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("facial_hair_name");
+
+ b.Property("FlavorText")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("flavor_text");
+
+ b.Property("Gender")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("gender");
+
+ b.Property("HairColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("hair_color");
+
+ b.Property("HairName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("hair_name");
+
+ b.Property("Markings")
+ .HasColumnType("jsonb")
+ .HasColumnName("markings");
+
+ b.Property("PreferenceId")
+ .HasColumnType("integer")
+ .HasColumnName("preference_id");
+
+ b.Property("PreferenceUnavailable")
+ .HasColumnType("integer")
+ .HasColumnName("pref_unavailable");
+
+ b.Property("Sex")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("sex");
+
+ b.Property("SkinColor")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("skin_color");
+
+ b.Property("Slot")
+ .HasColumnType("integer")
+ .HasColumnName("slot");
+
+ b.Property("SpawnPriority")
+ .HasColumnType("integer")
+ .HasColumnName("spawn_priority");
+
+ b.Property("Species")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("species");
+
+ b.HasKey("Id")
+ .HasName("PK_profile");
+
+ b.HasIndex("PreferenceId")
+ .HasDatabaseName("IX_profile_preference_id");
+
+ b.HasIndex("Slot", "PreferenceId")
+ .IsUnique();
+
+ b.ToTable("profile", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("LoadoutName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("loadout_name");
+
+ b.Property("ProfileLoadoutGroupId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_group_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout");
+
+ b.HasIndex("ProfileLoadoutGroupId");
+
+ b.ToTable("profile_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_loadout_group_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("GroupName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("group_name");
+
+ b.Property("ProfileRoleLoadoutId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_role_loadout_id");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_loadout_group");
+
+ b.HasIndex("ProfileRoleLoadoutId");
+
+ b.ToTable("profile_loadout_group", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("profile_role_loadout_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.Property("RoleName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("role_name");
+
+ b.HasKey("Id")
+ .HasName("PK_profile_role_loadout");
+
+ b.HasIndex("ProfileId");
+
+ b.ToTable("profile_role_loadout", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b =>
+ {
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("RoleId")
+ .HasColumnType("text")
+ .HasColumnName("role_id");
+
+ b.HasKey("PlayerUserId", "RoleId")
+ .HasName("PK_role_whitelists");
+
+ b.ToTable("role_whitelists", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Round", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ServerId")
+ .HasColumnType("integer")
+ .HasColumnName("server_id");
+
+ b.Property("StartDate")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("start_date");
+
+ b.HasKey("Id")
+ .HasName("PK_round");
+
+ b.HasIndex("ServerId")
+ .HasDatabaseName("IX_round_server_id");
+
+ b.HasIndex("StartDate");
+
+ b.ToTable("round", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Server", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.HasKey("Id")
+ .HasName("PK_server");
+
+ b.ToTable("server", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_ban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property("AutoDelete")
+ .HasColumnType("boolean")
+ .HasColumnName("auto_delete");
+
+ b.Property("BanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("ban_time");
+
+ b.Property("BanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("banning_admin");
+
+ b.Property("ExemptFlags")
+ .HasColumnType("integer")
+ .HasColumnName("exempt_flags");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property("HWId")
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b.Property("Hidden")
+ .HasColumnType("boolean")
+ .HasColumnName("hidden");
+
+ b.Property("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("reason");
+
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_ban_round_id");
+
+ b.ToTable("server_ban", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanExemption", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("user_id");
+
+ b.Property("Flags")
+ .HasColumnType("integer")
+ .HasColumnName("flags");
+
+ b.HasKey("UserId")
+ .HasName("PK_server_ban_exemption");
+
+ b.ToTable("server_ban_exemption", null, t =>
+ {
+ t.HasCheckConstraint("FlagsNotZero", "flags != 0");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_ban_hit_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property("ConnectionId")
+ .HasColumnType("integer")
+ .HasColumnName("connection_id");
+
+ b.HasKey("Id")
+ .HasName("PK_server_ban_hit");
+
+ b.HasIndex("BanId")
+ .HasDatabaseName("IX_server_ban_hit_ban_id");
+
+ b.HasIndex("ConnectionId")
+ .HasDatabaseName("IX_server_ban_hit_connection_id");
+
+ b.ToTable("server_ban_hit", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("server_role_ban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .HasColumnType("inet")
+ .HasColumnName("address");
+
+ b.Property("BanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("ban_time");
+
+ b.Property("BanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("banning_admin");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expiration_time");
+
+ b.Property("HWId")
+ .HasColumnType("bytea")
+ .HasColumnName("hwid");
+
+ b.Property("Hidden")
+ .HasColumnType("boolean")
+ .HasColumnName("hidden");
+
+ b.Property("LastEditedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_edited_at");
+
+ b.Property("LastEditedById")
+ .HasColumnType("uuid")
+ .HasColumnName("last_edited_by_id");
+
+ b.Property("PlayerUserId")
+ .HasColumnType("uuid")
+ .HasColumnName("player_user_id");
+
+ b.Property("PlaytimeAtNote")
+ .HasColumnType("interval")
+ .HasColumnName("playtime_at_note");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("reason");
+
+ b.Property("RoleId")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("role_id");
+
+ b.Property("RoundId")
+ .HasColumnType("integer")
+ .HasColumnName("round_id");
+
+ b.Property("Severity")
+ .HasColumnType("integer")
+ .HasColumnName("severity");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_ban");
+
+ b.HasIndex("Address");
+
+ b.HasIndex("BanningAdmin");
+
+ b.HasIndex("LastEditedById");
+
+ b.HasIndex("PlayerUserId")
+ .HasDatabaseName("IX_server_role_ban_player_user_id");
+
+ b.HasIndex("RoundId")
+ .HasDatabaseName("IX_server_role_ban_round_id");
+
+ b.ToTable("server_role_ban", null, t =>
+ {
+ t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
+
+ t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL");
+ });
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("role_unban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property("UnbanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("unban_time");
+
+ b.Property("UnbanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_role_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_role_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("unban_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BanId")
+ .HasColumnType("integer")
+ .HasColumnName("ban_id");
+
+ b.Property("UnbanTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("unban_time");
+
+ b.Property("UnbanningAdmin")
+ .HasColumnType("uuid")
+ .HasColumnName("unbanning_admin");
+
+ b.HasKey("Id")
+ .HasName("PK_server_unban");
+
+ b.HasIndex("BanId")
+ .IsUnique();
+
+ b.ToTable("server_unban", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Trait", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("trait_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ProfileId")
+ .HasColumnType("integer")
+ .HasColumnName("profile_id");
+
+ b.Property("TraitName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trait_name");
+
+ b.HasKey("Id")
+ .HasName("PK_trait");
+
+ b.HasIndex("ProfileId", "TraitName")
+ .IsUnique();
+
+ b.ToTable("trait", (string)null);
+ });
+
+ modelBuilder.Entity("Content.Server.Database.UploadedResourceLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("uploaded_resource_log_id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Data")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("data");
+
+ b.Property