Compare commits

..

2 Commits

Author SHA1 Message Date
comasqw
a20f2ba6a3 refactor Prototype class init 2024-11-19 17:12:42 +04:00
comasqw
c00de7fd09 refactor 2024-11-19 17:09:14 +04:00
1204 changed files with 14518 additions and 43026 deletions

2
.github/labeler.yml vendored
View File

@@ -16,7 +16,7 @@
- changed-files: - changed-files:
- any-glob-to-any-file: '**/*.swsl' - any-glob-to-any-file: '**/*.swsl'
"Changes: No C#": "No C#":
- changed-files: - changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label. # Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
- all-globs-to-all-files: "!**/*.cs" - all-globs-to-all-files: "!**/*.cs"

View File

@@ -16,6 +16,6 @@ jobs:
- name: Check for Merge Conflicts - name: Check for Merge Conflicts
uses: eps1lon/actions-label-merge-conflict@v3.0.0 uses: eps1lon/actions-label-merge-conflict@v3.0.0
with: with:
dirtyLabel: "S: Merge Conflict" dirtyLabel: "Merge Conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}" repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request." commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."

View File

@@ -10,7 +10,7 @@ jobs:
steps: steps:
- uses: actions-ecosystem/action-add-labels@v1 - uses: actions-ecosystem/action-add-labels@v1
with: with:
labels: "S: Needs Review" labels: "Status: Needs Review"
- uses: actions-ecosystem/action-remove-labels@v1 - uses: actions-ecosystem/action-remove-labels@v1
with: with:
labels: "S: Awaiting Changes" labels: "Status: Awaiting Changes"

View File

@@ -1,23 +0,0 @@
name: "Labels: Approved"
on:
pull_request_review:
types: [submitted]
jobs:
add_label:
# Change the repository name after you've made sure the team name is correct for your fork!
if: ${{ (github.repository == 'space-wizards/space-station-14') && (github.event.review.state == 'APPROVED') }}
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: tspascoal/get-user-teams-membership@v3
id: checkUserMember
with:
username: ${{ github.actor }}
team: "content-maintainers,junior-maintainers"
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
uses: actions-ecosystem/action-add-labels@v1
with:
labels: "S: Approved"

View File

@@ -1,20 +0,0 @@
name: "Labels: Size"
on: pull_request_target
jobs:
size-label:
runs-on: ubuntu-latest
steps:
- name: size-label
uses: "pascalgn/size-label-action@v0.5.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
with:
# Custom size configuration
sizes: >
{
"0": "XS",
"10": "S",
"30": "M",
"100": "L",
"1000": "XL"
}

View File

@@ -1,16 +0,0 @@
name: "Labels: Branch stable"
on:
pull_request_target:
types:
- opened
branches:
- 'stable'
jobs:
add_label:
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: Stable"

View File

@@ -1,16 +0,0 @@
name: "Labels: Branch staging"
on:
pull_request_target:
types:
- opened
branches:
- 'staging'
jobs:
add_label:
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: Staging"

View File

@@ -3,8 +3,6 @@
on: on:
issues: issues:
types: [opened] types: [opened]
pull_request_target:
types: [opened]
jobs: jobs:
add_label: add_label:
@@ -13,4 +11,4 @@ jobs:
- uses: actions-ecosystem/action-add-labels@v1 - uses: actions-ecosystem/action-add-labels@v1
if: join(github.event.issue.labels) == '' if: join(github.event.issue.labels) == ''
with: with:
labels: "S: Untriaged" labels: "Status: Untriaged"

View File

@@ -22,11 +22,11 @@ namespace Content.Client.Administration.UI.BanPanel;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class BanPanel : DefaultWindow public sealed partial class BanPanel : DefaultWindow
{ {
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted; public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string>? PlayerChanged; public event Action<string>? PlayerChanged;
private string? PlayerUsername { get; set; } private string? PlayerUsername { get; set; }
private (IPAddress, int)? IpAddress { get; set; } private (IPAddress, int)? IpAddress { get; set; }
private ImmutableTypedHwid? Hwid { get; set; } private byte[]? Hwid { get; set; }
private double TimeEntered { get; set; } private double TimeEntered { get; set; }
private uint Multiplier { get; set; } private uint Multiplier { get; set; }
private bool HasBanFlag { get; set; } private bool HasBanFlag { get; set; }
@@ -371,8 +371,9 @@ public sealed partial class BanPanel : DefaultWindow
private void OnHwidChanged() private void OnHwidChanged()
{ {
var hwidString = HwidLine.Text; var hwidString = HwidLine.Text;
ImmutableTypedHwid? hwid = null; var length = 3 * (hwidString.Length / 4) - hwidString.TakeLast(2).Count(c => c == '=');
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !ImmutableTypedHwid.TryParse(hwidString, out hwid)) Hwid = new byte[length];
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !Convert.TryFromBase64String(hwidString, Hwid, out _))
{ {
ErrorLevel |= ErrorLevelEnum.Hwid; ErrorLevel |= ErrorLevelEnum.Hwid;
HwidLine.ModulateSelfOverride = Color.Red; HwidLine.ModulateSelfOverride = Color.Red;
@@ -389,7 +390,7 @@ public sealed partial class BanPanel : DefaultWindow
Hwid = null; Hwid = null;
return; return;
} }
Hwid = hwid; Hwid = Convert.FromHexString(hwidString);
} }
private void OnTypeChanged() private void OnTypeChanged()

View File

@@ -8,7 +8,6 @@
<Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" /> <Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" />
<HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}" <HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}"
Visible="False" HorizontalExpand="True" /> Visible="False" HorizontalExpand="True" />
<OptionButton Name="ExpiryLengthDropdown" Visible="False" />
</BoxContainer> </BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<OptionButton Name="TypeOption" HorizontalAlignment="Center" /> <OptionButton Name="TypeOption" HorizontalAlignment="Center" />

View File

@@ -17,17 +17,6 @@ public sealed partial class NoteEdit : FancyWindow
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientConsoleHost _console = default!; [Dependency] private readonly IClientConsoleHost _console = default!;
private enum Multipliers
{
Minutes,
Hours,
Days,
Weeks,
Months,
Years,
Centuries
}
public event Action<int, NoteType, string, NoteSeverity?, bool, DateTime?>? SubmitPressed; public event Action<int, NoteType, string, NoteSeverity?, bool, DateTime?>? SubmitPressed;
public NoteEdit(SharedAdminNote? note, string playerName, bool canCreate, bool canEdit) public NoteEdit(SharedAdminNote? note, string playerName, bool canCreate, bool canEdit)
@@ -42,20 +31,6 @@ public sealed partial class NoteEdit : FancyWindow
ResetSubmitButton(); ResetSubmitButton();
// It's weird to use minutes as the IDs, but it works and makes sense kind of :)
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-minutes"), (int) Multipliers.Minutes);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-hours"), (int) Multipliers.Hours);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-days"), (int) Multipliers.Days);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-weeks"), (int) Multipliers.Weeks);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-months"), (int) Multipliers.Months);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-years"), (int) Multipliers.Years);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-centuries"), (int) Multipliers.Centuries);
ExpiryLengthDropdown.OnItemSelected += OnLengthChanged;
ExpiryLengthDropdown.SelectId((int) Multipliers.Weeks);
ExpiryLineEdit.OnTextChanged += OnTextChanged;
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-note"), (int) NoteType.Note); TypeOption.AddItem(Loc.GetString("admin-note-editor-type-note"), (int) NoteType.Note);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-message"), (int) NoteType.Message); TypeOption.AddItem(Loc.GetString("admin-note-editor-type-message"), (int) NoteType.Message);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-watchlist"), (int) NoteType.Watchlist); TypeOption.AddItem(Loc.GetString("admin-note-editor-type-watchlist"), (int) NoteType.Watchlist);
@@ -197,9 +172,8 @@ public sealed partial class NoteEdit : FancyWindow
{ {
ExpiryLabel.Visible = !PermanentCheckBox.Pressed; ExpiryLabel.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Visible = !PermanentCheckBox.Pressed; ExpiryLineEdit.Visible = !PermanentCheckBox.Pressed;
ExpiryLengthDropdown.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? 1.ToString() : string.Empty; ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty;
} }
private void OnSecretPressed(BaseButton.ButtonEventArgs _) private void OnSecretPressed(BaseButton.ButtonEventArgs _)
@@ -213,16 +187,6 @@ public sealed partial class NoteEdit : FancyWindow
SeverityOption.SelectId(args.Id); SeverityOption.SelectId(args.Id);
} }
private void OnLengthChanged(OptionButton.ItemSelectedEventArgs args)
{
ExpiryLengthDropdown.SelectId(args.Id);
}
private void OnTextChanged(HistoryLineEdit.LineEditEventArgs args)
{
ParseExpiryTime();
}
private void OnSubmitButtonPressed(BaseButton.ButtonEventArgs args) private void OnSubmitButtonPressed(BaseButton.ButtonEventArgs args)
{ {
if (!ParseExpiryTime()) if (!ParseExpiryTime())
@@ -299,24 +263,13 @@ public sealed partial class NoteEdit : FancyWindow
return true; return true;
} }
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !uint.TryParse(ExpiryLineEdit.Text, out var inputInt)) if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !DateTime.TryParse(ExpiryLineEdit.Text, out var result) || DateTime.UtcNow > result)
{ {
ExpiryLineEdit.ModulateSelfOverride = Color.Red; ExpiryLineEdit.ModulateSelfOverride = Color.Red;
return false; return false;
} }
var mult = ExpiryLengthDropdown.SelectedId switch ExpiryTime = result.ToUniversalTime();
{
(int) Multipliers.Minutes => TimeSpan.FromMinutes(1).TotalMinutes,
(int) Multipliers.Hours => TimeSpan.FromHours(1).TotalMinutes,
(int) Multipliers.Days => TimeSpan.FromDays(1).TotalMinutes,
(int) Multipliers.Weeks => TimeSpan.FromDays(7).TotalMinutes,
(int) Multipliers.Months => TimeSpan.FromDays(30).TotalMinutes,
(int) Multipliers.Years => TimeSpan.FromDays(365).TotalMinutes,
(int) Multipliers.Centuries => TimeSpan.FromDays(36525).TotalMinutes,
_ => throw new ArgumentOutOfRangeException(nameof(ExpiryLengthDropdown.SelectedId), "Multiplier out of range :(")
};
ExpiryTime = DateTime.UtcNow.AddMinutes(inputInt * mult);
ExpiryLineEdit.ModulateSelfOverride = null; ExpiryLineEdit.ModulateSelfOverride = null;
return true; return true;
} }

View File

@@ -2,7 +2,6 @@ using System.Linq;
using Content.Shared.Alert; using Content.Shared.Alert;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.GameStates;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -25,7 +24,8 @@ public sealed class ClientAlertsSystem : AlertsSystem
SubscribeLocalEvent<AlertsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached); SubscribeLocalEvent<AlertsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<AlertsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached); SubscribeLocalEvent<AlertsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<AlertsComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<AlertsComponent, AfterAutoHandleStateEvent>(ClientAlertsHandleState);
} }
protected override void LoadPrototypes() protected override void LoadPrototypes()
{ {
@@ -47,16 +47,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
} }
} }
private void OnHandleState(Entity<AlertsComponent> alerts, ref ComponentHandleState args)
{
if (args.Current is not AlertComponentState cast)
return;
alerts.Comp.Alerts = cast.Alerts;
UpdateHud(alerts);
}
protected override void AfterShowAlert(Entity<AlertsComponent> alerts) protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
{ {
UpdateHud(alerts); UpdateHud(alerts);
@@ -67,6 +57,11 @@ public sealed class ClientAlertsSystem : AlertsSystem
UpdateHud(alerts); UpdateHud(alerts);
} }
private void ClientAlertsHandleState(Entity<AlertsComponent> alerts, ref AfterAutoHandleStateEvent args)
{
UpdateHud(alerts);
}
private void UpdateHud(Entity<AlertsComponent> entity) private void UpdateHud(Entity<AlertsComponent> entity)
{ {
if (_playerManager.LocalEntity == entity.Owner) if (_playerManager.LocalEntity == entity.Owner)

View File

@@ -65,7 +65,6 @@ public sealed class ClientClothingSystem : ClothingSystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals); SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged); SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip); SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
@@ -78,7 +77,11 @@ public sealed class ClientClothingSystem : ClothingSystem
if (args.Sprite == null) if (args.Sprite == null)
return; return;
UpdateAllSlots(uid, component); var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, component);
}
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip. // No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer)) if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer))
@@ -88,23 +91,6 @@ public sealed class ClientClothingSystem : ClothingSystem
} }
} }
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
{
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
}
private void UpdateAllSlots(
EntityUid uid,
InventoryComponent? inventoryComponent = null,
ClothingComponent? clothing = null)
{
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
}
}
private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args) private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args)
{ {
if (!TryComp(args.Equipee, out InventoryComponent? inventory)) if (!TryComp(args.Equipee, out InventoryComponent? inventory))

View File

@@ -1,20 +1,15 @@
<DefaultWindow xmlns="https://spacestation14.io"> <DefaultWindow xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" MinWidth="243" Margin="0 0 5 0"> <BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5"> <BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5">
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/> <LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/>
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/> <OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/>
</BoxContainer> </BoxContainer>
<ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/> <ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/>
<ScrollContainer Name="RecipesGridScrollContainer" VerticalExpand="True" Access="Public" Visible="False">
<GridContainer Name="RecipesGrid" Columns="5" Access="Public"/>
</ScrollContainer>
</BoxContainer> </BoxContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True"> <BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
<BoxContainer Orientation="Horizontal"> <Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
<Button Name="MenuGridViewButton" ToggleMode="True" Text="{Loc construction-menu-grid-view}"/> HorizontalAlignment="Right" Margin="0 0 0 15"/>
<Button Name="FavoriteButton" Visible="false"/>
</BoxContainer>
<Control> <Control>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5"> <BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5">
<BoxContainer Orientation="Horizontal" Align="Center"> <BoxContainer Orientation="Horizontal" Align="Center">

View File

@@ -25,16 +25,11 @@ namespace Content.Client.Construction.UI
OptionButton OptionCategories { get; } OptionButton OptionCategories { get; }
bool EraseButtonPressed { get; set; } bool EraseButtonPressed { get; set; }
bool GridViewButtonPressed { get; set; }
bool BuildButtonPressed { get; set; } bool BuildButtonPressed { get; set; }
ItemList Recipes { get; } ItemList Recipes { get; }
ItemList RecipeStepList { get; } ItemList RecipeStepList { get; }
ScrollContainer RecipesGridScrollContainer { get; }
GridContainer RecipesGrid { get; }
event EventHandler<(string search, string catagory)> PopulateRecipes; event EventHandler<(string search, string catagory)> PopulateRecipes;
event EventHandler<ItemList.Item?> RecipeSelected; event EventHandler<ItemList.Item?> RecipeSelected;
event EventHandler RecipeFavorited; event EventHandler RecipeFavorited;
@@ -77,16 +72,9 @@ namespace Content.Client.Construction.UI
set => EraseButton.Pressed = value; set => EraseButton.Pressed = value;
} }
public bool GridViewButtonPressed
{
get => MenuGridViewButton.Pressed;
set => MenuGridViewButton.Pressed = value;
}
public ConstructionMenu() public ConstructionMenu()
{ {
SetSize = new Vector2(560, 450); SetSize = MinSize = new Vector2(720, 320);
MinSize = new Vector2(560, 320);
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
@@ -114,9 +102,6 @@ namespace Content.Client.Construction.UI
EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed); EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed);
FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty); FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty);
MenuGridViewButton.OnPressed += _ =>
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId]));
} }
public event EventHandler? ClearAllGhosts; public event EventHandler? ClearAllGhosts;

View File

