Compare commits
250 Commits
LocalHelpe
...
SpellStora
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
544a260f4b | ||
|
|
8057fad4d3 | ||
|
|
191112a8a8 | ||
|
|
406f22de3f | ||
|
|
b72c2bfb7b | ||
|
|
dbc2fd689a | ||
|
|
897a9cf683 | ||
|
|
b37113f7f2 | ||
|
|
42127c4682 | ||
|
|
ae01ebda0e | ||
|
|
fff97fa819 | ||
|
|
677e5194d6 | ||
|
|
09ca45a621 | ||
|
|
b4ec946bd9 | ||
|
|
646d41d3a7 | ||
|
|
a6c7bc5993 | ||
|
|
66fe15f8c7 | ||
|
|
94ac0b1399 | ||
|
|
a3edf04dd3 | ||
|
|
403528cbf3 | ||
|
|
38c70d6c9b | ||
|
|
5a751a820a | ||
|
|
8ad951183c | ||
|
|
548433baca | ||
|
|
96fc06a443 | ||
|
|
4f703ae9ce | ||
|
|
11ee2f9a37 | ||
|
|
f5930bb566 | ||
|
|
0f0b141f21 | ||
|
|
75a096b6bd | ||
|
|
beeffdb5e1 | ||
|
|
5c0a32b8b8 | ||
|
|
4fcfab972d | ||
|
|
4abd793ef9 | ||
|
|
cb246f5d7d | ||
|
|
f9533a637a | ||
|
|
98caf50626 | ||
|
|
a9be561ea7 | ||
|
|
4f3ac3ea68 | ||
|
|
59b09383ca | ||
|
|
a7003acd77 | ||
|
|
a818c2a134 | ||
|
|
8acbf87d8f | ||
|
|
f5d0e955e3 | ||
|
|
b8b33b97af | ||
|
|
44db676b24 | ||
|
|
1b3672e095 | ||
|
|
75acce0d62 | ||
|
|
a13a4f7a99 | ||
|
|
b177a1d019 | ||
|
|
0ec23362fe | ||
|
|
7e8e2c7212 | ||
|
|
e98383d572 | ||
|
|
1fa1975e60 | ||
|
|
9c666457c2 | ||
|
|
6e53cd98a4 | ||
|
|
35e2c641c1 | ||
|
|
fdf3df9fbd | ||
|
|
eebf06d9d6 | ||
|
|
ed1ae96fa2 | ||
|
|
89392e2424 | ||
|
|
efa28fc650 | ||
|
|
2002de9bb0 | ||
|
|
7f5bae99bb | ||
|
|
c4e2eb9d02 | ||
|
|
ed638c94a8 | ||
|
|
e79b046c4a | ||
|
|
ec278dc98f | ||
|
|
42ee90e53e | ||
|
|
a949cf33e9 | ||
|
|
895648aa2c | ||
|
|
0e2e6a001f | ||
|
|
437a586906 | ||
|
|
10ee37a47c | ||
|
|
909235cdbe | ||
|
|
dffece473a | ||
|
|
68eaf6ff25 | ||
|
|
96d2fe477d | ||
|
|
79ff990ddf | ||
|
|
d67f7619c4 | ||
|
|
647db6aa87 | ||
|
|
b0fd9d5a55 | ||
|
|
824efd4b25 | ||
|
|
97be261631 | ||
|
|
31d5a66866 | ||
|
|
e290588624 | ||
|
|
22987fc77f | ||
|
|
c7f83523ef | ||
|
|
f484118e2d | ||
|
|
96b9d1a714 | ||
|
|
d9c677e91b | ||
|
|
0991b6bbe8 | ||
|
|
5cd92431b9 | ||
|
|
476f90df09 | ||
|
|
01d6df3d0a | ||
|
|
a68c6cb29e | ||
|
|
bdab41248d | ||
|
|
f071bf65e0 | ||
|
|
f5b63b8393 | ||
|
|
d9a5ffbef4 | ||
|
|
47f94d1139 | ||
|
|
2c82a2dfc0 | ||
|
|
7077b930f2 | ||
|
|
4f659b9d6d | ||
|
|
11963e50b1 | ||
|
|
6bcfe6fb3d | ||
|
|
1f5eb6a08b | ||
|
|
c4e8751ee6 | ||
|
|
862c2ac858 | ||
|
|
4426bbe784 | ||
|
|
e7e1d96051 | ||
|
|
3173a3461e | ||
|
|
7d82a7bf5c | ||
|
|
abdefbd622 | ||
|
|
da4fa9bea9 | ||
|
|
09d0565413 | ||
|
|
6683dc9037 | ||
|
|
089f190266 | ||
|
|
3a6ae97566 | ||
|
|
4fc7a4c56e | ||
|
|
cf96679d0b | ||
|
|
97ce69fef6 | ||
|
|
e3b611085b | ||
|
|
465170f1e1 | ||
|
|
b4e0362ed4 | ||
|
|
f75be07a05 | ||
|
|
606d44bcb0 | ||
|
|
dfda557d4b | ||
|
|
530a741b7b | ||
|
|
d205d17ba3 | ||
|
|
2c9f2279d6 | ||
|
|
3b9365160c | ||
|
|
9a5c49b961 | ||
|
|
53ce812356 | ||
|
|
0437ec6d56 | ||
|
|
1bebb3390c | ||
|
|
669bc148f9 | ||
|
|
815e37e512 | ||
|
|
ace158df0e | ||
|
|
0f30639cf2 | ||
|
|
5dbea42751 | ||
|
|
c86201308a | ||
|
|
75ec546550 | ||
|
|
e9c66cfe98 | ||
|
|
4f754b814b | ||
|
|
755f322e29 | ||
|
|
5e54536141 | ||
|
|
f2b7743bdd | ||
|
|
b91c977f7a | ||
|
|
fa3a04a527 | ||
|
|
9643598c70 | ||
|
|
51d2b51ad0 | ||
|
|
6f7066eda8 | ||
|
|
c978eefedb | ||
|
|
8cf279e200 | ||
|
|
99b4604d50 | ||
|
|
52c1708117 | ||
|
|
bd2d0ee5e5 | ||
|
|
21074bd98d | ||
|
|
e9f6a02f18 | ||
|
|
af3593a3b7 | ||
|
|
cc3712be0c | ||
|
|
ef51700094 | ||
|
|
8b154899b5 | ||
|
|
8776c71e59 | ||
|
|
70e3650246 | ||
|
|
a1966d8671 | ||
|
|
806e1e46cb | ||
|
|
4f3db43696 | ||
|
|
36aceb178c | ||
|
|
37958378cb | ||
|
|
1136200dc8 | ||
|
|
bbdbad5691 | ||
|
|
991bbc2d4f | ||
|
|
b9c2b0c41b | ||
|
|
a138fede2b | ||
|
|
197d9e68dc | ||
|
|
21979a7b5f | ||
|
|
63f2c8491c | ||
|
|
9b7200607b | ||
|
|
1c8992ffbe | ||
|
|
2801ebea8d | ||
|
|
9396ce302a | ||
|
|
33b780fd1f | ||
|
|
d939e991bb | ||
|
|
d1c66d71e7 | ||
|
|
675e42df24 | ||
|
|
287a9a07de | ||
|
|
40044203e6 | ||
|
|
1e368ae300 | ||
|
|
b9685850fa | ||
|
|
41b84fc29d | ||
|
|
6ed2ab9e85 | ||
|
|
fea5769cc5 | ||
|
|
84338686a3 | ||
|
|
80e148c265 | ||
|
|
667daa168f | ||
|
|
012855475e | ||
|
|
261c18f764 | ||
|
|
6a1d631b14 | ||
|
|
9ee47b927b | ||
|
|
03723afee6 | ||
|
|
d13765fa5c | ||
|
|
8257dc87de | ||
|
|
fc0d85b487 | ||
|
|
379fb4cb6a | ||
|
|
6c7336b0a8 | ||
|
|
18971f2705 | ||
|
|
5b0761dab2 | ||
|
|
b15d5a7f27 | ||
|
|
e72d63e8a9 | ||
|
|
d588409909 | ||
|
|
ed865ae973 | ||
|
|
3972a25258 | ||
|
|
69c0f8773f | ||
|
|
190d965c52 | ||
|
|
a399c1ec7c | ||
|
|
33516b77ed | ||
|
|
03843734e4 | ||
|
|
b0c5023fda | ||
|
|
b35d2902d4 | ||
|
|
d7ed5b4386 | ||
|
|
581a4d14fc | ||
|
|
d863e3c5ca | ||
|
|
00aaffbc00 | ||
|
|
3aff20173c | ||
|
|
9dc90a258e | ||
|
|
4b633fde9c | ||
|
|
963009a440 | ||
|
|
08de5aeae1 | ||
|
|
d0114d9738 | ||
|
|
7169788e16 | ||
|
|
36390b23d1 | ||
|
|
c6fe5682c2 | ||
|
|
1abc60b995 | ||
|
|
834b6ebaaa | ||
|
|
eaa6017ada | ||
|
|
e75a71d7d3 | ||
|
|
0cc1f32b3b | ||
|
|
a4e7ad008c | ||
|
|
eb1168a831 | ||
|
|
4c8a235e61 | ||
|
|
f226f28e52 | ||
|
|
bad25e3397 | ||
|
|
964ef33fc7 | ||
|
|
c3fa1b45d0 | ||
|
|
602541b548 | ||
|
|
30018a3ab1 | ||
|
|
daf674e37b | ||
|
|
1f22dfda7b |
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@@ -16,7 +16,7 @@
|
|||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: '**/*.swsl'
|
- any-glob-to-any-file: '**/*.swsl'
|
||||||
|
|
||||||
"No C#":
|
"Changes: 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"
|
||||||
|
|||||||
@@ -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: "Merge Conflict"
|
dirtyLabel: "S: 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."
|
||||||
4
.github/workflows/labeler-needsreview.yml
vendored
4
.github/workflows/labeler-needsreview.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions-ecosystem/action-add-labels@v1
|
- uses: actions-ecosystem/action-add-labels@v1
|
||||||
with:
|
with:
|
||||||
labels: "Status: Needs Review"
|
labels: "S: Needs Review"
|
||||||
- uses: actions-ecosystem/action-remove-labels@v1
|
- uses: actions-ecosystem/action-remove-labels@v1
|
||||||
with:
|
with:
|
||||||
labels: "Status: Awaiting Changes"
|
labels: "S: Awaiting Changes"
|
||||||
|
|||||||
23
.github/workflows/labeler-review.yml
vendored
Normal file
23
.github/workflows/labeler-review.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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"
|
||||||
20
.github/workflows/labeler-size.yml
vendored
Normal file
20
.github/workflows/labeler-size.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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"
|
||||||
|
}
|
||||||
16
.github/workflows/labeler-stable.yml
vendored
Normal file
16
.github/workflows/labeler-stable.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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"
|
||||||
16
.github/workflows/labeler-staging.yml
vendored
Normal file
16
.github/workflows/labeler-staging.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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"
|
||||||
4
.github/workflows/labeler-untriaged.yml
vendored
4
.github/workflows/labeler-untriaged.yml
vendored
@@ -3,6 +3,8 @@
|
|||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [opened]
|
types: [opened]
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
add_label:
|
add_label:
|
||||||
@@ -11,4 +13,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: "Status: Untriaged"
|
labels: "S: Untriaged"
|
||||||
|
|||||||
@@ -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, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
|
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, 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 byte[]? Hwid { get; set; }
|
private ImmutableTypedHwid? 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,9 +371,8 @@ public sealed partial class BanPanel : DefaultWindow
|
|||||||
private void OnHwidChanged()
|
private void OnHwidChanged()
|
||||||
{
|
{
|
||||||
var hwidString = HwidLine.Text;
|
var hwidString = HwidLine.Text;
|
||||||
var length = 3 * (hwidString.Length / 4) - hwidString.TakeLast(2).Count(c => c == '=');
|
ImmutableTypedHwid? hwid = null;
|
||||||
Hwid = new byte[length];
|
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !ImmutableTypedHwid.TryParse(hwidString, out hwid))
|
||||||
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;
|
||||||
@@ -390,7 +389,7 @@ public sealed partial class BanPanel : DefaultWindow
|
|||||||
Hwid = null;
|
Hwid = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Hwid = Convert.FromHexString(hwidString);
|
Hwid = hwid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTypeChanged()
|
private void OnTypeChanged()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<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" />
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ 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)
|
||||||
@@ -31,6 +42,20 @@ 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);
|
||||||
@@ -172,8 +197,9 @@ 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 ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty;
|
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? 1.ToString() : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSecretPressed(BaseButton.ButtonEventArgs _)
|
private void OnSecretPressed(BaseButton.ButtonEventArgs _)
|
||||||
@@ -187,6 +213,16 @@ 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())
|
||||||
@@ -263,13 +299,24 @@ public sealed partial class NoteEdit : FancyWindow
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !DateTime.TryParse(ExpiryLineEdit.Text, out var result) || DateTime.UtcNow > result)
|
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !uint.TryParse(ExpiryLineEdit.Text, out var inputInt))
|
||||||
{
|
{
|
||||||
ExpiryLineEdit.ModulateSelfOverride = Color.Red;
|
ExpiryLineEdit.ModulateSelfOverride = Color.Red;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpiryTime = result.ToUniversalTime();
|
var mult = ExpiryLengthDropdown.SelectedId switch
|
||||||
|
{
|
||||||
|
(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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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;
|
||||||
|
|
||||||
@@ -24,8 +25,7 @@ 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,6 +47,16 @@ 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);
|
||||||
@@ -57,11 +67,6 @@ 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)
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ 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);
|
||||||
@@ -77,11 +78,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
|||||||
if (args.Sprite == null)
|
if (args.Sprite == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
|
UpdateAllSlots(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))
|
||||||
@@ -91,6 +88,23 @@ 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))
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io">
|
<DefaultWindow xmlns="https://spacestation14.io">
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
|
<BoxContainer Orientation="Vertical" MinWidth="243" 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 Orientation="Vertical" HorizontalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<Button Name="MenuGridViewButton" ToggleMode="True" Text="{Loc construction-menu-grid-view}"/>
|
||||||
|
<Button Name="FavoriteButton" Visible="false"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
|
|
||||||
<Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
|
|
||||||
HorizontalAlignment="Right" Margin="0 0 0 15"/>
|
|
||||||
<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">
|
||||||
|
|||||||
@@ -25,11 +25,16 @@ 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;
|
||||||
@@ -72,9 +77,16 @@ 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 = MinSize = new Vector2(720, 320);
|
SetSize = new Vector2(560, 450);
|
||||||
|
MinSize = new Vector2(560, 320);
|
||||||
|
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
@@ -102,6 +114,9 @@ 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;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
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;
|
||||||
@@ -11,7 +12,6 @@ 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,10 +33,12 @@ 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";
|
||||||
@@ -85,6 +87,7 @@ 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))
|
||||||
@@ -150,12 +153,24 @@ 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;
|
||||||
@@ -170,7 +185,7 @@ namespace Content.Client.Construction.UI
|
|||||||
if (recipe.Hide)
|
if (recipe.Hide)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!recipe.CrystallPunkAllowed) //CrystallPunk clearing recipes
|
if (!recipe.CrystallPunkAllowed) //CrystallEdge clearing recipes
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_playerManager.LocalSession == null
|
if (_playerManager.LocalSession == null
|
||||||
@@ -204,12 +219,73 @@ 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;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
foreach (var recipe in recipes)
|
||||||
{
|
{
|
||||||
recipesList.Add(GetItem(recipe, recipesList));
|
recipesList.Add(GetItem(recipe, recipesList));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There is apparently no way to set which
|
private void SelectGridButton(TextureButton button, bool select)
|
||||||
|
{
|
||||||
|
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)
|
||||||
@@ -260,11 +336,10 @@ 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, spriteSys.Frame0(prototype.Icon),
|
prototype.Name, prototype.Description, _spriteSystem.Frame0(prototype.Icon),
|
||||||
prototype.Type != ConstructionType.Item,
|
prototype.Type != ConstructionType.Item,
|
||||||
!_favoritedRecipes.Contains(prototype));
|
!_favoritedRecipes.Contains(prototype));
|
||||||
|
|
||||||
@@ -277,7 +352,6 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -293,20 +367,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 ? spriteSys.Frame0(entry.Icon) : Texture.Transparent;
|
var icon = entry.Icon != null ? _spriteSystem.Frame0(entry.Icon) : Texture.Transparent;
|
||||||
stepList.AddItem(text, icon, false);
|
stepList.AddItem(text, icon, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
|
private ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
|
||||||
{
|
{
|
||||||
return new(itemList)
|
return new(itemList)
|
||||||
{
|
{
|
||||||
Metadata = recipe,
|
Metadata = recipe,
|
||||||
Text = recipe.Name,
|
Text = recipe.Name,
|
||||||
Icon = recipe.Icon.Frame0(),
|
Icon = _spriteSystem.Frame0(recipe.Icon),
|
||||||
TooltipEnabled = true,
|
TooltipEnabled = true,
|
||||||
TooltipText = recipe.Description
|
TooltipText = recipe.Description,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
_menu?.Populate(crayonDecals.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnProtoReload(PrototypesReloadedEventArgs args)
|
public override void OnProtoReload(PrototypesReloadedEventArgs args)
|
||||||
@@ -44,6 +44,16 @@ 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);
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
Title="{Loc 'crayon-window-title'}"
|
Title="{Loc 'crayon-window-title'}"
|
||||||
MinSize="250 300"
|
MinSize="450 500"
|
||||||
SetSize="250 300">
|
SetSize="450 500">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<ColorSelectorSliders Name="ColorSelector" Visible="False" />
|
<ColorSelectorSliders Name="ColorSelector" Visible="False" />
|
||||||
<LineEdit Name="Search" />
|
<LineEdit Name="Search" Margin="0 0 0 8" PlaceHolder="{Loc 'crayon-window-placeholder'}" />
|
||||||
<ScrollContainer VerticalExpand="True">
|
<ScrollContainer VerticalExpand="True">
|
||||||
<GridContainer Name="Grid" Columns="6">
|
<BoxContainer Name="Grids" Orientation="Vertical">
|
||||||
<!-- Crayon decals get added here by code -->
|
</BoxContainer>
|
||||||
</GridContainer>
|
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</DefaultWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
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;
|
||||||
@@ -18,7 +20,12 @@ namespace Content.Client.Crayon.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class CrayonWindow : DefaultWindow
|
public sealed partial class CrayonWindow : DefaultWindow
|
||||||
{
|
{
|
||||||
private Dictionary<string, Texture>? _decals;
|
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -28,8 +35,10 @@ namespace Content.Client.Crayon.UI
|
|||||||
public CrayonWindow()
|
public CrayonWindow()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
|
||||||
|
|
||||||
Search.OnTextChanged += _ => RefreshList();
|
Search.OnTextChanged += SearchChanged;
|
||||||
ColorSelector.OnColorChanged += SelectColor;
|
ColorSelector.OnColorChanged += SelectColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,25 +53,60 @@ namespace Content.Client.Crayon.UI
|
|||||||
private void RefreshList()
|
private void RefreshList()
|
||||||
{
|
{
|
||||||
// Clear
|
// Clear
|
||||||
Grid.DisposeAllChildren();
|
Grids.DisposeAllChildren();
|
||||||
if (_decals == null)
|
|
||||||
|
if (_decals == null || _allDecals == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var filter = Search.Text;
|
var filter = Search.Text;
|
||||||
foreach (var (decal, tex) in _decals)
|
var comma = filter.IndexOf(',');
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
if (!decal.Contains(filter))
|
_selected = first;
|
||||||
|
_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
|
||||||
|
{
|
||||||
|
Text = locName
|
||||||
|
};
|
||||||
|
|
||||||
|
var grid = new GridContainer
|
||||||
|
{
|
||||||
|
Columns = 6,
|
||||||
|
Margin = new Thickness(0, 0, 0, 16)
|
||||||
|
};
|
||||||
|
|
||||||
|
Grids.AddChild(label);
|
||||||
|
Grids.AddChild(grid);
|
||||||
|
|
||||||
|
foreach (var (name, texture) in category)
|
||||||
|
{
|
||||||
var button = new TextureButton()
|
var button = new TextureButton()
|
||||||
{
|
{
|
||||||
TextureNormal = tex,
|
TextureNormal = texture,
|
||||||
Name = decal,
|
Name = name,
|
||||||
ToolTip = decal,
|
ToolTip = name,
|
||||||
Modulate = _color,
|
Modulate = _color,
|
||||||
|
Scale = new System.Numerics.Vector2(2, 2)
|
||||||
};
|
};
|
||||||
button.OnPressed += ButtonOnPressed;
|
button.OnPressed += ButtonOnPressed;
|
||||||
if (_selected == decal)
|
|
||||||
|
if (_selected == name)
|
||||||
{
|
{
|
||||||
var panelContainer = new PanelContainer()
|
var panelContainer = new PanelContainer()
|
||||||
{
|
{
|
||||||
@@ -75,20 +119,28 @@ namespace Content.Client.Crayon.UI
|
|||||||
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();
|
||||||
}
|
}
|
||||||
@@ -107,12 +159,38 @@ namespace Content.Client.Crayon.UI
|
|||||||
RefreshList();
|
RefreshList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Populate(IEnumerable<DecalPrototype> prototypes)
|
public void AdvanceState(string drawnDecal)
|
||||||
{
|
{
|
||||||
_decals = new Dictionary<string, Texture>();
|
var filter = Search.Text;
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
_decals.Add(decalPrototype.ID, decalPrototype.Sprite.Frame0());
|
var category = "random";
|
||||||
|
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();
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ 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;
|
||||||
@@ -132,3 +136,9 @@ 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);
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace Content.Client.Entry
|
|||||||
_clientPreferencesManager.Initialize();
|
_clientPreferencesManager.Initialize();
|
||||||
_euiManager.Initialize();
|
_euiManager.Initialize();
|
||||||
_voteManager.Initialize();
|
_voteManager.Initialize();
|
||||||
_userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
|
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme");
|
||||||
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
|
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
|
||||||
_documentParsingManager.Initialize();
|
_documentParsingManager.Initialize();
|
||||||
_titleWindowManager.Initialize();
|
_titleWindowManager.Initialize();
|
||||||
|
|||||||
@@ -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; //CrystallPunk guidebook filter
|
if (!entry.CrystallPunkAllowed) continue; //CrystallEdge guidebook filter
|
||||||
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallPunk guidebook filter
|
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallEdge guidebook filter
|
||||||
|
|
||||||
AddEntry(entry.Id, parent, addedEntries);
|
AddEntry(entry.Id, parent, addedEntries);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!; //CrystallPunk guidebook filter
|
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallEdge 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>(OnCrystallPunkMapInit); //CrystallPunk guidebook filter
|
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallEdgeMapInit); //CrystallEdge 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//CrystallPunk guidebook filter
|
//CrystallEdge guidebook filter
|
||||||
private void OnCrystallPunkMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
|
private void OnCrystallEdgeMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
foreach (var guide in ent.Comp.Guides)
|
foreach (var guide in ent.Comp.Guides)
|
||||||
{
|
{
|
||||||
var guideProto = _proto.Index<GuideEntryPrototype>(guide);
|
var guideProto = _proto.Index(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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//CrystallPunk guidebook filter end
|
//CrystallEdge 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
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ 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") };
|
||||||
|
|||||||
@@ -235,9 +235,23 @@ 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 readonly SlotDefinition SlotDef;
|
public SlotDefinition SlotDef;
|
||||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||||
public bool Blocked;
|
public bool Blocked;
|
||||||
public bool Highlighted;
|
public bool Highlighted;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ 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;
|
||||||
@@ -29,10 +30,13 @@ 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;
|
||||||
@@ -51,6 +55,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +204,8 @@ 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
|
||||||
if (entity != null && slotDef.StripHidden)
|
// this does not work for modified clients because they are still sent the real entity
|
||||||
|
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));
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
|||||||
|
|
||||||
_profileEditor.OnOpenGuidebook += _guide.OpenHelp;
|
_profileEditor.OnOpenGuidebook += _guide.OpenHelp;
|
||||||
|
|
||||||
_characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
|
_characterSetup = new CharacterSetupGui(_profileEditor);
|
||||||
|
|
||||||
_characterSetup.CloseButton.OnPressed += _ =>
|
_characterSetup.CloseButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
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" />
|
||||||
@@ -10,10 +11,15 @@
|
|||||||
<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"/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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;
|
||||||
@@ -8,6 +9,7 @@ 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
|
||||||
@@ -18,28 +20,23 @@ namespace Content.Client.Lobby.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class CharacterSetupGui : Control
|
public sealed partial class CharacterSetupGui : Control
|
||||||
{
|
{
|
||||||
private readonly IClientPreferencesManager _preferencesManager;
|
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||||
private readonly IEntityManager _entManager;
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
private readonly IPrototypeManager _protomanager;
|
[Dependency] private readonly IPrototypeManager _protomanager = default!;
|
||||||
|
[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(
|
public CharacterSetupGui(HumanoidProfileEditor profileEditor)
|
||||||
IEntityManager entManager,
|
|
||||||
IPrototypeManager protoManager,
|
|
||||||
IResourceCache resourceCache,
|
|
||||||
IClientPreferencesManager preferencesManager,
|
|
||||||
HumanoidProfileEditor profileEditor)
|
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_preferencesManager = preferencesManager;
|
IoCManager.InjectDependencies(this);
|
||||||
_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,
|
||||||
@@ -56,7 +53,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();
|
||||||
};
|
};
|
||||||
@@ -65,6 +62,8 @@ 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>
|
||||||
|
|||||||
@@ -36,19 +36,20 @@ public sealed partial class LoadoutContainer : BoxContainer
|
|||||||
|
|
||||||
if (_protoManager.TryIndex(proto, out var loadProto))
|
if (_protoManager.TryIndex(proto, out var loadProto))
|
||||||
{
|
{
|
||||||
var ent = _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
|
var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
|
||||||
|
|
||||||
|
if (ent == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (ent != null)
|
|
||||||
{
|
|
||||||
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
|
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
|
||||||
Sprite.SetEntity(_entity);
|
Sprite.SetEntity(_entity);
|
||||||
|
|
||||||
var spriteTooltip = new Tooltip();
|
var spriteTooltip = new Tooltip();
|
||||||
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
|
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
|
||||||
|
|
||||||
TooltipSupplier = _ => spriteTooltip;
|
TooltipSupplier = _ => spriteTooltip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ 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;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ 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;
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
|
|||||||
args.Components.Add(component);
|
args.Components.Add(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshOverlay(EntityUid uid)
|
protected void RefreshOverlay(EntityUid uid)
|
||||||
{
|
{
|
||||||
if (uid != _player.LocalSession?.AttachedEntity)
|
if (uid != _player.LocalSession?.AttachedEntity)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -21,9 +21,16 @@ 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);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ 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()
|
||||||
@@ -24,6 +25,7 @@ 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)
|
||||||
@@ -43,6 +45,11 @@ 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)
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
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;
|
||||||
@@ -14,6 +17,8 @@ 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()
|
||||||
{
|
{
|
||||||
@@ -135,4 +140,15 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
@@ -10,14 +13,20 @@ 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)
|
||||||
@@ -25,9 +34,30 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ 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 control = new BorgModuleControl(module, _entity);
|
var moduleComponent = _entity.GetComponent<BorgModuleComponent>(module);
|
||||||
|
var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule);
|
||||||
control.RemoveButtonPressed += () =>
|
control.RemoveButtonPressed += () =>
|
||||||
{
|
{
|
||||||
RemoveModuleButtonPressed?.Invoke(module);
|
RemoveModuleButtonPressed?.Invoke(module);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public sealed partial class BorgModuleControl : PanelContainer
|
|||||||
{
|
{
|
||||||
public Action? RemoveButtonPressed;
|
public Action? RemoveButtonPressed;
|
||||||
|
|
||||||
public BorgModuleControl(EntityUid entity, IEntityManager entityManager)
|
public BorgModuleControl(EntityUid entity, IEntityManager entityManager, bool canRemove)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ public sealed partial class BorgModuleControl : PanelContainer
|
|||||||
{
|
{
|
||||||
RemoveButtonPressed?.Invoke();
|
RemoveButtonPressed?.Invoke();
|
||||||
};
|
};
|
||||||
|
RemoveButton.Visible = canRemove;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml
Normal file
43
Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<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>
|
||||||
81
Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs
Normal file
81
Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Content.Client/Silicons/Borgs/BorgSelectTypeUserInterface.cs
Normal file
30
Content.Client/Silicons/Borgs/BorgSelectTypeUserInterface.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
81
Content.Client/Silicons/Borgs/BorgSwitchableTypeSystem.cs
Normal file
81
Content.Client/Silicons/Borgs/BorgSwitchableTypeSystem.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,4 +92,18 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.EntitySystems;
|
namespace Content.Client.Singularity.Systems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The client-side version of <see cref="SharedEventHorizonSystem"/>.
|
/// The client-side version of <see cref="SharedEventHorizonSystem"/>.
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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
|
||||||
|
{}
|
||||||
@@ -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.EntitySystems;
|
namespace Content.Client.Singularity.Systems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The client-side version of <see cref="SharedSingularitySystem"/>.
|
/// The client-side version of <see cref="SharedSingularitySystem"/>.
|
||||||
|
|||||||
@@ -307,12 +307,6 @@ 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();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public enum WeaponArcAnimation : byte
|
|||||||
None,
|
None,
|
||||||
Thrust,
|
Thrust,
|
||||||
Slash,
|
Slash,
|
||||||
//CrystallPunk Melee upgrade
|
//CrystallEdge Melee upgrade
|
||||||
CPSlash,
|
CPSlash,
|
||||||
CPThrust
|
CPThrust
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public sealed partial class MeleeWeaponSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var length = 1f; //CrystallPunk Melee upgrade
|
var length = 1f; //CrystallEdgeMelee upgrade
|
||||||
var offset = -1f; //CrystallPunk Melee upgrade
|
var offset = -1f; //CrystallEdge 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; //CrystallPunk Melee upgrade
|
length = meleeWeaponComponent.CPAnimationLength; //CrystallEdge Melee upgrade
|
||||||
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallPunk Melee upgrade
|
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallEdge 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;
|
||||||
//CrystallPunk MeleeUpgrade
|
//CrystallEdge 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;
|
||||||
//CrystallPunk MeleeUpgrade end
|
//CrystallEdge 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, CrystallPunk update
|
const float length = 0.2f; // 0.1 original, CrystallEdge 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), //CrystallPunk MeleeUpgrade
|
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallEdge MeleeUpgrade
|
||||||
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallPunk MeleeUpgrade
|
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallEdge MeleeUpgrade
|
||||||
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallPunk MeleeUpgrade
|
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallEdge MeleeUpgrade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ public sealed partial class MeleeWeaponSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//CrystallPunk MeleeUpgrade start
|
//CrystallEdge 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
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//CrystallPunk MeleeUpgrade end
|
//CrystallEdge MeleeUpgrade end
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.BurstActivated)
|
||||||
{
|
{
|
||||||
if (gun.ShotCounter != 0)
|
if (gun.ShotCounter != 0)
|
||||||
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
|
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using Content.Shared._CP14.Temperature;
|
||||||
|
|
||||||
|
namespace Content.Client._CP14.Temperature;
|
||||||
|
|
||||||
|
public sealed partial class CP14ClientFireSpreadSystem : CP14SharedFireSpreadSystem
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ 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()
|
||||||
{
|
{
|
||||||
@@ -123,6 +124,6 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
});
|
});
|
||||||
await pair.CleanReturnAsync();
|
await pair.CleanReturnAsync();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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), Is.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Is.Empty);
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, 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), Is.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Is.Empty);
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, 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), Is.Not.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Has.Count.EqualTo(1));
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, 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), Is.Not.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Has.Count.EqualTo(1));
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, 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), Is.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Has.Count.EqualTo(1));
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, 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), Is.Null);
|
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, 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), Has.Count.EqualTo(1));
|
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reconnect client. Slightly faster than dirtying the pair.
|
// Reconnect client. Slightly faster than dirtying the pair.
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
";
|
";*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ namespace Content.IntegrationTests.Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static readonly string[] GameMaps =
|
private static readonly string[] GameMaps =
|
||||||
{//CrystallPunk Map replacement
|
{//CrystallEdge Map replacement
|
||||||
"Dev",
|
"Dev",
|
||||||
"CentComm",
|
"CentComm",
|
||||||
"MeteorArena",
|
"MeteorArena",
|
||||||
|
|
||||||
//CrystallPunk maps
|
//CrystallEdge maps
|
||||||
"Village",
|
"Village",
|
||||||
"Island",
|
"Island",
|
||||||
//CrystallPunk Map replacement end
|
//CrystallEdge Map replacement end
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2072
Content.Server.Database/Migrations/Postgres/20241111170112_ModernHwid.Designer.cs
generated
Normal file
2072
Content.Server.Database/Migrations/Postgres/20241111170112_ModernHwid.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2076
Content.Server.Database/Migrations/Postgres/20241111193608_ConnectionTrust.Designer.cs
generated
Normal file
2076
Content.Server.Database/Migrations/Postgres/20241111193608_ConnectionTrust.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -512,20 +512,6 @@ 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")
|
||||||
@@ -571,6 +557,19 @@ 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")
|
||||||
@@ -589,10 +588,6 @@ 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")
|
||||||
@@ -603,6 +598,10 @@ 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");
|
||||||
@@ -718,10 +717,6 @@ 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");
|
||||||
@@ -1058,10 +1053,6 @@ 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");
|
||||||
@@ -1192,10 +1183,6 @@ 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");
|
||||||
@@ -1637,6 +1624,34 @@ 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");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1652,6 +1667,37 @@ 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")
|
||||||
@@ -1746,8 +1792,36 @@ 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");
|
||||||
@@ -1795,8 +1869,36 @@ 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");
|
||||||
|
|||||||
1995
Content.Server.Database/Migrations/Sqlite/20241111170107_ModernHwid.Designer.cs
generated
Normal file
1995
Content.Server.Database/Migrations/Sqlite/20241111170107_ModernHwid.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1999
Content.Server.Database/Migrations/Sqlite/20241111193602_ConnectionTrust.Designer.cs
generated
Normal file
1999
Content.Server.Database/Migrations/Sqlite/20241111193602_ConnectionTrust.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -483,19 +483,6 @@ 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")
|
||||||
@@ -539,6 +526,19 @@ 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,10 +555,6 @@ 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")
|
||||||
@@ -569,6 +565,10 @@ 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,10 +675,6 @@ 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");
|
||||||
@@ -996,10 +992,6 @@ 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");
|
||||||
@@ -1124,10 +1116,6 @@ 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");
|
||||||
@@ -1559,6 +1547,34 @@ 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");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1574,6 +1590,37 @@ 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")
|
||||||
@@ -1668,8 +1715,36 @@ 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");
|
||||||
@@ -1717,8 +1792,36 @@ 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");
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
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;
|
||||||
@@ -327,6 +329,47 @@ 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)
|
||||||
@@ -519,7 +562,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 byte[]? LastSeenHWId { get; set; }
|
public TypedHwid? 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!;
|
||||||
@@ -668,7 +711,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; }
|
||||||
byte[]? HWId { get; set; }
|
TypedHwid? 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; }
|
||||||
@@ -753,7 +796,7 @@ namespace Content.Server.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hardware ID of the banned player.
|
/// Hardware ID of the banned player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? HWId { get; set; }
|
public TypedHwid? 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.
|
||||||
@@ -891,7 +934,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 byte[]? HWId { get; set; }
|
public TypedHwid? HWId { get; set; }
|
||||||
|
|
||||||
public ConnectionDenyReason? Denied { get; set; }
|
public ConnectionDenyReason? Denied { get; set; }
|
||||||
|
|
||||||
@@ -908,6 +951,8 @@ 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
|
||||||
@@ -945,7 +990,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 byte[]? HWId { get; set; }
|
public TypedHwid? HWId { get; set; }
|
||||||
|
|
||||||
public DateTime BanTime { get; set; }
|
public DateTime BanTime { get; set; }
|
||||||
|
|
||||||
@@ -1206,4 +1251,37 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace Content.Server.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SnakeCaseConvention :
|
public partial class SnakeCaseConvention :
|
||||||
IEntityTypeAddedConvention,
|
IEntityTypeAddedConvention,
|
||||||
IEntityTypeAnnotationChangedConvention,
|
IEntityTypeAnnotationChangedConvention,
|
||||||
IPropertyAddedConvention,
|
IPropertyAddedConvention,
|
||||||
@@ -99,8 +99,8 @@ namespace Content.Server.Database
|
|||||||
|
|
||||||
public static string RewriteName(string name)
|
public static string RewriteName(string name)
|
||||||
{
|
{
|
||||||
var regex = new Regex("[A-Z]+", RegexOptions.Compiled);
|
return UpperCaseLocator()
|
||||||
return regex.Replace(
|
.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")) {
|
||||||
@@ -112,6 +112,11 @@ namespace Content.Server.Database
|
|||||||
return match.Value.ToLower();
|
return match.Value.ToLower();
|
||||||
if (match.Length > 1)
|
if (match.Length > 1)
|
||||||
return $"_{match.Value[..^1].ToLower()}_{match.Value[^1..^0].ToLower()}";
|
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();
|
return "_" + match.Value.ToLower();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -332,5 +337,8 @@ namespace Content.Server.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex("[A-Z]+", RegexOptions.Compiled)]
|
||||||
|
private static partial Regex UpperCaseLocator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.VowAlert);
|
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert);
|
||||||
_alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
|
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert);
|
||||||
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
|
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
foreach (var ban in await _db.GetServerBansAsync(null, userId, null, 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 == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan());
|
hwid = ban.HWId?.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
foreach (var ban in await _db.GetServerRoleBansAsync(null, userId, null, 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 == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan());
|
hwid = ban.HWId?.ToString();
|
||||||
}
|
}
|
||||||
RoleBans.Add(new SharedServerRoleBan(
|
RoleBans.Add(new SharedServerRoleBan(
|
||||||
ban.Id,
|
ban.Id,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
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;
|
||||||
@@ -8,7 +7,6 @@ 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;
|
||||||
@@ -27,7 +25,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 ImmutableArray<byte>? LastHwid { get; set; }
|
private ImmutableTypedHwid? 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;
|
||||||
|
|
||||||
@@ -51,7 +49,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?.ToImmutableArray(), r.UseLastHwid, r.Minutes, r.Severity, r.Reason, r.Roles, r.Erase);
|
BanPlayer(r.Player, r.IpAddress, r.UseLastIp, r.Hwid, 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);
|
||||||
@@ -59,7 +57,7 @@ public sealed class BanPanelEui : BaseEui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
if (!_admins.HasAdminFlag(Player, AdminFlags.Ban))
|
if (!_admins.HasAdminFlag(Player, AdminFlags.Ban))
|
||||||
{
|
{
|
||||||
@@ -155,7 +153,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, ImmutableArray<byte>? lastHwid)
|
public void ChangePlayer(NetUserId? playerId, string playerName, IPAddress? lastAddress, ImmutableTypedHwid? lastHwid)
|
||||||
{
|
{
|
||||||
PlayerId = playerId;
|
PlayerId = playerId;
|
||||||
PlayerName = playerName;
|
PlayerName = playerName;
|
||||||
|
|||||||
@@ -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.LastHWId, false);
|
var bans = await _dbManager.GetServerBansAsync(data.LastAddress, data.UserId, data.LastLegacyHWId, data.LastModernHWIds, false);
|
||||||
|
|
||||||
if (bans.Count == 0)
|
if (bans.Count == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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.LastHWId, includeUnbanned);
|
var bans = await _dbManager.GetServerRoleBansAsync(data.LastAddress, data.UserId, data.LastLegacyHWId, data.LastModernHWIds, includeUnbanned);
|
||||||
|
|
||||||
if (bans.Count == 0)
|
if (bans.Count == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ 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 roleBans = await _db.GetServerRoleBansAsync(netChannel.RemoteEndPoint.Address, player.UserId, hwId, false);
|
var modernHwids = netChannel.UserData.ModernHWIds;
|
||||||
|
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)
|
||||||
@@ -132,7 +133,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, ImmutableArray<byte>? hwid, uint? minutes, NoteSeverity severity, string reason)
|
public async void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? hwid, uint? minutes, NoteSeverity severity, string reason)
|
||||||
{
|
{
|
||||||
DateTimeOffset? expires = null;
|
DateTimeOffset? expires = null;
|
||||||
if (minutes > 0)
|
if (minutes > 0)
|
||||||
@@ -166,9 +167,7 @@ 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 != null
|
var hwidString = hwid?.ToString() ?? "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";
|
||||||
@@ -208,6 +207,7 @@ 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, ImmutableArray<byte>? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan)
|
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)
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex(role, out JobPrototype? _))
|
if (!_prototypeManager.TryIndex(role, out JobPrototype? _))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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, ImmutableArray<byte>? hwid, uint? minutes, NoteSeverity severity, string reason);
|
public void CreateServerBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? 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, ImmutableArray<byte>? hwid, string role, uint? minutes, NoteSeverity severity, string reason, DateTimeOffset timeOfBan);
|
public void CreateRoleBan(NetUserId? target, string? targetUsername, NetUserId? banningAdmin, (IPAddress, int)? addressRange, ImmutableTypedHwid? 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
|
||||||
|
|||||||
@@ -5,16 +5,42 @@ 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
|
||||||
{
|
{
|
||||||
public sealed record LocatedPlayerData(NetUserId UserId, IPAddress? LastAddress, ImmutableArray<byte>? LastHWId, string Username);
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
@@ -67,63 +93,42 @@ 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 new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId, record.LastSeenUserName);
|
return ReturnForPlayerRecord(record);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
if (resp.StatusCode == HttpStatusCode.NotFound)
|
return await HandleAuthServerResponse(resp, cancel);
|
||||||
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?> LookupIdAsync(NetUserId userId, CancellationToken cancel = default)
|
public async Task<LocatedPlayerData?> LookupIdAsync(NetUserId userId, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
// Check people currently on the server, the easiest case.
|
// Check people currently on the server, the easiest case.
|
||||||
if (_playerManager.TryGetSessionById(userId, out var session))
|
if (_playerManager.TryGetSessionById(userId, out var session))
|
||||||
{
|
return ReturnForSession(session);
|
||||||
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.GetPlayerRecordByUserId(userId, cancel);
|
var record = await _db.GetPlayerRecordByUserId(userId, cancel);
|
||||||
if (record != null)
|
if (record != null)
|
||||||
return new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId, record.LastSeenUserName);
|
return ReturnForPlayerRecord(record);
|
||||||
|
|
||||||
// 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/userid?userid={WebUtility.UrlEncode(userId.UserId.ToString())}";
|
var requestUri = $"{authServer}api/query/userid?userid={WebUtility.UrlEncode(userId.UserId.ToString())}";
|
||||||
using var resp = await _httpClient.GetAsync(requestUri, cancel);
|
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;
|
||||||
|
|
||||||
@@ -134,14 +139,40 @@ 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);
|
return new LocatedPlayerData(new NetUserId(responseData.UserId), null, null, responseData.UserName, null, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LocatedPlayerData ReturnForSession(ICommonSession session)
|
||||||
|
{
|
||||||
|
var userId = session.UserId;
|
||||||
|
var address = session.Channel.RemoteEndPoint.Address;
|
||||||
|
var hwId = session.Channel.UserData.GetModernHwid();
|
||||||
|
return new LocatedPlayerData(
|
||||||
|
userId,
|
||||||
|
address,
|
||||||
|
hwId,
|
||||||
|
session.Name,
|
||||||
|
session.Channel.UserData.HWId,
|
||||||
|
session.Channel.UserData.ModernHWIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LocatedPlayerData ReturnForPlayerRecord(PlayerRecord record)
|
||||||
|
{
|
||||||
|
var hwid = record.HWId;
|
||||||
|
|
||||||
|
return new LocatedPlayerData(
|
||||||
|
record.UserId,
|
||||||
|
record.LastSeenAddress,
|
||||||
|
hwid,
|
||||||
|
record.LastSeenUserName,
|
||||||
|
hwid is { Type: HwidType.Legacy } ? hwid.Hwid : null,
|
||||||
|
hwid is { Type: HwidType.Modern } ? [hwid.Hwid] : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default)
|
public async Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default)
|
||||||
|
|||||||
@@ -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)).Count;
|
_bans = (await _db.GetServerBansAsync(null, _targetPlayer.UserId, null, 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)).DistinctBy(rb => rb.BanTime).Count();
|
_roleBans = (await _db.GetServerRoleBansAsync(null, _targetPlayer.UserId, null, null)).DistinctBy(rb => rb.BanTime).Count();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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;
|
||||||
|
|||||||
@@ -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);
|
var ban = await _dbManager.GetServerBanAsync(null, e.Session.UserId, null, 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));
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
using Content.Server.Administration.Components;
|
using Content.Server.Administration.Components;
|
||||||
using Content.Shared.Climbing.Components;
|
using Content.Shared.Climbing.Components;
|
||||||
using Content.Shared.Climbing.Events;
|
using Content.Shared.Clumsy;
|
||||||
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 BonkSystem _bonkSystem = default!;
|
[Dependency] private readonly ClumsySystem _clumsySystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
|
|
||||||
SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
|
SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
|
SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false)
|
public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false)
|
||||||
@@ -31,7 +31,6 @@ 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>();
|
||||||
@@ -79,16 +78,17 @@ 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))
|
if (!HasComp<TransformComponent>(uid) || !TryComp<ClumsyComponent>(comp.Target, out var clumsyComp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates);
|
_transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates);
|
||||||
|
|
||||||
_bonkSystem.TryBonk(comp.Target, uid, bonkComp);
|
_clumsySystem.HitHeadClumsy((comp.Target, clumsyComp), uid);
|
||||||
|
|
||||||
|
_audioSystem.PlayPvs(clumsyComp.TableBonkSound, comp.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args)
|
private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args)
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ 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,
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ namespace Content.Server.Announcements
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var message = string.Join(' ', new ArraySegment<string>(args, 1, args.Length-1));
|
// Explicit IEnumerable<string> due to overload ambiguity on .NET 9
|
||||||
|
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!");
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ 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);
|
||||||
@@ -182,7 +184,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var players = _playerManager.Sessions
|
var players = _playerManager.Sessions
|
||||||
.Where(x => GameTicker.PlayerGameStatuses[x.UserId] == PlayerGameStatus.JoinedGame)
|
.Where(x => GameTicker.PlayerGameStatuses.TryGetValue(x.UserId, out var status) && status == PlayerGameStatus.JoinedGame)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
ChooseAntags((uid, component), players, midround: true);
|
ChooseAntags((uid, component), players, midround: true);
|
||||||
@@ -360,6 +362,8 @@ 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);
|
||||||
|
|||||||
@@ -84,9 +84,15 @@ namespace Content.Server.Atmos.Components
|
|||||||
public ProtoId<AlertPrototype> FireAlert = "Fire";
|
public ProtoId<AlertPrototype> FireAlert = "Fire";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CrystallPunk fireplace fuel
|
/// CrystallEdge 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
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;
|
||||||
@@ -6,6 +5,7 @@ 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,15 +144,16 @@ 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)
|
||||||
@@ -263,6 +264,19 @@ 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;
|
||||||
|
|
||||||
@@ -316,12 +330,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,11 +351,6 @@ 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);
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ public sealed partial class AtmosMonitorComponent : Component
|
|||||||
[DataField("gasThresholds")]
|
[DataField("gasThresholds")]
|
||||||
public Dictionary<Gas, AtmosAlarmThreshold>? GasThresholds;
|
public Dictionary<Gas, AtmosAlarmThreshold>? GasThresholds;
|
||||||
|
|
||||||
// Stores a reference to the gas on the tile this is on.
|
/// <summary>
|
||||||
|
/// 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;
|
||||||
|
|
||||||
@@ -65,4 +67,19 @@ 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";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ 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;
|
||||||
@@ -25,6 +28,7 @@ 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";
|
||||||
@@ -56,8 +60,15 @@ 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)
|
||||||
@@ -215,6 +226,10 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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;
|
||||||
@@ -14,7 +15,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); //CrystallPunk bonfire moment
|
SubscribeLocalEvent<CP14FlammableAmbientSoundComponent, OnFireChangedEvent>(OnFireChanged); //CrystallEdge bonfire moment
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args)
|
private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args)
|
||||||
@@ -27,10 +28,10 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
|
|||||||
SetAmbience(uid, args.Powered);
|
SetAmbience(uid, args.Powered);
|
||||||
}
|
}
|
||||||
|
|
||||||
//CrystallPunk bonfire moment
|
//CrystallEdge 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);
|
||||||
}
|
}
|
||||||
//CrystallPunk bonfire moment end
|
//CrystallEdge bonfire moment end
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user