@@ -1,8 +1,7 @@
using System.Linq; using System.Linq;
using System.Numerics;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Shared.Construction.Prototypes; using Content.Shared.Construction.Prototypes;
using Content.Shared.Tag;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
@@ -12,6 +11,7 @@ using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility; using Robust.Client.Utility;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BaseButton; using static Robust.Client.UserInterface.Controls.BaseButton;
@@ -33,12 +33,10 @@ namespace Content.Client.Construction.UI
private readonly IConstructionMenuView _constructionView; private readonly IConstructionMenuView _constructionView;
private readonly EntityWhitelistSystem _whitelistSystem; private readonly EntityWhitelistSystem _whitelistSystem;
private readonly SpriteSystem _spriteSystem;
private ConstructionSystem? _constructionSystem; private ConstructionSystem? _constructionSystem;
private ConstructionPrototype? _selected; private ConstructionPrototype? _selected;
private List<ConstructionPrototype> _favoritedRecipes = []; private List<ConstructionPrototype> _favoritedRecipes = [];
private Dictionary<string, TextureButton> _recipeButtons = new();
private string _selectedCategory = string.Empty; private string _selectedCategory = string.Empty;
private string _favoriteCatName = "construction-category-favorites"; private string _favoriteCatName = "construction-category-favorites";
private string _forAllCategoryName = "construction-category-all"; private string _forAllCategoryName = "construction-category-all";
@@ -87,7 +85,6 @@ namespace Content.Client.Construction.UI
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_constructionView = new ConstructionMenu(); _constructionView = new ConstructionMenu();
_whitelistSystem = _entManager.System<EntityWhitelistSystem>(); _whitelistSystem = _entManager.System<EntityWhitelistSystem>();
_spriteSystem = _entManager.System<SpriteSystem>();
// This is required so that if we load after the system is initialized, we can bind to it immediately // This is required so that if we load after the system is initialized, we can bind to it immediately
if (_systemManager.TryGetEntitySystem<ConstructionSystem>(out var constructionSystem)) if (_systemManager.TryGetEntitySystem<ConstructionSystem>(out var constructionSystem))
@@ -153,24 +150,12 @@ namespace Content.Client.Construction.UI
PopulateInfo(_selected); PopulateInfo(_selected);
} }
private void OnGridViewRecipeSelected(object? sender, ConstructionPrototype? recipe)
{
if (recipe is null)
{
_selected = null;
_constructionView.ClearRecipeInfo();
return;
}
_selected = recipe;
if (_placementManager.IsActive && !_placementManager.Eraser) UpdateGhostPlacement();
PopulateInfo(_selected);
}
private void OnViewPopulateRecipes(object? sender, (string search, string catagory) args) private void OnViewPopulateRecipes(object? sender, (string search, string catagory) args)
{ {
var (search, category) = args; var (search, category) = args;
var recipesList = _constructionView.Recipes;
recipesList.Clear();
var recipes = new List<ConstructionPrototype>(); var recipes = new List<ConstructionPrototype>();
var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName; var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName;
@@ -185,7 +170,7 @@ namespace Content.Client.Construction.UI
if (recipe.Hide) if (recipe.Hide)
continue; continue;
if (!recipe.CrystallPunkAllowed) //CrystallEdge clearing recipes if (!recipe.CrystallPunkAllowed) //CrystallPunk clearing recipes
continue; continue;
if (_playerManager.LocalSession == null if (_playerManager.LocalSession == null
@@ -219,73 +204,12 @@ namespace Content.Client.Construction.UI
recipes.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCulture)); recipes.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCulture));
var recipesList = _constructionView.Recipes; foreach (var recipe in recipes)
recipesList.Clear();
var recipesGrid = _constructionView.RecipesGrid;
recipesGrid.RemoveAllChildren();
_constructionView.RecipesGridScrollContainer.Visible = _constructionView.GridViewButtonPressed;
_constructionView.Recipes.Visible = !_constructionView.GridViewButtonPressed;
if (_constructionView.GridViewButtonPressed)
{ {
foreach (var recipe in recipes) recipesList.Add(GetItem(recipe, recipesList));
{
var itemButton = new TextureButton
{
TextureNormal = _spriteSystem.Frame0(recipe.Icon),
VerticalAlignment = Control.VAlignment.Center,
Name = recipe.Name,
ToolTip = recipe.Name,
Scale = new Vector2(1.35f),
ToggleMode = true,
};
var itemButtonPanelContainer = new PanelContainer
{
PanelOverride = new StyleBoxFlat { BackgroundColor = StyleNano.ButtonColorDefault },
Children = { itemButton },
};
itemButton.OnToggled += buttonToggledEventArgs =>
{
SelectGridButton(itemButton, buttonToggledEventArgs.Pressed);
if (buttonToggledEventArgs.Pressed &&
_selected != null &&
_recipeButtons.TryGetValue(_selected.Name, out var oldButton))
{
oldButton.Pressed = false;
SelectGridButton(oldButton, false);
}
OnGridViewRecipeSelected(this, buttonToggledEventArgs.Pressed ? recipe : null);
};
recipesGrid.AddChild(itemButtonPanelContainer);
_recipeButtons[recipe.Name] = itemButton;
var isCurrentButtonSelected = _selected == recipe;
itemButton.Pressed = isCurrentButtonSelected;
SelectGridButton(itemButton, isCurrentButtonSelected);
}
} }
else
{
foreach (var recipe in recipes)
{
recipesList.Add(GetItem(recipe, recipesList));
}
}
}
private void SelectGridButton(TextureButton button, bool select) // There is apparently no way to set which
{
if (button.Parent is not PanelContainer buttonPanel)
return;
button.Modulate = select ? Color.Green : Color.White;
var buttonColor = select ? StyleNano.ButtonColorDefault : Color.Transparent;
buttonPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = buttonColor };
} }
private void PopulateCategories(string? selectCategory = null) private void PopulateCategories(string? selectCategory = null)
@@ -336,10 +260,11 @@ namespace Content.Client.Construction.UI
private void PopulateInfo(ConstructionPrototype prototype) private void PopulateInfo(ConstructionPrototype prototype)
{ {
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
_constructionView.ClearRecipeInfo(); _constructionView.ClearRecipeInfo();
_constructionView.SetRecipeInfo( _constructionView.SetRecipeInfo(
prototype.Name, prototype.Description, _spriteSystem.Frame0(prototype.Icon), prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon),
prototype.Type != ConstructionType.Item, prototype.Type != ConstructionType.Item,
!_favoritedRecipes.Contains(prototype)); !_favoritedRecipes.Contains(prototype));
@@ -352,6 +277,7 @@ namespace Content.Client.Construction.UI
if (_constructionSystem?.GetGuide(prototype) is not { } guide) if (_constructionSystem?.GetGuide(prototype) is not { } guide)
return; return;
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
foreach (var entry in guide.Entries) foreach (var entry in guide.Entries)
{ {
@@ -367,20 +293,20 @@ namespace Content.Client.Construction.UI
// The padding needs to be applied regardless of text length... (See PadLeft documentation) // The padding needs to be applied regardless of text length... (See PadLeft documentation)
text = text.PadLeft(text.Length + entry.Padding); text = text.PadLeft(text.Length + entry.Padding);
var icon = entry.Icon != null ? _spriteSystem.Frame0(entry.Icon) : Texture.Transparent; var icon = entry.Icon != null ? spriteSys.Frame0(entry.Icon) : Texture.Transparent;
stepList.AddItem(text, icon, false); stepList.AddItem(text, icon, false);
} }
} }
private ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList) private static ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
{ {
return new(itemList) return new(itemList)
{ {
Metadata = recipe, Metadata = recipe,
Text = recipe.Name, Text = recipe.Name,
Icon = _spriteSystem.Frame0(recipe.Icon), Icon = recipe.Icon.Frame0(),
TooltipEnabled = true, TooltipEnabled = true,
TooltipText = recipe.Description, TooltipText = recipe.Description
}; };
} }

View File

@@ -31,7 +31,7 @@ namespace Content.Client.Crayon.UI
private void PopulateCrayons() private void PopulateCrayons()
{ {
var crayonDecals = _protoManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon")); var crayonDecals = _protoManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
_menu?.Populate(crayonDecals.ToList()); _menu?.Populate(crayonDecals);
} }
public override void OnProtoReload(PrototypesReloadedEventArgs args) public override void OnProtoReload(PrototypesReloadedEventArgs args)
@@ -44,16 +44,6 @@ namespace Content.Client.Crayon.UI
PopulateCrayons(); PopulateCrayons();
} }
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
base.ReceiveMessage(message);
if (_menu is null || message is not CrayonUsedMessage crayonMessage)
return;
_menu.AdvanceState(crayonMessage.DrawnDecal);
}
protected override void UpdateState(BoundUserInterfaceState state) protected override void UpdateState(BoundUserInterfaceState state)
{ {
base.UpdateState(state); base.UpdateState(state);

View File

@@ -1,13 +1,14 @@
<DefaultWindow xmlns="https://spacestation14.io" <DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'crayon-window-title'}" Title="{Loc 'crayon-window-title'}"
MinSize="450 500" MinSize="250 300"
SetSize="450 500"> SetSize="250 300">
<BoxContainer Orientation="Vertical"> <BoxContainer Orientation="Vertical">
<ColorSelectorSliders Name="ColorSelector" Visible="False" /> <ColorSelectorSliders Name="ColorSelector" Visible="False" />
<LineEdit Name="Search" Margin="0 0 0 8" PlaceHolder="{Loc 'crayon-window-placeholder'}" /> <LineEdit Name="Search" />
<ScrollContainer VerticalExpand="True"> <ScrollContainer VerticalExpand="True">
<BoxContainer Name="Grids" Orientation="Vertical"> <GridContainer Name="Grid" Columns="6">
</BoxContainer> <!-- Crayon decals get added here by code -->
</GridContainer>
</ScrollContainer> </ScrollContainer>
</BoxContainer> </BoxContainer>
</DefaultWindow> </DefaultWindow>

View File

@@ -1,10 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Shared.Crayon; using Content.Shared.Crayon;
using Content.Shared.Decals; using Content.Shared.Decals;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
@@ -20,12 +18,7 @@ namespace Content.Client.Crayon.UI
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class CrayonWindow : DefaultWindow public sealed partial class CrayonWindow : DefaultWindow
{ {
[Dependency] private readonly IEntitySystemManager _entitySystem = default!; private Dictionary<string, Texture>? _decals;
private readonly SpriteSystem _spriteSystem = default!;
private Dictionary<string, List<(string Name, Texture Texture)>>? _decals;
private List<string>? _allDecals;
private string? _autoSelected;
private string? _selected; private string? _selected;
private Color _color; private Color _color;
@@ -35,10 +28,8 @@ namespace Content.Client.Crayon.UI
public CrayonWindow() public CrayonWindow()
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
Search.OnTextChanged += SearchChanged; Search.OnTextChanged += _ => RefreshList();
ColorSelector.OnColorChanged += SelectColor; ColorSelector.OnColorChanged += SelectColor;
} }
@@ -53,94 +44,51 @@ namespace Content.Client.Crayon.UI
private void RefreshList() private void RefreshList()
{ {
// Clear // Clear
Grids.DisposeAllChildren(); Grid.DisposeAllChildren();
if (_decals == null)
if (_decals == null || _allDecals == null)
return; return;
var filter = Search.Text; var filter = Search.Text;
var comma = filter.IndexOf(','); foreach (var (decal, tex) in _decals)
var first = (comma == -1 ? filter : filter[..comma]).Trim();
var names = _decals.Keys.ToList();
names.Sort((a, b) => a == "random" ? 1 : b == "random" ? -1 : a.CompareTo(b));
if (_autoSelected != null && first != _autoSelected && _allDecals.Contains(first))
{ {
_selected = first; if (!decal.Contains(filter))
_autoSelected = _selected;
OnSelected?.Invoke(_selected);
}
foreach (var categoryName in names)
{
var locName = Loc.GetString("crayon-category-" + categoryName);
var category = _decals[categoryName].Where(d => locName.Contains(first) || d.Name.Contains(first)).ToList();
if (category.Count == 0)
continue; continue;
var label = new Label var button = new TextureButton()
{ {
Text = locName TextureNormal = tex,
Name = decal,
ToolTip = decal,
Modulate = _color,
}; };
button.OnPressed += ButtonOnPressed;
var grid = new GridContainer if (_selected == decal)
{ {
Columns = 6, var panelContainer = new PanelContainer()
Margin = new Thickness(0, 0, 0, 16)
};
Grids.AddChild(label);
Grids.AddChild(grid);
foreach (var (name, texture) in category)
{
var button = new TextureButton()
{ {
TextureNormal = texture, PanelOverride = new StyleBoxFlat()
Name = name,
ToolTip = name,
Modulate = _color,
Scale = new System.Numerics.Vector2(2, 2)
};
button.OnPressed += ButtonOnPressed;
if (_selected == name)
{
var panelContainer = new PanelContainer()
{ {
PanelOverride = new StyleBoxFlat() BackgroundColor = StyleNano.ButtonColorDefault,
{ },
BackgroundColor = StyleNano.ButtonColorDefault, Children =
}, {
Children = button,
{ },
button, };
}, Grid.AddChild(panelContainer);
}; }
grid.AddChild(panelContainer); else
} {
else Grid.AddChild(button);
{
grid.AddChild(button);
}
} }
} }
} }
private void SearchChanged(LineEdit.LineEditEventArgs obj)
{
_autoSelected = ""; // Placeholder to kick off the auto-select in refreshlist()
RefreshList();
}
private void ButtonOnPressed(ButtonEventArgs obj) private void ButtonOnPressed(ButtonEventArgs obj)
{ {
if (obj.Button.Name == null) return; if (obj.Button.Name == null) return;
_selected = obj.Button.Name; _selected = obj.Button.Name;
_autoSelected = null;
OnSelected?.Invoke(_selected); OnSelected?.Invoke(_selected);
RefreshList(); RefreshList();
} }
@@ -159,38 +107,12 @@ namespace Content.Client.Crayon.UI
RefreshList(); RefreshList();
} }
public void AdvanceState(string drawnDecal) public void Populate(IEnumerable<DecalPrototype> prototypes)
{ {
var filter = Search.Text; _decals = new Dictionary<string, Texture>();
if (!filter.Contains(',') || !filter.Contains(drawnDecal))
return;
var first = filter[..filter.IndexOf(',')].Trim();
if (first.Equals(drawnDecal, StringComparison.InvariantCultureIgnoreCase))
{
Search.Text = filter[(filter.IndexOf(',') + 1)..].Trim();
_autoSelected = first;
}
RefreshList();
}
public void Populate(List<DecalPrototype> prototypes)
{
_decals = [];
_allDecals = [];
prototypes.Sort((a, b) => a.ID.CompareTo(b.ID));
foreach (var decalPrototype in prototypes) foreach (var decalPrototype in prototypes)
{ {
var category = "random"; _decals.Add(decalPrototype.ID, decalPrototype.Sprite.Frame0());
if (decalPrototype.Tags.Count > 1 && decalPrototype.Tags[1].StartsWith("crayon-"))
category = decalPrototype.Tags[1].Replace("crayon-", "");
var list = _decals.GetOrNew(category);
list.Add((decalPrototype.ID, _spriteSystem.Frame0(decalPrototype.Sprite)));
_allDecals.Add(decalPrototype.ID);
} }
RefreshList(); RefreshList();

View File

@@ -124,10 +124,6 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
continue; continue;
} }
var targetEv = new GetFlashEffectTargetEvent(ent);
RaiseLocalEvent(ent, ref targetEv);
ent = targetEv.Target;
EnsureComp<ColorFlashEffectComponent>(ent, out comp); EnsureComp<ColorFlashEffectComponent>(ent, out comp);
comp.NetSyncEnabled = false; comp.NetSyncEnabled = false;
comp.Color = sprite.Color; comp.Color = sprite.Color;
@@ -136,9 +132,3 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
} }
} }
} }
/// <summary>
/// Raised on an entity to change the target for a color flash effect.
/// </summary>
[ByRefEvent]
public record struct GetFlashEffectTargetEvent(EntityUid Target);

View File

@@ -165,7 +165,7 @@ namespace Content.Client.Entry
_clientPreferencesManager.Initialize(); _clientPreferencesManager.Initialize();
_euiManager.Initialize(); _euiManager.Initialize();
_voteManager.Initialize(); _voteManager.Initialize();
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme"); _userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme)); _userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
_documentParsingManager.Initialize(); _documentParsingManager.Initialize();
_titleWindowManager.Initialize(); _titleWindowManager.Initialize();

View File

@@ -168,8 +168,8 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
var parent = forcedRoot == null ? null : AddEntry(forcedRoot.Value, null, addedEntries); var parent = forcedRoot == null ? null : AddEntry(forcedRoot.Value, null, addedEntries);
foreach (var entry in GetSortedEntries(roots)) foreach (var entry in GetSortedEntries(roots))
{ {
if (!entry.CrystallPunkAllowed) continue; //CrystallEdge guidebook filter if (!entry.CrystallPunkAllowed) continue; //CrystallPunk guidebook filter
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallEdge guidebook filter if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallPunk guidebook filter
AddEntry(entry.Id, parent, addedEntries); AddEntry(entry.Id, parent, addedEntries);
} }

View File

@@ -32,7 +32,7 @@ public sealed class GuidebookSystem : EntitySystem
[Dependency] private readonly RgbLightControllerSystem _rgbLightControllerSystem = default!; [Dependency] private readonly RgbLightControllerSystem _rgbLightControllerSystem = default!;
[Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!; [Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!;
[Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly TagSystem _tags = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallEdge guidebook filter [Dependency] private readonly IPrototypeManager _proto = default!; //CrystallPunk guidebook filter
public event Action<List<ProtoId<GuideEntryPrototype>>, public event Action<List<ProtoId<GuideEntryPrototype>>,
List<ProtoId<GuideEntryPrototype>>?, List<ProtoId<GuideEntryPrototype>>?,
@@ -47,7 +47,7 @@ public sealed class GuidebookSystem : EntitySystem
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallEdgeMapInit); //CrystallEdge guidebook filter SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallPunkMapInit); //CrystallPunk guidebook filter
SubscribeLocalEvent<GuideHelpComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerbs); SubscribeLocalEvent<GuideHelpComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerbs);
SubscribeLocalEvent<GuideHelpComponent, ActivateInWorldEvent>(OnInteract); SubscribeLocalEvent<GuideHelpComponent, ActivateInWorldEvent>(OnInteract);
@@ -57,12 +57,12 @@ public sealed class GuidebookSystem : EntitySystem
OnGuidebookControlsTestGetAlternateVerbs); OnGuidebookControlsTestGetAlternateVerbs);
} }
//CrystallEdge guidebook filter //CrystallPunk guidebook filter
private void OnCrystallEdgeMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args) private void OnCrystallPunkMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
{ {
foreach (var guide in ent.Comp.Guides) foreach (var guide in ent.Comp.Guides)
{ {
var guideProto = _proto.Index(guide); var guideProto = _proto.Index<GuideEntryPrototype>(guide);
if (!guideProto.CrystallPunkAllowed) //REMOVE unnecessary guidebook if (!guideProto.CrystallPunkAllowed) //REMOVE unnecessary guidebook
{ {
RemComp<GuideHelpComponent>(ent); RemComp<GuideHelpComponent>(ent);
@@ -70,7 +70,7 @@ public sealed class GuidebookSystem : EntitySystem
} }
} }
} }
//CrystallEdge guidebook filter end //CrystallPunk guidebook filter end
/// <summary> /// <summary>
/// Gets a user entity to use for verbs and examinations. If the player has no attached entity, this will use a /// Gets a user entity to use for verbs and examinations. If the player has no attached entity, this will use a

View File

@@ -34,7 +34,6 @@ namespace Content.Client.Info
AddInfoButton("server-info-website-button", CCVars.InfoLinksWebsite); AddInfoButton("server-info-website-button", CCVars.InfoLinksWebsite);
AddInfoButton("server-info-wiki-button", CCVars.InfoLinksWiki); AddInfoButton("server-info-wiki-button", CCVars.InfoLinksWiki);
AddInfoButton("server-info-forum-button", CCVars.InfoLinksForum); AddInfoButton("server-info-forum-button", CCVars.InfoLinksForum);
AddInfoButton("server-info-telegram-button", CCVars.InfoLinksTelegram);
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>(); var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
var guidebookButton = new Button() { Text = Loc.GetString("server-info-guidebook-button") }; var guidebookButton = new Button() { Text = Loc.GetString("server-info-guidebook-button") };

View File

@@ -235,23 +235,9 @@ namespace Content.Client.Inventory
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true)); EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
} }
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
base.UpdateInventoryTemplate(ent);
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
{
foreach (var slot in ent.Comp.Slots)
{
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
slotData.SlotDef = slot;
}
}
}
public sealed class SlotData public sealed class SlotData
{ {
public SlotDefinition SlotDef; public readonly SlotDefinition SlotDef;
public EntityUid? HeldEntity => Container?.ContainedEntity; public EntityUid? HeldEntity => Container?.ContainedEntity;
public bool Blocked; public bool Blocked;
public bool Highlighted; public bool Highlighted;

View File

@@ -17,7 +17,6 @@ using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Strip.Components; using Content.Shared.Strip.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input; using Robust.Shared.Input;
@@ -30,13 +29,10 @@ namespace Content.Client.Inventory
[UsedImplicitly] [UsedImplicitly]
public sealed class StrippableBoundUserInterface : BoundUserInterface public sealed class StrippableBoundUserInterface : BoundUserInterface
{ {
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!; [Dependency] private readonly IUserInterfaceManager _ui = default!;
private readonly ExamineSystem _examine; private readonly ExamineSystem _examine;
private readonly InventorySystem _inv; private readonly InventorySystem _inv;
private readonly SharedCuffableSystem _cuffable; private readonly SharedCuffableSystem _cuffable;
private readonly StrippableSystem _strippable;
[ViewVariables] [ViewVariables]
private const int ButtonSeparation = 4; private const int ButtonSeparation = 4;
@@ -55,8 +51,6 @@ namespace Content.Client.Inventory
_examine = EntMan.System<ExamineSystem>(); _examine = EntMan.System<ExamineSystem>();
_inv = EntMan.System<InventorySystem>(); _inv = EntMan.System<InventorySystem>();
_cuffable = EntMan.System<SharedCuffableSystem>(); _cuffable = EntMan.System<SharedCuffableSystem>();
_strippable = EntMan.System<StrippableSystem>();
_virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace); _virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace);
} }
@@ -204,8 +198,7 @@ namespace Content.Client.Inventory
var entity = container.ContainedEntity; var entity = container.ContainedEntity;
// If this is a full pocket, obscure the real entity // If this is a full pocket, obscure the real entity
// this does not work for modified clients because they are still sent the real entity if (entity != null && slotDef.StripHidden)
if (entity != null && _strippable.IsStripHidden(slotDef, _player.LocalEntity))
entity = _virtualHiddenEntity; entity = _virtualHiddenEntity;
var button = new SlotButton(new SlotData(slotDef, container)); var button = new SlotButton(new SlotData(slotDef, container));

View File

@@ -279,7 +279,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
_profileEditor.OnOpenGuidebook += _guide.OpenHelp; _profileEditor.OnOpenGuidebook += _guide.OpenHelp;
_characterSetup = new CharacterSetupGui(_profileEditor); _characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
_characterSetup.CloseButton.OnPressed += _ => _characterSetup.CloseButton.OnPressed += _ =>
{ {

View File

@@ -2,7 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client" xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:style="clr-namespace:Content.Client.Stylesheets" xmlns:style="clr-namespace:Content.Client.Stylesheets"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
VerticalExpand="True"> VerticalExpand="True">
<Control> <Control>
<PanelContainer Name="BackgroundPanel" /> <PanelContainer Name="BackgroundPanel" />
@@ -11,15 +10,10 @@
<Label Text="{Loc 'character-setup-gui-character-setup-label'}" <Label Text="{Loc 'character-setup-gui-character-setup-label'}"
Margin="8 0 0 0" VAlign="Center" Margin="8 0 0 0" VAlign="Center"
StyleClasses="LabelHeadingBigger" /> StyleClasses="LabelHeadingBigger" />
<Button Name="StatsButton" HorizontalExpand="True" <Button Name="StatsButton" HorizontalExpand="True"
Text="{Loc 'character-setup-gui-character-setup-stats-button'}" Text="{Loc 'character-setup-gui-character-setup-stats-button'}"
StyleClasses="ButtonBig" StyleClasses="ButtonBig"
HorizontalAlignment="Right" /> HorizontalAlignment="Right" />
<cc:CommandButton Name="AdminRemarksButton"
Command="adminremarks"
Text="{Loc 'character-setup-gui-character-setup-adminremarks-button'}"
StyleClasses="ButtonBig" />
<Button Name="RulesButton" <Button Name="RulesButton"
Text="{Loc 'character-setup-gui-character-setup-rules-button'}" Text="{Loc 'character-setup-gui-character-setup-rules-button'}"
StyleClasses="ButtonBig"/> StyleClasses="ButtonBig"/>

View File

@@ -1,7 +1,6 @@
using Content.Client.Info; using Content.Client.Info;
using Content.Client.Info.PlaytimeStats; using Content.Client.Info.PlaytimeStats;
using Content.Client.Resources; using Content.Client.Resources;
using Content.Shared.CCVar;
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Graphics; using Robust.Client.Graphics;
@@ -9,7 +8,6 @@ using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI namespace Content.Client.Lobby.UI
@@ -20,23 +18,28 @@ namespace Content.Client.Lobby.UI
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class CharacterSetupGui : Control public sealed partial class CharacterSetupGui : Control
{ {
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!; private readonly IClientPreferencesManager _preferencesManager;
[Dependency] private readonly IEntityManager _entManager = default!; private readonly IEntityManager _entManager;
[Dependency] private readonly IPrototypeManager _protomanager = default!; private readonly IPrototypeManager _protomanager;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private readonly Button _createNewCharacterButton; private readonly Button _createNewCharacterButton;
public event Action<int>? SelectCharacter; public event Action<int>? SelectCharacter;
public event Action<int>? DeleteCharacter; public event Action<int>? DeleteCharacter;
public CharacterSetupGui(HumanoidProfileEditor profileEditor) public CharacterSetupGui(
IEntityManager entManager,
IPrototypeManager protoManager,
IResourceCache resourceCache,
IClientPreferencesManager preferencesManager,
HumanoidProfileEditor profileEditor)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this); _preferencesManager = preferencesManager;
_entManager = entManager;
_protomanager = protoManager;
var panelTex = _resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var back = new StyleBoxTexture var back = new StyleBoxTexture
{ {
Texture = panelTex, Texture = panelTex,
@@ -53,7 +56,7 @@ namespace Content.Client.Lobby.UI
_createNewCharacterButton.OnPressed += args => _createNewCharacterButton.OnPressed += args =>
{ {
_preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random()); preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
ReloadCharacterPickers(); ReloadCharacterPickers();
args.Event.Handle(); args.Event.Handle();
}; };
@@ -62,8 +65,6 @@ namespace Content.Client.Lobby.UI
RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open(); RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open();
StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered(); StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered();
_cfg.OnValueChanged(CCVars.SeeOwnNotes, p => AdminRemarksButton.Visible = p, true);
} }
/// <summary> /// <summary>

View File

@@ -36,18 +36,17 @@ public sealed partial class LoadoutContainer : BoxContainer
if (_protoManager.TryIndex(proto, out var loadProto)) if (_protoManager.TryIndex(proto, out var loadProto))
{ {
var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto); var ent = _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
if (ent == null) if (ent != null)
return; {
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
Sprite.SetEntity(_entity);
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace); var spriteTooltip = new Tooltip();
Sprite.SetEntity(_entity); spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
TooltipSupplier = _ => spriteTooltip;
var spriteTooltip = new Tooltip(); }
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
TooltipSupplier = _ => spriteTooltip;
} }
} }

View File

@@ -2,6 +2,7 @@ using Content.Client.Message;
using Content.Client.UserInterface.Systems.EscapeMenu; using Content.Client.UserInterface.Systems.EscapeMenu;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Console; using Robust.Client.Console;
using Robust.Client.State;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;

View File

@@ -14,7 +14,6 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
{ {
[Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPlayerManager _player = default!;
[ViewVariables]
protected bool IsActive; protected bool IsActive;
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET; protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;
@@ -103,7 +102,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
args.Components.Add(component); args.Components.Add(component);
} }
protected void RefreshOverlay(EntityUid uid) private void RefreshOverlay(EntityUid uid)
{ {
if (uid != _player.LocalSession?.AttachedEntity) if (uid != _player.LocalSession?.AttachedEntity)
return; return;

View File

@@ -21,16 +21,9 @@ public sealed class ShowHealthBarsSystem : EquipmentHudSystem<ShowHealthBarsComp
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<ShowHealthBarsComponent, AfterAutoHandleStateEvent>(OnHandleState);
_overlay = new(EntityManager, _prototype); _overlay = new(EntityManager, _prototype);
} }
private void OnHandleState(Entity<ShowHealthBarsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component) protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component)
{ {
base.UpdateInternal(component); base.UpdateInternal(component);

View File

@@ -17,7 +17,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
{ {
[Dependency] private readonly IPrototypeManager _prototypeMan = default!; [Dependency] private readonly IPrototypeManager _prototypeMan = default!;
[ViewVariables]
public HashSet<string> DamageContainers = new(); public HashSet<string> DamageContainers = new();
public override void Initialize() public override void Initialize()
@@ -25,7 +24,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
base.Initialize(); base.Initialize();
SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent); SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
SubscribeLocalEvent<ShowHealthIconsComponent, AfterAutoHandleStateEvent>(OnHandleState);
} }
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component) protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
@@ -45,11 +43,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
DamageContainers.Clear(); DamageContainers.Clear();
} }
private void OnHandleState(Entity<ShowHealthIconsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args) private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
{ {
if (!IsActive) if (!IsActive)

View File

@@ -1,12 +1,9 @@
using Content.Shared.Alert;
using Content.Shared.CCVar;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Physics; using Robust.Client.Physics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -17,8 +14,6 @@ public sealed class MoverController : SharedMoverController
{ {
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -140,15 +135,4 @@ public sealed class MoverController : SharedMoverController
{ {
return _timing is { IsFirstTimePredicted: true, InSimulation: true }; return _timing is { IsFirstTimePredicted: true, InSimulation: true };
} }
public override void SetSprinting(Entity<InputMoverComponent> entity, ushort subTick, bool walking)
{
// Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}");
base.SetSprinting(entity, subTick, walking);
if (walking && _cfg.GetCVar(CCVars.ToggleWalk))
_alerts.ShowAlert(entity, WalkingAlert, showCooldown: false, autoRemove: false);
else
_alerts.ClearAlert(entity, WalkingAlert);
}
} }

View File

@@ -1,10 +1,7 @@
using Content.Client.Effects;
using Content.Client.Smoking;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Content.Shared.Polymorph.Components; using Content.Shared.Polymorph.Components;
using Content.Shared.Polymorph.Systems; using Content.Shared.Polymorph.Systems;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Player;
namespace Content.Client.Polymorph.Systems; namespace Content.Client.Polymorph.Systems;
@@ -13,20 +10,14 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
private EntityQuery<AppearanceComponent> _appearanceQuery; private EntityQuery<AppearanceComponent> _appearanceQuery;
private EntityQuery<SpriteComponent> _spriteQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_appearanceQuery = GetEntityQuery<AppearanceComponent>(); _appearanceQuery = GetEntityQuery<AppearanceComponent>();
_spriteQuery = GetEntityQuery<SpriteComponent>();
SubscribeLocalEvent<ChameleonDisguiseComponent, AfterAutoHandleStateEvent>(OnHandleState); SubscribeLocalEvent<ChameleonDisguiseComponent, AfterAutoHandleStateEvent>(OnHandleState);
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ChameleonDisguisedComponent, GetFlashEffectTargetEvent>(OnGetFlashEffectTargetEvent);
} }
private void OnHandleState(Entity<ChameleonDisguiseComponent> ent, ref AfterAutoHandleStateEvent args) private void OnHandleState(Entity<ChameleonDisguiseComponent> ent, ref AfterAutoHandleStateEvent args)
@@ -34,30 +25,9 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
CopyComp<SpriteComponent>(ent); CopyComp<SpriteComponent>(ent);
CopyComp<GenericVisualizerComponent>(ent); CopyComp<GenericVisualizerComponent>(ent);
CopyComp<SolutionContainerVisualsComponent>(ent); CopyComp<SolutionContainerVisualsComponent>(ent);
CopyComp<BurnStateVisualsComponent>(ent);
// reload appearance to hopefully prevent any invisible layers // reload appearance to hopefully prevent any invisible layers
if (_appearanceQuery.TryComp(ent, out var appearance)) if (_appearanceQuery.TryComp(ent, out var appearance))
_appearance.QueueUpdate(ent, appearance); _appearance.QueueUpdate(ent, appearance);
} }
private void OnStartup(Entity<ChameleonDisguisedComponent> ent, ref ComponentStartup args)
{
if (!_spriteQuery.TryComp(ent, out var sprite))
return;
ent.Comp.WasVisible = sprite.Visible;
sprite.Visible = false;
}
private void OnShutdown(Entity<ChameleonDisguisedComponent> ent, ref ComponentShutdown args)
{
if (_spriteQuery.TryComp(ent, out var sprite))
sprite.Visible = ent.Comp.WasVisible;
}
private void OnGetFlashEffectTargetEvent(Entity<ChameleonDisguisedComponent> ent, ref GetFlashEffectTargetEvent args)
{
args.Target = ent.Comp.Disguise;
}
} }

View File

@@ -131,8 +131,7 @@ public sealed partial class BorgMenu : FancyWindow
_modules.Clear(); _modules.Clear();
foreach (var module in chassis.ModuleContainer.ContainedEntities) foreach (var module in chassis.ModuleContainer.ContainedEntities)
{ {
var moduleComponent = _entity.GetComponent<BorgModuleComponent>(module); var control = new BorgModuleControl(module, _entity);
var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule);
control.RemoveButtonPressed += () => control.RemoveButtonPressed += () =>
{ {
RemoveModuleButtonPressed?.Invoke(module); RemoveModuleButtonPressed?.Invoke(module);

View File

@@ -9,7 +9,7 @@ public sealed partial class BorgModuleControl : PanelContainer
{ {
public Action? RemoveButtonPressed; public Action? RemoveButtonPressed;
public BorgModuleControl(EntityUid entity, IEntityManager entityManager, bool canRemove) public BorgModuleControl(EntityUid entity, IEntityManager entityManager)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
@@ -20,7 +20,6 @@ public sealed partial class BorgModuleControl : PanelContainer
{ {
RemoveButtonPressed?.Invoke(); RemoveButtonPressed?.Invoke();
}; };
RemoveButton.Visible = canRemove;
} }
} }

View File

@@ -1,43 +0,0 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc 'borg-select-type-menu-title'}"
SetSize="550 300">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
<!-- Left pane: selection of borg type -->
<BoxContainer Orientation="Vertical" MinWidth="200" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-available'}" StyleClasses="LabelHeading" />
<ScrollContainer HScrollEnabled="False" VerticalExpand="True">
<BoxContainer Name="SelectionsContainer" Orientation="Vertical" />
</ScrollContainer>
</BoxContainer>
<customControls:VSeparator />
<!-- Right pane: information about selected borg module, confirm button. -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-information'}" StyleClasses="LabelHeading" />
<Control VerticalExpand="True">
<controls:Placeholder Name="InfoPlaceholder" PlaceholderText="{Loc 'borg-select-type-menu-select-type'}" />
<BoxContainer Name="InfoContents" Orientation="Vertical" Visible="False">
<BoxContainer Orientation="Horizontal" Margin="0 0 0 4">
<EntityPrototypeView Name="ChassisView" Scale="2,2" />
<Label Name="NameLabel" HorizontalExpand="True" />
</BoxContainer>
<RichTextLabel Name="DescriptionLabel" VerticalExpand="True" VerticalAlignment="Top" />
</BoxContainer>
</Control>
<controls:ConfirmButton Name="ConfirmTypeButton" Text="{Loc 'borg-select-type-menu-confirm'}"
Disabled="True" HorizontalAlignment="Right"
MinWidth="200" />
</BoxContainer>
</BoxContainer>
<controls:StripeBack Margin="0 0 0 4">
<Label Text="{Loc 'borg-select-type-menu-bottom-text'}" HorizontalAlignment="Center" StyleClasses="LabelSubText" Margin="4 4 0 4"/>
</controls:StripeBack>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -1,81 +0,0 @@
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared.Guidebook;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Menu used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeUserInterface"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
[GenerateTypedNameReferences]
public sealed partial class BorgSelectTypeMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private BorgTypePrototype? _selectedBorgType;
public event Action<ProtoId<BorgTypePrototype>>? ConfirmedBorgType;
[ValidatePrototypeId<GuideEntryPrototype>]
private static readonly List<ProtoId<GuideEntryPrototype>> GuidebookEntries = new() { "Cyborgs", "Robotics" };
public BorgSelectTypeMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var group = new ButtonGroup();
foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
{
var button = new Button
{
Text = PrototypeName(borgType),
Group = group,
};
button.OnPressed += _ =>
{
_selectedBorgType = borgType;
UpdateInformation(borgType);
};
SelectionsContainer.AddChild(button);
}
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
HelpGuidebookIds = GuidebookEntries;
}
private void UpdateInformation(BorgTypePrototype prototype)
{
_selectedBorgType = prototype;
InfoContents.Visible = true;
InfoPlaceholder.Visible = false;
ConfirmTypeButton.Disabled = false;
NameLabel.Text = PrototypeName(prototype);
DescriptionLabel.Text = Loc.GetString($"borg-type-{prototype.ID}-desc");
ChassisView.SetPrototype(prototype.DummyPrototype);
}
private void ConfirmButtonPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedBorgType == null)
return;
ConfirmedBorgType?.Invoke(_selectedBorgType);
}
private static string PrototypeName(BorgTypePrototype prototype)
{
return Loc.GetString($"borg-type-{prototype.ID}-name");
}
}

View File

@@ -1,30 +0,0 @@
using Content.Shared.Silicons.Borgs.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// User interface used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeMenu"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
/// <seealso cref="BorgSwitchableTypeUiKey"/>
[UsedImplicitly]
public sealed class BorgSelectTypeUserInterface : BoundUserInterface
{
[ViewVariables]
private BorgSelectTypeMenu? _menu;
public BorgSelectTypeUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = this.CreateWindow<BorgSelectTypeMenu>();
_menu.ConfirmedBorgType += prototype => SendMessage(new BorgSelectTypeMessage(prototype));
}
}

View File

@@ -1,81 +0,0 @@
using Content.Shared.Movement.Components;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Client side logic for borg type switching. Sets up primarily client-side visual information.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
{
[Dependency] private readonly BorgSystem _borgSystem = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BorgSwitchableTypeComponent, AfterAutoHandleStateEvent>(AfterStateHandler);
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentStartup>(OnComponentStartup);
}
private void OnComponentStartup(Entity<BorgSwitchableTypeComponent> ent, ref ComponentStartup args)
{
UpdateEntityAppearance(ent);
}
private void AfterStateHandler(Entity<BorgSwitchableTypeComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateEntityAppearance(ent);
}
protected override void UpdateEntityAppearance(
Entity<BorgSwitchableTypeComponent> entity,
BorgTypePrototype prototype)
{
if (TryComp(entity, out SpriteComponent? sprite))
{
sprite.LayerSetState(BorgVisualLayers.Body, prototype.SpriteBodyState);
sprite.LayerSetState(BorgVisualLayers.LightStatus, prototype.SpriteToggleLightState);
}
if (TryComp(entity, out BorgChassisComponent? chassis))
{
_borgSystem.SetMindStates(
(entity.Owner, chassis),
prototype.SpriteHasMindState,
prototype.SpriteNoMindState);
if (TryComp(entity, out AppearanceComponent? appearance))
{
// Queue update so state changes apply.
_appearance.QueueUpdate(entity, appearance);
}
}
if (prototype.SpriteBodyMovementState is { } movementState)
{
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
spriteMovement.NoMovementLayers.Clear();
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
{
State = prototype.SpriteBodyState,
};
spriteMovement.MovementLayers.Clear();
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
{
State = movementState,
};
}
else
{
RemComp<SpriteMovementComponent>(entity);
}
base.UpdateEntityAppearance(entity, prototype);
}
}

View File

@@ -92,18 +92,4 @@ public sealed class BorgSystem : SharedBorgSystem
sprite.LayerSetState(MMIVisualLayers.Base, state); sprite.LayerSetState(MMIVisualLayers.Base, state);
} }
} }
/// <summary>
/// Sets the sprite states used for the borg "is there a mind or not" indication.
/// </summary>
/// <param name="borg">The entity and component to modify.</param>
/// <param name="hasMindState">The state to use if the borg has a mind.</param>
/// <param name="noMindState">The state to use if the borg has no mind.</param>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
public void SetMindStates(Entity<BorgChassisComponent> borg, string hasMindState, string noMindState)
{
borg.Comp.HasMindState = hasMindState;
borg.Comp.NoMindState = noMindState;
}
} }

View File

@@ -1,7 +1,7 @@
using Content.Shared.Singularity.EntitySystems; using Content.Shared.Singularity.EntitySystems;
using Content.Shared.Singularity.Components; using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Systems; namespace Content.Client.Singularity.EntitySystems;
/// <summary> /// <summary>
/// The client-side version of <see cref="SharedEventHorizonSystem"/>. /// The client-side version of <see cref="SharedEventHorizonSystem"/>.

View File

@@ -1,12 +0,0 @@
using Content.Shared.Singularity.EntitySystems;
using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Systems;
/// <summary>
/// The client-side version of <see cref="SharedSingularityGeneratorSystem"/>.
/// Manages <see cref="SingularityGeneratorComponent"/>s.
/// Exists to make relevant signal handlers (ie: <see cref="SharedSingularityGeneratorSystem.OnEmagged"/>) work on the client.
/// </summary>
public sealed class SingularityGeneratorSystem : SharedSingularityGeneratorSystem
{}

View File

@@ -5,7 +5,7 @@ using Robust.Client.GameObjects;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Client.Singularity.Systems; namespace Content.Client.Singularity.EntitySystems;
/// <summary> /// <summary>
/// The client-side version of <see cref="SharedSingularitySystem"/>. /// The client-side version of <see cref="SharedSingularitySystem"/>.

View File

@@ -307,6 +307,12 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
_entity.GetNetEntity(storageEnt), _entity.GetNetEntity(storageEnt),
new ItemStorageLocation(DraggingRotation, position))); new ItemStorageLocation(DraggingRotation, position)));
} }
else
{
_entity.RaisePredictiveEvent(new StorageRemoveItemEvent(
_entity.GetNetEntity(draggingGhost.Entity),
_entity.GetNetEntity(storageEnt)));
}
_menuDragHelper.EndDrag(); _menuDragHelper.EndDrag();
_container?.BuildItemPieces(); _container?.BuildItemPieces();

View File

@@ -20,7 +20,7 @@ public enum WeaponArcAnimation : byte
None, None,
Thrust, Thrust,
Slash, Slash,
//CrystallEdge Melee upgrade //CrystallPunk Melee upgrade
CPSlash, CPSlash,
CPThrust CPThrust
} }

View File

@@ -43,8 +43,8 @@ public sealed partial class MeleeWeaponSystem
return; return;
} }
var length = 1f; //CrystallEdgeMelee upgrade var length = 1f; //CrystallPunk Melee upgrade
var offset = -1f; //CrystallEdge Melee upgrade var offset = -1f; //CrystallPunk Melee upgrade
var spriteRotation = Angle.Zero; var spriteRotation = Angle.Zero;
if (arcComponent.Animation != WeaponArcAnimation.None if (arcComponent.Animation != WeaponArcAnimation.None
@@ -59,8 +59,8 @@ public sealed partial class MeleeWeaponSystem
if (meleeWeaponComponent.SwingLeft) if (meleeWeaponComponent.SwingLeft)
angle *= -1; angle *= -1;
length = meleeWeaponComponent.CPAnimationLength; //CrystallEdge Melee upgrade length = meleeWeaponComponent.CPAnimationLength; //CrystallPunk Melee upgrade
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallEdge Melee upgrade offset = meleeWeaponComponent.CPAnimationOffset; //CrystallPunk Melee upgrade
} }
sprite.Rotation = localPos.ToWorldAngle(); sprite.Rotation = localPos.ToWorldAngle();
var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f); var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
@@ -92,7 +92,7 @@ public sealed partial class MeleeWeaponSystem
if (arcComponent.Fadeout) if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey); _animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break; break;
//CrystallEdge MeleeUpgrade //CrystallPunk MeleeUpgrade
case WeaponArcAnimation.CPSlash: case WeaponArcAnimation.CPSlash:
track = EnsureComp<TrackUserComponent>(animationUid); track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user; track.User = user;
@@ -107,7 +107,7 @@ public sealed partial class MeleeWeaponSystem
if (arcComponent.Fadeout) if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey); _animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break; break;
//CrystallEdge MeleeUpgrade end //CrystallPunk MeleeUpgrade end
} }
} }
@@ -207,7 +207,7 @@ public sealed partial class MeleeWeaponSystem
/// </summary> /// </summary>
private Animation GetLungeAnimation(Vector2 direction) private Animation GetLungeAnimation(Vector2 direction)
{ {
const float length = 0.2f; // 0.1 original, CrystallEdge update const float length = 0.2f; // 0.1 original, CrystallPunk update
return new Animation return new Animation
{ {
@@ -221,9 +221,9 @@ public sealed partial class MeleeWeaponSystem
InterpolationMode = AnimationInterpolationMode.Linear, InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames = KeyFrames =
{ {
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallEdge MeleeUpgrade new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallEdge MeleeUpgrade new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallEdge MeleeUpgrade new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallPunk MeleeUpgrade
} }
} }
} }
@@ -253,7 +253,7 @@ public sealed partial class MeleeWeaponSystem
} }
} }
//CrystallEdge MeleeUpgrade start //CrystallPunk MeleeUpgrade start
private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f) private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f)
{ {
var startRotation = sprite.Rotation + (arc * 0.5f); var startRotation = sprite.Rotation + (arc * 0.5f);
@@ -324,6 +324,6 @@ public sealed partial class MeleeWeaponSystem
}; };
} }
//CrystallEdge MeleeUpgrade end //CrystallPunk MeleeUpgrade end
} }

View File

@@ -157,7 +157,7 @@ public sealed partial class GunSystem : SharedGunSystem
var useKey = gun.UseKey ? EngineKeyFunctions.Use : EngineKeyFunctions.UseSecondary; var useKey = gun.UseKey ? EngineKeyFunctions.Use : EngineKeyFunctions.UseSecondary;
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.BurstActivated) if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down)
{ {
if (gun.ShotCounter != 0) if (gun.ShotCounter != 0)
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) }); EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });

View File

@@ -1,7 +0,0 @@
using Content.Shared._CP14.Temperature;
namespace Content.Client._CP14.Temperature;
public sealed partial class CP14ClientFireSpreadSystem : CP14SharedFireSpreadSystem
{
}

View File

@@ -12,7 +12,6 @@ namespace Content.IntegrationTests.Tests.Access
[TestOf(typeof(AccessReaderComponent))] [TestOf(typeof(AccessReaderComponent))]
public sealed class AccessReaderTest public sealed class AccessReaderTest
{ {
/*
[Test] [Test]
public async Task TestProtoTags() public async Task TestProtoTags()
{ {
@@ -124,6 +123,6 @@ namespace Content.IntegrationTests.Tests.Access
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
} }
*/
} }
} }

View File

@@ -6,7 +6,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture] [TestFixture]
[TestOf(typeof(AtmosAlarmThreshold))] [TestOf(typeof(AtmosAlarmThreshold))]
public sealed class AlarmThresholdTest public sealed class AlarmThresholdTest
{/* {
[TestPrototypes] [TestPrototypes]
private const string Prototypes = @" private const string Prototypes = @"
- type: alarmThreshold - type: alarmThreshold
@@ -135,6 +135,6 @@ namespace Content.IntegrationTests.Tests.Atmos
} }
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture] [TestFixture]
[TestOf(typeof(Atmospherics))] [TestOf(typeof(Atmospherics))]
public sealed class ConstantsTest public sealed class ConstantsTest
{/* {
[Test] [Test]
public async Task TotalGasesTest() public async Task TotalGasesTest()
{ {
@@ -27,6 +27,6 @@ namespace Content.IntegrationTests.Tests.Atmos
}); });
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture] [TestFixture]
[TestOf(typeof(GasMixture))] [TestOf(typeof(GasMixture))]
public sealed class GasMixtureTest public sealed class GasMixtureTest
{/* {
[Test] [Test]
public async Task TestMerge() public async Task TestMerge()
{ {
@@ -105,6 +105,6 @@ namespace Content.IntegrationTests.Tests.Atmos
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos;
[TestFixture] [TestFixture]
public sealed class GridJoinTest public sealed class GridJoinTest
{/* {
private const string CanisterProtoId = "AirCanister"; private const string CanisterProtoId = "AirCanister";
[Test] [Test]
@@ -49,5 +49,5 @@ public sealed class GridJoinTest
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }

View File

@@ -18,7 +18,7 @@ namespace Content.IntegrationTests.Tests;
[TestFixture] [TestFixture]
public sealed class CargoTest public sealed class CargoTest
{/* {
private static readonly HashSet<ProtoId<CargoProductPrototype>> Ignored = private static readonly HashSet<ProtoId<CargoProductPrototype>> Ignored =
[ [
// This is ignored because it is explicitly intended to be able to sell for more than it costs. // This is ignored because it is explicitly intended to be able to sell for more than it costs.
@@ -265,5 +265,5 @@ public sealed class CargoTest
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }

View File

@@ -32,9 +32,9 @@ namespace Content.IntegrationTests.Tests.Commands
// No bans on record // No bans on record
Assert.Multiple(async () => Assert.Multiple(async () =>
{ {
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Is.Empty); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Is.Empty);
}); });
// Try to pardon a ban that does not exist // Try to pardon a ban that does not exist
@@ -43,9 +43,9 @@ namespace Content.IntegrationTests.Tests.Commands
// Still no bans on record // Still no bans on record
Assert.Multiple(async () => Assert.Multiple(async () =>
{ {
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Is.Empty); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Is.Empty);
}); });
var banReason = "test"; var banReason = "test";
@@ -57,9 +57,9 @@ namespace Content.IntegrationTests.Tests.Commands
// Should have one ban on record now // Should have one ban on record now
Assert.Multiple(async () => Assert.Multiple(async () =>
{ {
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Not.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Not.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null); Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1)); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
}); });
await pair.RunTicksSync(5); await pair.RunTicksSync(5);
@@ -70,13 +70,13 @@ namespace Content.IntegrationTests.Tests.Commands
await server.WaitPost(() => sConsole.ExecuteCommand("pardon 2")); await server.WaitPost(() => sConsole.ExecuteCommand("pardon 2"));
// The existing ban is unaffected // The existing ban is unaffected
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Not.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Not.Null);
var ban = await sDatabase.GetServerBanAsync(1); var ban = await sDatabase.GetServerBanAsync(1);
Assert.Multiple(async () => Assert.Multiple(async () =>
{ {
Assert.That(ban, Is.Not.Null); Assert.That(ban, Is.Not.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1)); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
// Check that it matches // Check that it matches
Assert.That(ban.Id, Is.EqualTo(1)); Assert.That(ban.Id, Is.EqualTo(1));
@@ -95,7 +95,7 @@ namespace Content.IntegrationTests.Tests.Commands
await server.WaitPost(() => sConsole.ExecuteCommand("pardon 1")); await server.WaitPost(() => sConsole.ExecuteCommand("pardon 1"));
// No bans should be returned // No bans should be returned
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
// Direct id lookup returns a pardoned ban // Direct id lookup returns a pardoned ban
var pardonedBan = await sDatabase.GetServerBanAsync(1); var pardonedBan = await sDatabase.GetServerBanAsync(1);
@@ -105,7 +105,7 @@ namespace Content.IntegrationTests.Tests.Commands
Assert.That(pardonedBan, Is.Not.Null); Assert.That(pardonedBan, Is.Not.Null);
// The list is still returned since that ignores pardons // The list is still returned since that ignores pardons
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1)); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
Assert.That(pardonedBan.Id, Is.EqualTo(1)); Assert.That(pardonedBan.Id, Is.EqualTo(1));
Assert.That(pardonedBan.UserId, Is.EqualTo(clientId)); Assert.That(pardonedBan.UserId, Is.EqualTo(clientId));
@@ -133,13 +133,13 @@ namespace Content.IntegrationTests.Tests.Commands
Assert.Multiple(async () => Assert.Multiple(async () =>
{ {
// No bans should be returned // No bans should be returned
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null); Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
// Direct id lookup returns a pardoned ban // Direct id lookup returns a pardoned ban
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null); Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null);
// The list is still returned since that ignores pardons // The list is still returned since that ignores pardons
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1)); Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
}); });
// Reconnect client. Slightly faster than dirtying the pair. // Reconnect client. Slightly faster than dirtying the pair.

View File

@@ -18,7 +18,7 @@ namespace Content.IntegrationTests.Tests.Disposal
[TestOf(typeof(DisposalEntryComponent))] [TestOf(typeof(DisposalEntryComponent))]
[TestOf(typeof(DisposalUnitComponent))] [TestOf(typeof(DisposalUnitComponent))]
public sealed class DisposalUnitTest public sealed class DisposalUnitTest
{/* {
[Reflect(false)] [Reflect(false)]
private sealed class DisposalUnitTestSystem : EntitySystem private sealed class DisposalUnitTestSystem : EntitySystem
{ {
@@ -242,6 +242,6 @@ namespace Content.IntegrationTests.Tests.Disposal
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -6,7 +6,7 @@ using Content.Shared.Wires;
namespace Content.IntegrationTests.Tests.EncryptionKeys; namespace Content.IntegrationTests.Tests.EncryptionKeys;
public sealed class RemoveEncryptionKeys : InteractionTest public sealed class RemoveEncryptionKeys : InteractionTest
{/* {
[Test] [Test]
public async Task HeadsetKeys() public async Task HeadsetKeys()
{ {
@@ -108,5 +108,5 @@ public sealed class RemoveEncryptionKeys : InteractionTest
AssertPrototype("TelecomServerFilled"); AssertPrototype("TelecomServerFilled");
await InteractUsing(Pry); await InteractUsing(Pry);
AssertPrototype("MachineFrame"); AssertPrototype("MachineFrame");
}*/ }
} }

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Internals;
[TestFixture] [TestFixture]
[TestOf(typeof(InternalsSystem))] [TestOf(typeof(InternalsSystem))]
public sealed class AutoInternalsTests public sealed class AutoInternalsTests
{/* {
[Test] [Test]
public async Task TestInternalsAutoActivateInSpaceForStationSpawn() public async Task TestInternalsAutoActivateInSpaceForStationSpawn()
{ {
@@ -81,5 +81,5 @@ public sealed class AutoInternalsTests
components: components:
- type: Loadout - type: Loadout
prototypes: [InternalsDummyGear] prototypes: [InternalsDummyGear]
";*/ ";
} }

View File

@@ -8,7 +8,7 @@ using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests; namespace Content.IntegrationTests.Tests;
public sealed class MachineBoardTest public sealed class MachineBoardTest
{/* {
/// <summary> /// <summary>
/// A list of machine boards that can be ignored by this test. /// A list of machine boards that can be ignored by this test.
/// </summary> /// </summary>
@@ -138,5 +138,5 @@ public sealed class MachineBoardTest
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }

View File

@@ -7,7 +7,7 @@ using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests.Payload; namespace Content.IntegrationTests.Tests.Payload;
public sealed class ModularGrenadeTests : InteractionTest public sealed class ModularGrenadeTests : InteractionTest
{/* {
public const string Trigger = "TimerTrigger"; public const string Trigger = "TimerTrigger";
public const string Payload = "ExplosivePayload"; public const string Payload = "ExplosivePayload";
@@ -70,5 +70,5 @@ public sealed class ModularGrenadeTests : InteractionTest
// Grenade has exploded. // Grenade has exploded.
await RunTicks(30); await RunTicks(30);
AssertDeleted(); AssertDeleted();
}*/ }
} }

View File

@@ -44,15 +44,15 @@ namespace Content.IntegrationTests.Tests
}; };
private static readonly string[] GameMaps = private static readonly string[] GameMaps =
{//CrystallEdge Map replacement {//CrystallPunk Map replacement
"Dev", "Dev",
"CentComm", "CentComm",
"MeteorArena", "MeteorArena",
//CrystallEdge maps //CrystallPunk maps
"Village", "Village",
"Island", "Island",
//CrystallEdge Map replacement end //CrystallPunk Map replacement end
}; };
/// <summary> /// <summary>

View File

@@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Power
{ {
[TestFixture] [TestFixture]
public sealed class PowerTest public sealed class PowerTest
{/* {
[TestPrototypes] [TestPrototypes]
private const string Prototypes = @" private const string Prototypes = @"
- type: entity - type: entity
@@ -1333,7 +1333,7 @@ namespace Content.IntegrationTests.Tests.Power
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -9,7 +9,7 @@ namespace Content.IntegrationTests.Tests;
[TestFixture] [TestFixture]
public sealed class ResearchTest public sealed class ResearchTest
{/* {
[Test] [Test]
public async Task DisciplineValidTierPrerequesitesTest() public async Task DisciplineValidTierPrerequesitesTest()
{ {
@@ -117,5 +117,5 @@ public sealed class ResearchTest
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }

View File

@@ -19,7 +19,7 @@ namespace Content.IntegrationTests.Tests
[TestOf(typeof(VendingMachineRestockComponent))] [TestOf(typeof(VendingMachineRestockComponent))]
[TestOf(typeof(VendingMachineSystem))] [TestOf(typeof(VendingMachineSystem))]
public sealed class VendingMachineRestockTest : EntitySystem public sealed class VendingMachineRestockTest : EntitySystem
{/* {
[TestPrototypes] [TestPrototypes]
private const string Prototypes = @" private const string Prototypes = @"
- type: entity - type: entity
@@ -369,7 +369,7 @@ namespace Content.IntegrationTests.Tests
}); });
await pair.CleanReturnAsync(); await pair.CleanReturnAsync();
}*/ }
} }
} }

View File

@@ -1,62 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class ModernHwid : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "server_role_ban",
type: "integer",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "server_ban",
type: "integer",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "last_seen_hwid_type",
table: "player",
type: "integer",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "connection_log",
type: "integer",
nullable: true,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "hwid_type",
table: "server_role_ban");
migrationBuilder.DropColumn(
name: "hwid_type",
table: "server_ban");
migrationBuilder.DropColumn(
name: "last_seen_hwid_type",
table: "player");
migrationBuilder.DropColumn(
name: "hwid_type",
table: "connection_log");
}
}
}

View File

@@ -1,29 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class ConnectionTrust : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<float>(
name: "trust",
table: "connection_log",
type: "real",
nullable: false,
defaultValue: 0f);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "trust",
table: "connection_log");
}
}
}

View File

@@ -512,6 +512,20 @@ namespace Content.Server.Database.Migrations.Postgres
b.ToTable("assigned_user_id", (string)null); b.ToTable("assigned_user_id", (string)null);
}); });
modelBuilder.Entity("Content.Server.Database.Blacklist",
b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("UserId")
.HasName("PK_blacklist");
b.ToTable("blacklist", (string) null);
});
modelBuilder.Entity("Content.Server.Database.BanTemplate", b => modelBuilder.Entity("Content.Server.Database.BanTemplate", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -557,19 +571,6 @@ namespace Content.Server.Database.Migrations.Postgres
b.ToTable("ban_template", (string)null); b.ToTable("ban_template", (string)null);
}); });
modelBuilder.Entity("Content.Server.Database.Blacklist", b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("UserId")
.HasName("PK_blacklist");
b.ToTable("blacklist", (string)null);
});
modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -588,6 +589,10 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("smallint") .HasColumnType("smallint")
.HasColumnName("denied"); .HasColumnName("denied");
b.Property<byte[]>("HWId")
.HasColumnType("bytea")
.HasColumnName("hwid");
b.Property<int>("ServerId") b.Property<int>("ServerId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("integer") .HasColumnType("integer")
@@ -598,10 +603,6 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("time"); .HasColumnName("time");
b.Property<float>("Trust")
.HasColumnType("real")
.HasColumnName("trust");
b.Property<Guid>("UserId") b.Property<Guid>("UserId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("user_id"); .HasColumnName("user_id");
@@ -717,6 +718,10 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("inet") .HasColumnType("inet")
.HasColumnName("last_seen_address"); .HasColumnName("last_seen_address");
b.Property<byte[]>("LastSeenHWId")
.HasColumnType("bytea")
.HasColumnName("last_seen_hwid");
b.Property<DateTime>("LastSeenTime") b.Property<DateTime>("LastSeenTime")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("last_seen_time"); .HasColumnName("last_seen_time");
@@ -1053,6 +1058,10 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("expiration_time"); .HasColumnName("expiration_time");
b.Property<byte[]>("HWId")
.HasColumnType("bytea")
.HasColumnName("hwid");
b.Property<bool>("Hidden") b.Property<bool>("Hidden")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("hidden"); .HasColumnName("hidden");
@@ -1183,6 +1192,10 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("expiration_time"); .HasColumnName("expiration_time");
b.Property<byte[]>("HWId")
.HasColumnType("bytea")
.HasColumnName("hwid");
b.Property<bool>("Hidden") b.Property<bool>("Hidden")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("hidden"); .HasColumnName("hidden");
@@ -1624,34 +1637,6 @@ namespace Content.Server.Database.Migrations.Postgres
.IsRequired() .IsRequired()
.HasConstraintName("FK_connection_log_server_server_id"); .HasConstraintName("FK_connection_log_server_server_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ConnectionLogId")
.HasColumnType("integer")
.HasColumnName("connection_log_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("bytea")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ConnectionLogId");
b1.ToTable("connection_log");
b1.WithOwner()
.HasForeignKey("ConnectionLogId")
.HasConstraintName("FK_connection_log_connection_log_connection_log_id");
});
b.Navigation("HWId");
b.Navigation("Server"); b.Navigation("Server");
}); });
@@ -1667,37 +1652,6 @@ namespace Content.Server.Database.Migrations.Postgres
b.Navigation("Profile"); b.Navigation("Profile");
}); });
modelBuilder.Entity("Content.Server.Database.Player", b =>
{
b.OwnsOne("Content.Server.Database.TypedHwid", "LastSeenHWId", b1 =>
{
b1.Property<int>("PlayerId")
.HasColumnType("integer")
.HasColumnName("player_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("bytea")
.HasColumnName("last_seen_hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("last_seen_hwid_type");
b1.HasKey("PlayerId");
b1.ToTable("player");
b1.WithOwner()
.HasForeignKey("PlayerId")
.HasConstraintName("FK_player_player_player_id");
});
b.Navigation("LastSeenHWId");
});
modelBuilder.Entity("Content.Server.Database.Profile", b => modelBuilder.Entity("Content.Server.Database.Profile", b =>
{ {
b.HasOne("Content.Server.Database.Preference", "Preference") b.HasOne("Content.Server.Database.Preference", "Preference")
@@ -1792,36 +1746,8 @@ namespace Content.Server.Database.Migrations.Postgres
.HasForeignKey("RoundId") .HasForeignKey("RoundId")
.HasConstraintName("FK_server_ban_round_round_id"); .HasConstraintName("FK_server_ban_round_round_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ServerBanId")
.HasColumnType("integer")
.HasColumnName("server_ban_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("bytea")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ServerBanId");
b1.ToTable("server_ban");
b1.WithOwner()
.HasForeignKey("ServerBanId")
.HasConstraintName("FK_server_ban_server_ban_server_ban_id");
});
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");
b.Navigation("HWId");
b.Navigation("LastEditedBy"); b.Navigation("LastEditedBy");
b.Navigation("Round"); b.Navigation("Round");
@@ -1869,36 +1795,8 @@ namespace Content.Server.Database.Migrations.Postgres
.HasForeignKey("RoundId") .HasForeignKey("RoundId")
.HasConstraintName("FK_server_role_ban_round_round_id"); .HasConstraintName("FK_server_role_ban_round_round_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ServerRoleBanId")
.HasColumnType("integer")
.HasColumnName("server_role_ban_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("bytea")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ServerRoleBanId");
b1.ToTable("server_role_ban");
b1.WithOwner()
.HasForeignKey("ServerRoleBanId")
.HasConstraintName("FK_server_role_ban_server_role_ban_server_role_ban_id");
});
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");
b.Navigation("HWId");
b.Navigation("LastEditedBy"); b.Navigation("LastEditedBy");
b.Navigation("Round"); b.Navigation("Round");

View File

@@ -1,62 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class ModernHwid : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "server_role_ban",
type: "INTEGER",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "server_ban",
type: "INTEGER",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "last_seen_hwid_type",
table: "player",
type: "INTEGER",
nullable: true,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "hwid_type",
table: "connection_log",
type: "INTEGER",
nullable: true,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "hwid_type",
table: "server_role_ban");
migrationBuilder.DropColumn(
name: "hwid_type",
table: "server_ban");
migrationBuilder.DropColumn(
name: "last_seen_hwid_type",
table: "player");
migrationBuilder.DropColumn(
name: "hwid_type",
table: "connection_log");
}
}
}

View File

@@ -1,29 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class ConnectionTrust : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<float>(
name: "trust",
table: "connection_log",
type: "REAL",
nullable: false,
defaultValue: 0f);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "trust",
table: "connection_log");
}
}
}

View File

@@ -483,6 +483,19 @@ namespace Content.Server.Database.Migrations.Sqlite
b.ToTable("assigned_user_id", (string)null); b.ToTable("assigned_user_id", (string)null);
}); });
modelBuilder.Entity("Content.Server.Database.Blacklist",
b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("UserId")
.HasName("PK_blacklist");
b.ToTable("blacklist", (string) null);
});
modelBuilder.Entity("Content.Server.Database.BanTemplate", b => modelBuilder.Entity("Content.Server.Database.BanTemplate", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -526,19 +539,6 @@ namespace Content.Server.Database.Migrations.Sqlite
b.ToTable("ban_template", (string)null); b.ToTable("ban_template", (string)null);
}); });
modelBuilder.Entity("Content.Server.Database.Blacklist", b =>
{
b.Property<Guid>("UserId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("UserId")
.HasName("PK_blacklist");
b.ToTable("blacklist", (string)null);
});
modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -555,6 +555,10 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("INTEGER") .HasColumnType("INTEGER")
.HasColumnName("denied"); .HasColumnName("denied");
b.Property<byte[]>("HWId")
.HasColumnType("BLOB")
.HasColumnName("hwid");
b.Property<int>("ServerId") b.Property<int>("ServerId")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER") .HasColumnType("INTEGER")
@@ -565,10 +569,6 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("time"); .HasColumnName("time");
b.Property<float>("Trust")
.HasColumnType("REAL")
.HasColumnName("trust");
b.Property<Guid>("UserId") b.Property<Guid>("UserId")
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("user_id"); .HasColumnName("user_id");
@@ -675,6 +675,10 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("last_seen_address"); .HasColumnName("last_seen_address");
b.Property<byte[]>("LastSeenHWId")
.HasColumnType("BLOB")
.HasColumnName("last_seen_hwid");
b.Property<DateTime>("LastSeenTime") b.Property<DateTime>("LastSeenTime")
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("last_seen_time"); .HasColumnName("last_seen_time");
@@ -992,6 +996,10 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("expiration_time"); .HasColumnName("expiration_time");
b.Property<byte[]>("HWId")
.HasColumnType("BLOB")
.HasColumnName("hwid");
b.Property<bool>("Hidden") b.Property<bool>("Hidden")
.HasColumnType("INTEGER") .HasColumnType("INTEGER")
.HasColumnName("hidden"); .HasColumnName("hidden");
@@ -1116,6 +1124,10 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("expiration_time"); .HasColumnName("expiration_time");
b.Property<byte[]>("HWId")
.HasColumnType("BLOB")
.HasColumnName("hwid");
b.Property<bool>("Hidden") b.Property<bool>("Hidden")
.HasColumnType("INTEGER") .HasColumnType("INTEGER")
.HasColumnName("hidden"); .HasColumnName("hidden");
@@ -1547,34 +1559,6 @@ namespace Content.Server.Database.Migrations.Sqlite
.IsRequired() .IsRequired()
.HasConstraintName("FK_connection_log_server_server_id"); .HasConstraintName("FK_connection_log_server_server_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ConnectionLogId")
.HasColumnType("INTEGER")
.HasColumnName("connection_log_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("BLOB")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ConnectionLogId");
b1.ToTable("connection_log");
b1.WithOwner()
.HasForeignKey("ConnectionLogId")
.HasConstraintName("FK_connection_log_connection_log_connection_log_id");
});
b.Navigation("HWId");
b.Navigation("Server"); b.Navigation("Server");
}); });
@@ -1590,37 +1574,6 @@ namespace Content.Server.Database.Migrations.Sqlite
b.Navigation("Profile"); b.Navigation("Profile");
}); });
modelBuilder.Entity("Content.Server.Database.Player", b =>
{
b.OwnsOne("Content.Server.Database.TypedHwid", "LastSeenHWId", b1 =>
{
b1.Property<int>("PlayerId")
.HasColumnType("INTEGER")
.HasColumnName("player_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("BLOB")
.HasColumnName("last_seen_hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0)
.HasColumnName("last_seen_hwid_type");
b1.HasKey("PlayerId");
b1.ToTable("player");
b1.WithOwner()
.HasForeignKey("PlayerId")
.HasConstraintName("FK_player_player_player_id");
});
b.Navigation("LastSeenHWId");
});
modelBuilder.Entity("Content.Server.Database.Profile", b => modelBuilder.Entity("Content.Server.Database.Profile", b =>
{ {
b.HasOne("Content.Server.Database.Preference", "Preference") b.HasOne("Content.Server.Database.Preference", "Preference")
@@ -1715,36 +1668,8 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasForeignKey("RoundId") .HasForeignKey("RoundId")
.HasConstraintName("FK_server_ban_round_round_id"); .HasConstraintName("FK_server_ban_round_round_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ServerBanId")
.HasColumnType("INTEGER")
.HasColumnName("server_ban_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("BLOB")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ServerBanId");
b1.ToTable("server_ban");
b1.WithOwner()
.HasForeignKey("ServerBanId")
.HasConstraintName("FK_server_ban_server_ban_server_ban_id");
});
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");
b.Navigation("HWId");
b.Navigation("LastEditedBy"); b.Navigation("LastEditedBy");
b.Navigation("Round"); b.Navigation("Round");
@@ -1792,36 +1717,8 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasForeignKey("RoundId") .HasForeignKey("RoundId")
.HasConstraintName("FK_server_role_ban_round_round_id"); .HasConstraintName("FK_server_role_ban_round_round_id");
b.OwnsOne("Content.Server.Database.TypedHwid", "HWId", b1 =>
{
b1.Property<int>("ServerRoleBanId")
.HasColumnType("INTEGER")
.HasColumnName("server_role_ban_id");
b1.Property<byte[]>("Hwid")
.IsRequired()
.HasColumnType("BLOB")
.HasColumnName("hwid");
b1.Property<int>("Type")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0)
.HasColumnName("hwid_type");
b1.HasKey("ServerRoleBanId");
b1.ToTable("server_role_ban");
b1.WithOwner()
.HasForeignKey("ServerRoleBanId")
.HasConstraintName("FK_server_role_ban_server_role_ban_server_role_ban_id");
});
b.Navigation("CreatedBy"); b.Navigation("CreatedBy");
b.Navigation("HWId");
b.Navigation("LastEditedBy"); b.Navigation("LastEditedBy");
b.Navigation("Round"); b.Navigation("Round");

View File

@@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text.Json; using System.Text.Json;
@@ -329,47 +327,6 @@ namespace Content.Server.Database
.HasForeignKey(w => w.PlayerUserId) .HasForeignKey(w => w.PlayerUserId)
.HasPrincipalKey(p => p.UserId) .HasPrincipalKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
// Changes for modern HWID integration
modelBuilder.Entity<Player>()
.OwnsOne(p => p.LastSeenHWId)
.Property(p => p.Hwid)
.HasColumnName("last_seen_hwid");
modelBuilder.Entity<Player>()
.OwnsOne(p => p.LastSeenHWId)
.Property(p => p.Type)
.HasDefaultValue(HwidType.Legacy);
modelBuilder.Entity<ServerBan>()
.OwnsOne(p => p.HWId)
.Property(p => p.Hwid)
.HasColumnName("hwid");
modelBuilder.Entity<ServerBan>()
.OwnsOne(p => p.HWId)
.Property(p => p.Type)
.HasDefaultValue(HwidType.Legacy);
modelBuilder.Entity<ServerRoleBan>()
.OwnsOne(p => p.HWId)
.Property(p => p.Hwid)
.HasColumnName("hwid");
modelBuilder.Entity<ServerRoleBan>()
.OwnsOne(p => p.HWId)
.Property(p => p.Type)
.HasDefaultValue(HwidType.Legacy);
modelBuilder.Entity<ConnectionLog>()
.OwnsOne(p => p.HWId)
.Property(p => p.Hwid)
.HasColumnName("hwid");
modelBuilder.Entity<ConnectionLog>()
.OwnsOne(p => p.HWId)
.Property(p => p.Type)
.HasDefaultValue(HwidType.Legacy);
} }
public virtual IQueryable<AdminLog> SearchLogs(IQueryable<AdminLog> query, string searchText) public virtual IQueryable<AdminLog> SearchLogs(IQueryable<AdminLog> query, string searchText)
@@ -562,7 +519,7 @@ namespace Content.Server.Database
public string LastSeenUserName { get; set; } = null!; public string LastSeenUserName { get; set; } = null!;
public DateTime LastSeenTime { get; set; } public DateTime LastSeenTime { get; set; }
public IPAddress LastSeenAddress { get; set; } = null!; public IPAddress LastSeenAddress { get; set; } = null!;
public TypedHwid? LastSeenHWId { get; set; } public byte[]? LastSeenHWId { get; set; }
// Data that changes with each round // Data that changes with each round
public List<Round> Rounds { get; set; } = null!; public List<Round> Rounds { get; set; } = null!;
@@ -711,7 +668,7 @@ namespace Content.Server.Database
int Id { get; set; } int Id { get; set; }
Guid? PlayerUserId { get; set; } Guid? PlayerUserId { get; set; }
NpgsqlInet? Address { get; set; } NpgsqlInet? Address { get; set; }
TypedHwid? HWId { get; set; } byte[]? HWId { get; set; }
DateTime BanTime { get; set; } DateTime BanTime { get; set; }
DateTime? ExpirationTime { get; set; } DateTime? ExpirationTime { get; set; }
string Reason { get; set; } string Reason { get; set; }
@@ -796,7 +753,7 @@ namespace Content.Server.Database
/// <summary> /// <summary>
/// Hardware ID of the banned player. /// Hardware ID of the banned player.
/// </summary> /// </summary>
public TypedHwid? HWId { get; set; } public byte[]? HWId { get; set; }
/// <summary> /// <summary>
/// The time when the ban was applied by an administrator. /// The time when the ban was applied by an administrator.
@@ -934,7 +891,7 @@ namespace Content.Server.Database
public DateTime Time { get; set; } public DateTime Time { get; set; }
public IPAddress Address { get; set; } = null!; public IPAddress Address { get; set; } = null!;
public TypedHwid? HWId { get; set; } public byte[]? HWId { get; set; }
public ConnectionDenyReason? Denied { get; set; } public ConnectionDenyReason? Denied { get; set; }
@@ -951,8 +908,6 @@ namespace Content.Server.Database
public List<ServerBanHit> BanHits { get; set; } = null!; public List<ServerBanHit> BanHits { get; set; } = null!;
public Server Server { get; set; } = null!; public Server Server { get; set; } = null!;
public float Trust { get; set; }
} }
public enum ConnectionDenyReason : byte public enum ConnectionDenyReason : byte
@@ -990,7 +945,7 @@ namespace Content.Server.Database
public Guid? PlayerUserId { get; set; } public Guid? PlayerUserId { get; set; }
[Required] public TimeSpan PlaytimeAtNote { get; set; } [Required] public TimeSpan PlaytimeAtNote { get; set; }
public NpgsqlInet? Address { get; set; } public NpgsqlInet? Address { get; set; }
public TypedHwid? HWId { get; set; } public byte[]? HWId { get; set; }
public DateTime BanTime { get; set; } public DateTime BanTime { get; set; }
@@ -1251,37 +1206,4 @@ namespace Content.Server.Database
/// <seealso cref="ServerBan.Hidden"/> /// <seealso cref="ServerBan.Hidden"/>
public bool Hidden { get; set; } public bool Hidden { get; set; }
} }
/// <summary>
/// A hardware ID value together with its <see cref="HwidType"/>.
/// </summary>
/// <seealso cref="ImmutableTypedHwid"/>
[Owned]
public sealed class TypedHwid
{
public byte[] Hwid { get; set; } = default!;
public HwidType Type { get; set; }
[return: NotNullIfNotNull(nameof(immutable))]
public static implicit operator TypedHwid?(ImmutableTypedHwid? immutable)
{
if (immutable == null)
return null;
return new TypedHwid
{
Hwid = immutable.Hwid.ToArray(),
Type = immutable.Type,
};
}
[return: NotNullIfNotNull(nameof(hwid))]
public static implicit operator ImmutableTypedHwid?(TypedHwid? hwid)
{
if (hwid == null)
return null;
return new ImmutableTypedHwid(hwid.Hwid.ToImmutableArray(), hwid.Type);
}
}
} }

View File

@@ -82,7 +82,7 @@ namespace Content.Server.Database
} }
} }
public partial class SnakeCaseConvention : public class SnakeCaseConvention :
IEntityTypeAddedConvention, IEntityTypeAddedConvention,
IEntityTypeAnnotationChangedConvention, IEntityTypeAnnotationChangedConvention,
IPropertyAddedConvention, IPropertyAddedConvention,
@@ -99,27 +99,22 @@ namespace Content.Server.Database
public static string RewriteName(string name) public static string RewriteName(string name)
{ {
return UpperCaseLocator() var regex = new Regex("[A-Z]+", RegexOptions.Compiled);
.Replace( return regex.Replace(
name, name,
(Match match) => { (Match match) => {
if (match.Index == 0 && (match.Value == "FK" || match.Value == "PK" || match.Value == "IX")) { if (match.Index == 0 && (match.Value == "FK" || match.Value == "PK" || match.Value == "IX")) {
return match.Value; return match.Value;
}
if (match.Value == "HWI")
return (match.Index == 0 ? "" : "_") + "hwi";
if (match.Index == 0)
return match.Value.ToLower();
if (match.Length > 1)
return $"_{match.Value[..^1].ToLower()}_{match.Value[^1..^0].ToLower()}";
// Do not add a _ if there is already one before this. This happens with owned entities.
if (name[match.Index - 1] == '_')
return match.Value.ToLower();
return "_" + match.Value.ToLower();
} }
); if (match.Value == "HWI")
return (match.Index == 0 ? "" : "_") + "hwi";
if (match.Index == 0)
return match.Value.ToLower();
if (match.Length > 1)
return $"_{match.Value[..^1].ToLower()}_{match.Value[^1..^0].ToLower()}";
return "_" + match.Value.ToLower();
}
);
} }
public virtual void ProcessEntityTypeAdded( public virtual void ProcessEntityTypeAdded(
@@ -337,8 +332,5 @@ namespace Content.Server.Database
} }
} }
} }
[GeneratedRegex("[A-Z]+", RegexOptions.Compiled)]
private static partial Regex UpperCaseLocator();
} }
} }

View File

@@ -146,8 +146,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.ReadyToRepent = false; mimePowers.ReadyToRepent = false;
mimePowers.VowBroken = false; mimePowers.VowBroken = false;
AddComp<MutedComponent>(uid); AddComp<MutedComponent>(uid);
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert); _alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert); _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid); _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
} }
} }

View File

@@ -54,7 +54,7 @@ public sealed class BanListEui : BaseEui
private async Task LoadBans(NetUserId userId) private async Task LoadBans(NetUserId userId)
{ {
foreach (var ban in await _db.GetServerBansAsync(null, userId, null, null)) foreach (var ban in await _db.GetServerBansAsync(null, userId, null))
{ {
SharedServerUnban? unban = null; SharedServerUnban? unban = null;
if (ban.Unban is { } unbanDef) if (ban.Unban is { } unbanDef)
@@ -74,7 +74,7 @@ public sealed class BanListEui : BaseEui
? (address.address.ToString(), address.cidrMask) ? (address.address.ToString(), address.cidrMask)
: null; : null;
hwid = ban.HWId?.ToString(); hwid = ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan());
} }
Bans.Add(new SharedServerBan( Bans.Add(new SharedServerBan(
@@ -95,7 +95,7 @@ public sealed class BanListEui : BaseEui
private async Task LoadRoleBans(NetUserId userId) private async Task LoadRoleBans(NetUserId userId)
{ {
foreach (var ban in await _db.GetServerRoleBansAsync(null, userId, null, null)) foreach (var ban in await _db.GetServerRoleBansAsync(null, userId, null))
{ {
SharedServerUnban? unban = null; SharedServerUnban? unban = null;
if (ban.Unban is { } unbanDef) if (ban.Unban is { } unbanDef)
@@ -115,7 +115,7 @@ public sealed class BanListEui : BaseEui
? (address.address.ToString(), address.cidrMask) ? (address.address.ToString(), address.cidrMask)
: null; : null;
hwid = ban.HWId?.ToString(); hwid = ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan());
} }
RoleBans.Add(new SharedServerRoleBan( RoleBans.Add(new SharedServerRoleBan(
ban.Id, ban.Id,

View File

@@ -1,3 +1,4 @@
using System.Collections.Immutable;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Content.Server.Administration.Managers; using Content.Server.Administration.Managers;
@@ -7,6 +8,7 @@ using Content.Server.EUI;
using Content.Shared.Administration; using Content.Shared.Administration;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Eui; using Content.Shared.Eui;
using Robust.Server.Player;
using Robust.Shared.Network; using Robust.Shared.Network;
namespace Content.Server.Administration; namespace Content.Server.Administration;
@@ -25,7 +27,7 @@ public sealed class BanPanelEui : BaseEui
private NetUserId? PlayerId { get; set; } private NetUserId? PlayerId { get; set; }
private string PlayerName { get; set; } = string.Empty; private string PlayerName { get; set; } = string.Empty;
private IPAddress? LastAddress { get; set; } private IPAddress? LastAddress { get; set; }
private ImmutableTypedHwid? LastHwid { get; set; } private ImmutableArray<byte>? LastHwid { get; set; }
private const int Ipv4_CIDR = 32; private const int Ipv4_CIDR = 32;
private const int Ipv6_CIDR = 64; private const int Ipv6_CIDR = 64;
@@ -49,7 +51,7 @@ public sealed class BanPanelEui : BaseEui
switch (msg) switch (msg)
{ {
case BanPanelEuiStateMsg.CreateBanRequest r: case BanPanelEuiStateMsg.CreateBanRequest r:
BanPlayer(r.Player, r.IpAddress, r.UseLastIp, r.Hwid, r.UseLastHwid, r.Minutes, r.Severity, r.Reason, r.Roles, r.Erase); BanPlayer(r.Player, r.IpAddress, r.UseLastIp, r.Hwid?.ToImmutableArray(), r.UseLastHwid, r.Minutes, r.Severity, r.Reason, r.Roles, r.Erase);
break; break;
case BanPanelEuiStateMsg.GetPlayerInfoRequest r: case BanPanelEuiStateMsg.GetPlayerInfoRequest r:
ChangePlayer(r.PlayerUsername); ChangePlayer(r.PlayerUsername);
@@ -57,7 +59,7 @@ public sealed class BanPanelEui : BaseEui
} }
} }
private async void BanPlayer(string? target, string? ipAddressString, bool useLastIp, ImmutableTypedHwid? hwid, bool useLastHwid, uint minutes, NoteSeverity severity, string reason, IReadOnlyCollection<string>? roles, bool erase) private async void BanPlayer(string? target, string? ipAddressString, bool useLastIp, ImmutableArray<byte>? hwid, bool useLastHwid, uint minutes, NoteSeverity severity, string reason, IReadOnlyCollection<string>? roles, bool erase)
{ {
if (!_admins.HasAdminFlag(Player, AdminFlags.Ban)) if (!_admins.HasAdminFlag(Player, AdminFlags.Ban))
{ {
@@ -153,7 +155,7 @@ public sealed class BanPanelEui : BaseEui
ChangePlayer(located?.UserId, located?.Username ?? string.Empty, located?.LastAddress, located?.LastHWId); ChangePlayer(located?.UserId, located?.Username ?? string.Empty, located?.LastAddress, located?.LastHWId);
} }
public void ChangePlayer(NetUserId? playerId, string playerName, IPAddress? lastAddress, ImmutableTypedHwid? lastHwid) public void ChangePlayer(NetUserId? playerId, string playerName, IPAddress? lastAddress, ImmutableArray<byte>? lastHwid)
{ {
PlayerId = playerId; PlayerId = playerId;
PlayerName = playerName; PlayerName = playerName;

View File

@@ -38,7 +38,7 @@ public sealed class BanListCommand : LocalizedCommands
if (shell.Player is not { } player) if (shell.Player is not { } player)
{ {
var bans = await _dbManager.GetServerBansAsync(data.LastAddress, data.UserId, data.LastLegacyHWId, data.LastModernHWIds, false); var bans = await _dbManager.GetServerBansAsync(data.LastAddress, data.UserId, data.LastHWId, false);
if (bans.Count == 0) if (bans.Count == 0)
{ {

View File

@@ -48,7 +48,7 @@ public sealed class RoleBanListCommand : IConsoleCommand
if (shell.Player is not { } player) if (shell.Player is not { } player)
{ {
var bans = await _dbManager.GetServerRoleBansAsync(data.LastAddress, data.UserId, data.LastLegacyHWId, data.LastModernHWIds, includeUnbanned); var bans = await _dbManager.GetServerRoleBansAsync(data.LastAddress, data.UserId, data.LastHWId, includeUnbanned);
if (bans.Count == 0) if (bans.Count == 0)
{ {

View File

@@ -65,8 +65,7 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
var netChannel = player.Channel; var netChannel = player.Channel;
ImmutableArray<byte>? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId; ImmutableArray<byte>? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId;
var modernHwids = netChannel.UserData.ModernHWIds; var roleBans = await _db.GetServerRoleBansAsync(netChannel.RemoteEndPoint.Address, player.UserId, hwId, false);
var roleBans = await _db.GetServerRoleBansAsync(netChannel.RemoteEndPoint.Address, player.UserId, hwId, modernHwids, false);
var userRoleBans = new List<ServerRoleBanDef>(); var userRoleBans = new List<ServerRoleBanDef>();
foreach (var ban in roleBans) foreach (var ban in roleBans)
@@ -133,7 +132,7 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
} }
#region Server Bans #region Server Bans
public async void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? hwid, uint? minutes, NoteSeverity severity, string reason) public async void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray<byte>? hwid, uint? minutes, NoteSeverity severity, string reason)
{ {
DateTimeOffset? expires = null; DateTimeOffset? expires = null;
if (minutes > 0) if (minutes > 0)
@@ -167,7 +166,9 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
var addressRangeString = addressRange != null var addressRangeString = addressRange != null
? $"{addressRange.Value.Item1}/{addressRange.Value.Item2}" ? $"{addressRange.Value.Item1}/{addressRange.Value.Item2}"
: "null"; : "null";
var hwidString = hwid?.ToString() ?? "null"; var hwidString = hwid != null
? string.Concat(hwid.Value.Select(x => x.ToString("x2")))
: "null";
var expiresString = expires == null ? Loc.GetString("server-ban-string-never") : $"{expires}"; var expiresString = expires == null ? Loc.GetString("server-ban-string-never") : $"{expires}";
var key = _cfg.GetCVar(CCVars.AdminShowPIIOnBan) ? "server-ban-string" : "server-ban-string-no-pii"; var key = _cfg.GetCVar(CCVars.AdminShowPIIOnBan) ? "server-ban-string" : "server-ban-string-no-pii";
@@ -207,7 +208,6 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
UserId = player.UserId, UserId = player.UserId,
Address = player.Channel.RemoteEndPoint.Address, Address = player.Channel.RemoteEndPoint.Address,
HWId = player.Channel.UserData.HWId, HWId = player.Channel.UserData.HWId,
ModernHWIds = player.Channel.UserData.ModernHWIds,
// It's possible for the player to not have cached data loading yet due to coincidental timing. // It's possible for the player to not have cached data loading yet due to coincidental timing.
// If this is the case, we assume they have all flags to avoid false-positives. // If this is the case, we assume they have all flags to avoid false-positives.
ExemptFlags = _cachedBanExemptions.GetValueOrDefault(player, ServerBanExemptFlags.All), ExemptFlags = _cachedBanExemptions.GetValueOrDefault(player, ServerBanExemptFlags.All),
@@ -228,7 +228,7 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
#region Job Bans #region Job Bans
// If you are trying to remove timeOfBan, please don't. It's there because the note system groups role bans by time, reason and banning admin. // If you are trying to remove timeOfBan, please don't. It's there because the note system groups role bans by time, reason and banning admin.
// Removing it will clutter the note list. Please also make sure that department bans are applied to roles with the same DateTimeOffset. // Removing it will clutter the note list. Please also make sure that department bans are applied to roles with the same DateTimeOffset.
public async void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan) public async void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray<byte>? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan)
{ {
if (!_prototypeManager.TryIndex(role, out JobPrototype? _)) if (!_prototypeManager.TryIndex(role, out JobPrototype? _))
{ {

View File

@@ -24,7 +24,7 @@ public interface IBanManager
/// <param name="minutes">Number of minutes to ban for. 0 and null mean permanent</param> /// <param name="minutes">Number of minutes to ban for. 0 and null mean permanent</param>
/// <param name="severity">Severity of the resulting ban note</param> /// <param name="severity">Severity of the resulting ban note</param>
/// <param name="reason">Reason for the ban</param> /// <param name="reason">Reason for the ban</param>
public void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? hwid, uint? minutes, NoteSeverity severity, string reason); public void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray<byte>? hwid, uint? minutes, NoteSeverity severity, string reason);
public HashSet<string>? GetRoleBans(NetUserId playerUserId); public HashSet<string>? GetRoleBans(NetUserId playerUserId);
public HashSet<ProtoId<JobPrototype>>? GetJobBans(NetUserId playerUserId); public HashSet<ProtoId<JobPrototype>>? GetJobBans(NetUserId playerUserId);
@@ -37,7 +37,7 @@ public interface IBanManager
/// <param name="reason">Reason for the ban</param> /// <param name="reason">Reason for the ban</param>
/// <param name="minutes">Number of minutes to ban for. 0 and null mean permanent</param> /// <param name="minutes">Number of minutes to ban for. 0 and null mean permanent</param>
/// <param name="timeOfBan">Time when the ban was applied, used for grouping role bans</param> /// <param name="timeOfBan">Time when the ban was applied, used for grouping role bans</param>
public void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan); public void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableArray<byte>? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan);
/// <summary> /// <summary>
/// Pardons a role ban for the specified target, username or GUID /// Pardons a role ban for the specified target, username or GUID

View File

@@ -5,42 +5,16 @@ using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.Connection;
using Content.Server.Database; using Content.Server.Database;
using Content.Shared.Database;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared; using Robust.Shared;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player;
namespace Content.Server.Administration namespace Content.Server.Administration
{ {
/// <summary> public sealed record LocatedPlayerData(NetUserId UserId, IPAddress? LastAddress, ImmutableArray<byte>? LastHWId, string Username);
/// Contains data resolved via <see cref="IPlayerLocator"/>.
/// </summary>
/// <param name="UserId">The ID of the located user.</param>
/// <param name="LastAddress">The last known IP address that the user connected with.</param>
/// <param name="LastHWId">
/// The last known HWID that the user connected with.
/// This should be used for placing new records involving HWIDs, such as bans.
/// For looking up data based on HWID, use combined <see cref="LastLegacyHWId"/> and <see cref="LastModernHWIds"/>.
/// </param>
/// <param name="Username">The last known username for the user connected with.</param>
/// <param name="LastLegacyHWId">
/// The last known legacy HWID value this user connected with. Only use for old lookups!
/// </param>
/// <param name="LastModernHWIds">
/// The set of last known modern HWIDs the user connected with.
/// </param>
public sealed record LocatedPlayerData(
NetUserId UserId,
IPAddress? LastAddress,
ImmutableTypedHwid? LastHWId,
string Username,
ImmutableArray<byte>? LastLegacyHWId,
ImmutableArray<ImmutableArray<byte>> LastModernHWIds);
/// <summary> /// <summary>
/// Utilities for finding user IDs that extend to more than the server database. /// Utilities for finding user IDs that extend to more than the server database.
@@ -93,42 +67,23 @@ namespace Content.Server.Administration
{ {
// Check people currently on the server, the easiest case. // Check people currently on the server, the easiest case.
if (_playerManager.TryGetSessionByUsername(playerName, out var session)) if (_playerManager.TryGetSessionByUsername(playerName, out var session))
return ReturnForSession(session); {
var userId = session.UserId;
var address = session.Channel.RemoteEndPoint.Address;
var hwId = session.Channel.UserData.HWId;
return new LocatedPlayerData(userId, address, hwId, session.Name);
}
// Check database for past players. // Check database for past players.
var record = await _db.GetPlayerRecordByUserName(playerName, cancel); var record = await _db.GetPlayerRecordByUserName(playerName, cancel);
if (record != null) if (record != null)
return ReturnForPlayerRecord(record); return new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId, record.LastSeenUserName);
// If all else fails, ask the auth server. // If all else fails, ask the auth server.
var authServer = _configurationManager.GetCVar(CVars.AuthServer); var authServer = _configurationManager.GetCVar(CVars.AuthServer);
var requestUri = $"{authServer}api/query/name?name={WebUtility.UrlEncode(playerName)}"; var requestUri = $"{authServer}api/query/name?name={WebUtility.UrlEncode(playerName)}";
using var resp = await _httpClient.GetAsync(requestUri, cancel); using var resp = await _httpClient.GetAsync(requestUri, cancel);
return await HandleAuthServerResponse(resp, cancel);
}
public async Task<LocatedPlayerData?> LookupIdAsync(NetUserId userId, CancellationToken cancel = default)
{
// Check people currently on the server, the easiest case.
if (_playerManager.TryGetSessionById(userId, out var session))
return ReturnForSession(session);
// Check database for past players.
var record = await _db.GetPlayerRecordByUserId(userId, cancel);
if (record != null)
return ReturnForPlayerRecord(record);
// If all else fails, ask the auth server.
var authServer = _configurationManager.GetCVar(CVars.AuthServer);
var requestUri = $"{authServer}api/query/userid?userid={WebUtility.UrlEncode(userId.UserId.ToString())}";
using var resp = await _httpClient.GetAsync(requestUri, cancel);
return await HandleAuthServerResponse(resp, cancel);
}
private async Task<LocatedPlayerData?> HandleAuthServerResponse(HttpResponseMessage resp, CancellationToken cancel)
{
if (resp.StatusCode == HttpStatusCode.NotFound) if (resp.StatusCode == HttpStatusCode.NotFound)
return null; return null;
@@ -139,40 +94,54 @@ namespace Content.Server.Administration
} }
var responseData = await resp.Content.ReadFromJsonAsync<UserDataResponse>(cancellationToken: cancel); var responseData = await resp.Content.ReadFromJsonAsync<UserDataResponse>(cancellationToken: cancel);
if (responseData == null) if (responseData == null)
{ {
_sawmill.Error("Auth server returned null response!"); _sawmill.Error("Auth server returned null response!");
return null; return null;
} }
return new LocatedPlayerData(new NetUserId(responseData.UserId), null, null, responseData.UserName, null, []); return new LocatedPlayerData(new NetUserId(responseData.UserId), null, null, responseData.UserName);
} }
private static LocatedPlayerData ReturnForSession(ICommonSession session) public async Task<LocatedPlayerData?> LookupIdAsync(NetUserId userId, CancellationToken cancel = default)
{ {
var userId = session.UserId; // Check people currently on the server, the easiest case.
var address = session.Channel.RemoteEndPoint.Address; if (_playerManager.TryGetSessionById(userId, out var session))
var hwId = session.Channel.UserData.GetModernHwid(); {
return new LocatedPlayerData( var address = session.Channel.RemoteEndPoint.Address;
userId, var hwId = session.Channel.UserData.HWId;
address, return new LocatedPlayerData(userId, address, hwId, session.Name);
hwId, }
session.Name,
session.Channel.UserData.HWId,
session.Channel.UserData.ModernHWIds);
}
private static LocatedPlayerData ReturnForPlayerRecord(PlayerRecord record) // Check database for past players.
{ var record = await _db.GetPlayerRecordByUserId(userId, cancel);
var hwid = record.HWId; if (record != null)
return new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId, record.LastSeenUserName);
return new LocatedPlayerData( // If all else fails, ask the auth server.
record.UserId, var authServer = _configurationManager.GetCVar(CVars.AuthServer);
record.LastSeenAddress, var requestUri = $"{authServer}api/query/userid?userid={WebUtility.UrlEncode(userId.UserId.ToString())}";
hwid, using var resp = await _httpClient.GetAsync(requestUri, cancel);
record.LastSeenUserName,
hwid is { Type: HwidType.Legacy } ? hwid.Hwid : null, if (resp.StatusCode == HttpStatusCode.NotFound)
hwid is { Type: HwidType.Modern } ? [hwid.Hwid] : []); return null;
if (!resp.IsSuccessStatusCode)
{
_sawmill.Error("Auth server returned bad response {StatusCode}!", resp.StatusCode);
return null;
}
var responseData = await resp.Content.ReadFromJsonAsync<UserDataResponse>(cancellationToken: cancel);
if (responseData == null)
{
_sawmill.Error("Auth server returned null response!");
return null;
}
return new LocatedPlayerData(new NetUserId(responseData.UserId), null, null, responseData.UserName);
} }
public async Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default) public async Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default)

View File

@@ -173,11 +173,11 @@ public sealed class PlayerPanelEui : BaseEui
{ {
_whitelisted = await _db.GetWhitelistStatusAsync(_targetPlayer.UserId); _whitelisted = await _db.GetWhitelistStatusAsync(_targetPlayer.UserId);
// This won't get associated ip or hwid bans but they were not placed on this account anyways // This won't get associated ip or hwid bans but they were not placed on this account anyways
_bans = (await _db.GetServerBansAsync(null, _targetPlayer.UserId, null, null)).Count; _bans = (await _db.GetServerBansAsync(null, _targetPlayer.UserId, null)).Count;
// Unfortunately role bans for departments and stuff are issued individually. This means that a single role ban can have many individual role bans internally // Unfortunately role bans for departments and stuff are issued individually. This means that a single role ban can have many individual role bans internally
// The only way to distinguish whether a role ban is the same is to compare the ban time. // The only way to distinguish whether a role ban is the same is to compare the ban time.
// This is horrible and I would love to just erase the database and start from scratch instead but that's what I can do for now. // This is horrible and I would love to just erase the database and start from scratch instead but that's what I can do for now.
_roleBans = (await _db.GetServerRoleBansAsync(null, _targetPlayer.UserId, null, null)).DistinctBy(rb => rb.BanTime).Count(); _roleBans = (await _db.GetServerRoleBansAsync(null, _targetPlayer.UserId, null)).DistinctBy(rb => rb.BanTime).Count();
} }
else else
{ {

View File

@@ -22,7 +22,6 @@ using Content.Shared.Administration;
using Content.Shared.Administration.Components; using Content.Shared.Administration.Components;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Body.Part; using Content.Shared.Body.Part;
using Content.Shared.Clumsy;
using Content.Shared.Clothing.Components; using Content.Shared.Clothing.Components;
using Content.Shared.Cluwne; using Content.Shared.Cluwne;
using Content.Shared.Damage; using Content.Shared.Damage;

View File

@@ -172,7 +172,7 @@ namespace Content.Server.Administration.Systems
} }
// Check if the user has been banned // Check if the user has been banned
var ban = await _dbManager.GetServerBanAsync(null, e.Session.UserId, null, null); var ban = await _dbManager.GetServerBanAsync(null, e.Session.UserId, null);
if (ban != null) if (ban != null)
{ {
var banMessage = Loc.GetString("bwoink-system-player-banned", ("banReason", ban.Reason)); var banMessage = Loc.GetString("bwoink-system-player-banned", ("banReason", ban.Reason));

View File

@@ -1,27 +1,27 @@
using Content.Server.Administration.Components; using Content.Server.Administration.Components;
using Content.Shared.Climbing.Components; using Content.Shared.Climbing.Components;
using Content.Shared.Clumsy; using Content.Shared.Climbing.Events;
using Content.Shared.Climbing.Systems;
using Content.Shared.Interaction.Components;
using Content.Shared.Mobs; using Content.Shared.Mobs;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Robust.Shared.Audio.Systems;
namespace Content.Server.Administration.Systems; namespace Content.Server.Administration.Systems;
public sealed class SuperBonkSystem : EntitySystem public sealed class SuperBonkSystem: EntitySystem
{ {
[Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly ClumsySystem _clumsySystem = default!; [Dependency] private readonly BonkSystem _bonkSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown); SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
} }
public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false) public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false )
{ {
//The other check in the code to stop when the target dies does not work if the target is already dead. //The other check in the code to stop when the target dies does not work if the target is already dead.
@@ -31,6 +31,7 @@ public sealed class SuperBonkSystem : EntitySystem
return; return;
} }
var hadClumsy = EnsureComp<ClumsyComponent>(target, out _); var hadClumsy = EnsureComp<ClumsyComponent>(target, out _);
var tables = EntityQueryEnumerator<BonkableComponent>(); var tables = EntityQueryEnumerator<BonkableComponent>();
@@ -78,17 +79,16 @@ public sealed class SuperBonkSystem : EntitySystem
private void Bonk(SuperBonkComponent comp) private void Bonk(SuperBonkComponent comp)
{ {
var uid = comp.Tables.Current.Key; var uid = comp.Tables.Current.Key;
var bonkComp = comp.Tables.Current.Value;
// It would be very weird for something without a transform component to have a bonk component // It would be very weird for something without a transform component to have a bonk component
// but just in case because I don't want to crash the server. // but just in case because I don't want to crash the server.
if (!HasComp<TransformComponent>(uid) || !TryComp<ClumsyComponent>(comp.Target, out var clumsyComp)) if (!HasComp<TransformComponent>(uid))
return; return;
_transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates); _transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates);
_clumsySystem.HitHeadClumsy((comp.Target, clumsyComp), uid); _bonkSystem.TryBonk(comp.Target, uid, bonkComp);
_audioSystem.PlayPvs(clumsyComp.TableBonkSound, comp.Target);
} }
private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args) private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args)

View File

@@ -25,16 +25,6 @@ public sealed class TagCommand : ToolshedCommand
}); });
} }
[CommandImplementation("with")]
public IEnumerable<EntityUid> With(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> entities,
[CommandArgument] ValueRef<string, Prototype<TagPrototype>> tag)
{
_tag ??= GetSys<TagSystem>();
return entities.Where(e => _tag.HasTag(e, tag.Evaluate(ctx)!));
}
[CommandImplementation("add")] [CommandImplementation("add")]
public EntityUid Add( public EntityUid Add(
[CommandInvocationContext] IInvocationContext ctx, [CommandInvocationContext] IInvocationContext ctx,

View File

@@ -1,19 +1,7 @@
using Content.Shared.Alert; using Content.Shared.Alert;
using Robust.Shared.GameStates;
namespace Content.Server.Alert; namespace Content.Server.Alert;
internal sealed class ServerAlertsSystem : AlertsSystem internal sealed class ServerAlertsSystem : AlertsSystem
{ {
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AlertsComponent, ComponentGetState>(OnGetState);
}
private void OnGetState(Entity<AlertsComponent> alerts, ref ComponentGetState args)
{
args.State = new AlertComponentState(alerts.Comp.Alerts);
}
} }

View File

@@ -28,8 +28,7 @@ namespace Content.Server.Announcements
} }
else else
{ {
// Explicit IEnumerable<string> due to overload ambiguity on .NET 9 var message = string.Join(' ', new ArraySegment<string>(args, 1, args.Length-1));
var message = string.Join(' ', (IEnumerable<string>)new ArraySegment<string>(args, 1, args.Length-1));
chat.DispatchGlobalAnnouncement(message, args[0], colorOverride: Color.Gold); chat.DispatchGlobalAnnouncement(message, args[0], colorOverride: Color.Gold);
} }
shell.WriteLine("Sent!"); shell.WriteLine("Sent!");

View File

@@ -55,8 +55,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
{ {
base.Initialize(); base.Initialize();
Log.Level = LogLevel.Debug;
SubscribeLocalEvent<GhostRoleAntagSpawnerComponent, TakeGhostRoleEvent>(OnTakeGhostRole); SubscribeLocalEvent<GhostRoleAntagSpawnerComponent, TakeGhostRoleEvent>(OnTakeGhostRole);
SubscribeLocalEvent<AntagSelectionComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo); SubscribeLocalEvent<AntagSelectionComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
@@ -184,7 +182,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
return; return;
var players = _playerManager.Sessions var players = _playerManager.Sessions
.Where(x => GameTicker.PlayerGameStatuses.TryGetValue(x.UserId, out var status) && status == PlayerGameStatus.JoinedGame) .Where(x => GameTicker.PlayerGameStatuses[x.UserId] == PlayerGameStatus.JoinedGame)
.ToList(); .ToList();
ChooseAntags((uid, component), players, midround: true); ChooseAntags((uid, component), players, midround: true);
@@ -362,8 +360,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
_role.MindAddRoles(curMind.Value, def.MindRoles, null, true); _role.MindAddRoles(curMind.Value, def.MindRoles, null, true);
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player))); ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
SendBriefing(session, def.Briefing); SendBriefing(session, def.Briefing);
Log.Debug($"Selected {ToPrettyString(curMind)} as antagonist: {ToPrettyString(ent)}");
} }
var afterEv = new AfterAntagEntitySelectedEvent(session, player, ent, def); var afterEv = new AfterAntagEntitySelectedEvent(session, player, ent, def);

View File

@@ -84,15 +84,9 @@ namespace Content.Server.Atmos.Components
public ProtoId<AlertPrototype> FireAlert = "Fire"; public ProtoId<AlertPrototype> FireAlert = "Fire";
/// <summary> /// <summary>
/// CrystallEdge fireplace fuel /// CrystallPunk fireplace fuel
/// </summary> /// </summary>
[DataField] [DataField]
public float CP14FireplaceFuel = 10f; public float CP14FireplaceFuel = 10f;
/// <summary>
/// the value is cached to check if it has changed
/// </summary>
[DataField]
public bool OnFireOld = false;
} }
} }

View File

@@ -1,3 +1,4 @@
using Content.Server._CP14.Temperature;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.IgnitionSource; using Content.Server.IgnitionSource;
@@ -5,7 +6,6 @@ using Content.Server.Stunnable;
using Content.Server.Temperature.Components; using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems; using Content.Server.Temperature.Systems;
using Content.Server.Damage.Components; using Content.Server.Damage.Components;
using Content.Shared._CP14.Temperature;
using Content.Shared.ActionBlocker; using Content.Shared.ActionBlocker;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Atmos; using Content.Shared.Atmos;
@@ -144,16 +144,15 @@ namespace Content.Server.Atmos.EntitySystems
{ {
if (args.Handled) if (args.Handled)
return; return;
var isHotEvent = new IsHotEvent(); var isHotEvent = new IsHotEvent();
RaiseLocalEvent(args.Used, isHotEvent); RaiseLocalEvent(args.Used, isHotEvent);
if (!isHotEvent.IsHot) if (!isHotEvent.IsHot)
return; return;
/* //CP14 disabling igniting via direact interact. Only from DelayedIgnitionSource
Ignite(uid, args.Used, flammable, args.User); Ignite(uid, args.Used, flammable, args.User);
args.Handled = true; args.Handled = true;
*/
} }
private void OnExtinguishActivateInWorld(EntityUid uid, ExtinguishOnInteractComponent component, ActivateInWorldEvent args) private void OnExtinguishActivateInWorld(EntityUid uid, ExtinguishOnInteractComponent component, ActivateInWorldEvent args)
@@ -264,19 +263,6 @@ namespace Content.Server.Atmos.EntitySystems
public void UpdateAppearance(EntityUid uid, FlammableComponent? flammable = null, AppearanceComponent? appearance = null) public void UpdateAppearance(EntityUid uid, FlammableComponent? flammable = null, AppearanceComponent? appearance = null)
{ {
//CrystallEdge bonfire moment
if (!Resolve(uid, ref flammable))
return;
if (flammable.OnFireOld != flammable.OnFire)
{
var ev = new OnFireChangedEvent(flammable.OnFire);
RaiseLocalEvent(uid, ref ev);
flammable.OnFireOld = flammable.OnFire;
}
//CrystallEdge bonfire moment end
if (!Resolve(uid, ref flammable, ref appearance)) if (!Resolve(uid, ref flammable, ref appearance))
return; return;
@@ -330,6 +316,12 @@ namespace Content.Server.Atmos.EntitySystems
_ignitionSourceSystem.SetIgnited(uid, false); _ignitionSourceSystem.SetIgnited(uid, false);
//CrystallPunk bonfire moment
var ev = new OnFireChangedEvent(flammable.OnFire);
RaiseLocalEvent(uid, ref ev);
//CrystallPunk bonfire moment end
UpdateAppearance(uid, flammable); UpdateAppearance(uid, flammable);
} }
@@ -351,6 +343,11 @@ namespace Content.Server.Atmos.EntitySystems
else else
_adminLogger.Add(LogType.Flammable, $"{ToPrettyString(uid):target} set on fire by {ToPrettyString(ignitionSource):actor}"); _adminLogger.Add(LogType.Flammable, $"{ToPrettyString(uid):target} set on fire by {ToPrettyString(ignitionSource):actor}");
flammable.OnFire = true; flammable.OnFire = true;
//CrystallPunk fireplace moment
var ev = new OnFireChangedEvent(flammable.OnFire);
RaiseLocalEvent(uid, ref ev);
//CrystallPunk fireplace moment end
} }
UpdateAppearance(uid, flammable); UpdateAppearance(uid, flammable);

View File

@@ -48,9 +48,7 @@ public sealed partial class AtmosMonitorComponent : Component
[DataField("gasThresholds")] [DataField("gasThresholds")]
public Dictionary<Gas, AtmosAlarmThreshold>? GasThresholds; public Dictionary<Gas, AtmosAlarmThreshold>? GasThresholds;
/// <summary> // Stores a reference to the gas on the tile this is on.
/// Stores a reference to the gas on the tile this entity is on (or the pipe network it monitors; see <see cref="MonitorsPipeNet"/>).
/// </summary>
[ViewVariables] [ViewVariables]
public GasMixture? TileGas; public GasMixture? TileGas;
@@ -67,19 +65,4 @@ public sealed partial class AtmosMonitorComponent : Component
/// </summary> /// </summary>
[DataField("registeredDevices")] [DataField("registeredDevices")]
public HashSet<string> RegisteredDevices = new(); public HashSet<string> RegisteredDevices = new();
/// <summary>
/// Specifies whether this device monitors its own internal pipe network rather than the surrounding atmosphere.
/// </summary>
/// <remarks>
/// If 'true', the entity will require a NodeContainerComponent with one or more PipeNodes to function.
/// </remarks>
[DataField]
public bool MonitorsPipeNet = false;
/// <summary>
/// Specifies the name of the pipe node that this device is monitoring.
/// </summary>
[DataField]
public string NodeNameMonitoredPipe = "monitored";
} }

View File

@@ -4,9 +4,6 @@ using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.EntitySystems; using Content.Server.Atmos.Piping.EntitySystems;
using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Systems; using Content.Server.DeviceNetwork.Systems;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Shared.Atmos; using Content.Shared.Atmos;
@@ -28,7 +25,6 @@ public sealed class AtmosMonitorSystem : EntitySystem
[Dependency] private readonly AtmosDeviceSystem _atmosDeviceSystem = default!; [Dependency] private readonly AtmosDeviceSystem _atmosDeviceSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainerSystem = default!;
// Commands // Commands
public const string AtmosMonitorSetThresholdCmd = "atmos_monitor_set_threshold"; public const string AtmosMonitorSetThresholdCmd = "atmos_monitor_set_threshold";
@@ -60,15 +56,8 @@ public sealed class AtmosMonitorSystem : EntitySystem
private void OnAtmosDeviceEnterAtmosphere(EntityUid uid, AtmosMonitorComponent atmosMonitor, ref AtmosDeviceEnabledEvent args) private void OnAtmosDeviceEnterAtmosphere(EntityUid uid, AtmosMonitorComponent atmosMonitor, ref AtmosDeviceEnabledEvent args)
{ {
if (atmosMonitor.MonitorsPipeNet && _nodeContainerSystem.TryGetNode<PipeNode>(uid, atmosMonitor.NodeNameMonitoredPipe, out var pipeNode))
{
atmosMonitor.TileGas = pipeNode.Air;
return;
}
atmosMonitor.TileGas = _atmosphereSystem.GetContainingMixture(uid, true); atmosMonitor.TileGas = _atmosphereSystem.GetContainingMixture(uid, true);
} }
private void OnMapInit(EntityUid uid, AtmosMonitorComponent component, MapInitEvent args) private void OnMapInit(EntityUid uid, AtmosMonitorComponent component, MapInitEvent args)
{ {
if (component.TemperatureThresholdId != null) if (component.TemperatureThresholdId != null)
@@ -217,7 +206,7 @@ public sealed class AtmosMonitorSystem : EntitySystem
if (!this.IsPowered(uid, EntityManager)) if (!this.IsPowered(uid, EntityManager))
return; return;
if (args.Grid == null) if (args.Grid == null)
return; return;
// if we're not monitoring atmos, don't bother // if we're not monitoring atmos, don't bother
@@ -226,10 +215,6 @@ public sealed class AtmosMonitorSystem : EntitySystem
&& component.GasThresholds == null) && component.GasThresholds == null)
return; return;
// If monitoring a pipe network, get its most recent gas mixture
if (component.MonitorsPipeNet && _nodeContainerSystem.TryGetNode<PipeNode>(uid, component.NodeNameMonitoredPipe, out var pipeNode))
component.TileGas = pipeNode.Air;
UpdateState(uid, component.TileGas, component); UpdateState(uid, component.TileGas, component);
} }

View File

@@ -1,7 +1,6 @@
using Content.Server._CP14.Temperature; using Content.Server._CP14.Temperature;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Shared._CP14.Temperature;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.Mobs; using Content.Shared.Mobs;
using Content.Shared.Power; using Content.Shared.Power;
@@ -15,7 +14,7 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<AmbientOnPoweredComponent, PowerChangedEvent>(HandlePowerChange); SubscribeLocalEvent<AmbientOnPoweredComponent, PowerChangedEvent>(HandlePowerChange);
SubscribeLocalEvent<AmbientOnPoweredComponent, PowerNetBatterySupplyEvent>(HandlePowerSupply); SubscribeLocalEvent<AmbientOnPoweredComponent, PowerNetBatterySupplyEvent>(HandlePowerSupply);
SubscribeLocalEvent<CP14FlammableAmbientSoundComponent, OnFireChangedEvent>(OnFireChanged); //CrystallEdge bonfire moment SubscribeLocalEvent<CP14FlammableAmbientSoundComponent, OnFireChangedEvent>(OnFireChanged); //CrystallPunk bonfire moment
} }
private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args) private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args)
@@ -28,10 +27,10 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
SetAmbience(uid, args.Powered); SetAmbience(uid, args.Powered);
} }
//CrystallEdge bonfire moment //CrystallPunk bonfire moment
private void OnFireChanged(Entity<CP14FlammableAmbientSoundComponent> ent, ref OnFireChangedEvent args) private void OnFireChanged(Entity<CP14FlammableAmbientSoundComponent> ent, ref OnFireChangedEvent args)
{ {
SetAmbience(ent, args.OnFire); SetAmbience(ent, args.OnFire);
} }
//CrystallEdge bonfire moment end //CrystallPunk bonfire moment end
} }

Some files were not shown because too many files have changed in this diff Show More