Compare commits
503 Commits
ed-27-06-2
...
ed-18-07-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b63f054245 | ||
|
|
eeecbbfd57 | ||
|
|
2eaa917afd | ||
|
|
eba7d2de0d | ||
|
|
fb7ca28b9a | ||
|
|
02275a0237 | ||
|
|
6f5077803b | ||
|
|
be9acaea35 | ||
|
|
ba2c5fcded | ||
|
|
b20fd4fbd0 | ||
|
|
0e02c50548 | ||
|
|
6443c53a8c | ||
|
|
1ac7739564 | ||
|
|
1fd8369a9c | ||
|
|
d8ab4982ad | ||
|
|
11320f4d2c | ||
|
|
13bec7a0e9 | ||
|
|
8d99961a00 | ||
|
|
8db252e7dc | ||
|
|
21d48ca5c4 | ||
|
|
93e4bfcfb3 | ||
|
|
db3f304f4b | ||
|
|
2e3d2db97e | ||
|
|
927cf7799f | ||
|
|
911a94dba9 | ||
|
|
8cbd26ae2f | ||
|
|
2de26baebd | ||
|
|
c69fff0bb9 | ||
|
|
09a05955d7 | ||
|
|
33a303236c | ||
|
|
b35539db4a | ||
|
|
dbc8c1b4d7 | ||
|
|
c0593fb328 | ||
|
|
eb3b2ae01a | ||
|
|
028c1ee478 | ||
|
|
b7d3964c56 | ||
|
|
17c23f11c5 | ||
|
|
3b85b1e43e | ||
|
|
35cd013e88 | ||
|
|
f6d827f5d9 | ||
|
|
b6115b672a | ||
|
|
a0052c5b09 | ||
|
|
1c74ffb8e4 | ||
|
|
7d9653fff7 | ||
|
|
f90538cca7 | ||
|
|
07535e8ecf | ||
|
|
4f479b6c85 | ||
|
|
919b3ac9e6 | ||
|
|
011250f35e | ||
|
|
960cc806cc | ||
|
|
bdf7293cfb | ||
|
|
922be64290 | ||
|
|
5d1702d280 | ||
|
|
68982953f3 | ||
|
|
87467a358b | ||
|
|
a06309b964 | ||
|
|
85fba9809a | ||
|
|
f687124312 | ||
|
|
b7aa97e203 | ||
|
|
a03b88979e | ||
|
|
c1915c9d73 | ||
|
|
5e800e0ece | ||
|
|
bf4ef62ab3 | ||
|
|
dcb3443b35 | ||
|
|
22a9290c5b | ||
|
|
1b0c434a9f | ||
|
|
87c82ff114 | ||
|
|
6c1d1057d5 | ||
|
|
ac768fe9f1 | ||
|
|
87f7ea8aa9 | ||
|
|
044d84142c | ||
|
|
eb4ce85354 | ||
|
|
49096cf14f | ||
|
|
361ec59412 | ||
|
|
f969fd2bfb | ||
|
|
cb98b659ad | ||
|
|
7b590122b6 | ||
|
|
87fa6075b6 | ||
|
|
3388c0dcaa | ||
|
|
de2ab29f34 | ||
|
|
e11f1e6cf6 | ||
|
|
3acc100ae5 | ||
|
|
b94b52396e | ||
|
|
1b360ac914 | ||
|
|
55a50d0426 | ||
|
|
162348e02d | ||
|
|
8ed9ea1586 | ||
|
|
5fa0844f3c | ||
|
|
a1000587cf | ||
|
|
2e694f109d | ||
|
|
97aa8ff701 | ||
|
|
c94c72785d | ||
|
|
e3697c6fda | ||
|
|
a314a967c2 | ||
|
|
3ee7d7bc35 | ||
|
|
7ce3a1f27f | ||
|
|
caf8776d07 | ||
|
|
560df6ed97 | ||
|
|
4f24b30b22 | ||
|
|
2ef4402068 | ||
|
|
0931c9e7d1 | ||
|
|
b5e49c9c07 | ||
|
|
f53d0143ae | ||
|
|
a8cae6f3e6 | ||
|
|
160364e100 | ||
|
|
b6672f087f | ||
|
|
65ccd6e033 | ||
|
|
00ec83af0f | ||
|
|
f125dda677 | ||
|
|
3a9b1eaa16 | ||
|
|
cd90b414df | ||
|
|
00a2c6a234 | ||
|
|
e87994ae40 | ||
|
|
4945e6a61c | ||
|
|
e3bb2771d6 | ||
|
|
8fd35e8e44 | ||
|
|
bb67364900 | ||
|
|
9a17154d83 | ||
|
|
03f0257ae9 | ||
|
|
e6f55fafb4 | ||
|
|
02636386b5 | ||
|
|
e45f55e36d | ||
|
|
1a50760e67 | ||
|
|
1ea7e3e71f | ||
|
|
eae04129cf | ||
|
|
3ebfe468ca | ||
|
|
19a06b6cc0 | ||
|
|
6371a04621 | ||
|
|
e01af4d602 | ||
|
|
4d4f67132c | ||
|
|
24a2866747 | ||
|
|
8340686078 | ||
|
|
adcbe8d0be | ||
|
|
2df65f10f5 | ||
|
|
b014d4d0e0 | ||
|
|
939f0f4b27 | ||
|
|
6f6bc38a55 | ||
|
|
ee59ae91ec | ||
|
|
8aecd663f8 | ||
|
|
a5ec01792b | ||
|
|
91740ef5be | ||
|
|
56fb8c832e | ||
|
|
a1f2df0b2c | ||
|
|
e8b3042a38 | ||
|
|
8d48096c57 | ||
|
|
a0165773a4 | ||
|
|
3f2793c179 | ||
|
|
eef6f92012 | ||
|
|
d3642c7383 | ||
|
|
c57009b646 | ||
|
|
7a66da31c7 | ||
|
|
d3495fc51c | ||
|
|
93197b6cce | ||
|
|
edf8c6cb4a | ||
|
|
2349fb485e | ||
|
|
742290c606 | ||
|
|
bb82b4cd6f | ||
|
|
1ac9ec85c5 | ||
|
|
82f1ed1493 | ||
|
|
49128ba9d3 | ||
|
|
b511d8e180 | ||
|
|
c9be1ef96b | ||
|
|
245c99cc78 | ||
|
|
8c598799b4 | ||
|
|
62d8665484 | ||
|
|
7bf77beb9e | ||
|
|
7e087a6eb8 | ||
|
|
04cb2657bf | ||
|
|
f3342c5155 | ||
|
|
061ec432ff | ||
|
|
74d9ac7241 | ||
|
|
ba03872c57 | ||
|
|
9bf3c33cca | ||
|
|
08b12f34b3 | ||
|
|
8bd8787819 | ||
|
|
8dde49db95 | ||
|
|
c7f752dc96 | ||
|
|
f12b395f2a | ||
|
|
149b6a89ca | ||
|
|
40f735acb1 | ||
|
|
f42546e0c6 | ||
|
|
451d04d759 | ||
|
|
d6c4ebdd37 | ||
|
|
92e2980534 | ||
|
|
c8a87ceaab | ||
|
|
f6d093ef5c | ||
|
|
8c3e72c8c8 | ||
|
|
5ae2590667 | ||
|
|
eab93cb09e | ||
|
|
04249e8682 | ||
|
|
ed7f00692e | ||
|
|
21d0f85cc2 | ||
|
|
ff93070d25 | ||
|
|
70b56136aa | ||
|
|
437f6f451a | ||
|
|
13b84870ec | ||
|
|
71b7dddb59 | ||
|
|
0e9ed36b85 | ||
|
|
063c5de985 | ||
|
|
f50488d7e3 | ||
|
|
c9c721be16 | ||
|
|
8e1547e616 | ||
|
|
20d6ccffdb | ||
|
|
336f264c77 | ||
|
|
23887d5bd9 | ||
|
|
d9be666e8a | ||
|
|
18df27d8e7 | ||
|
|
0098d71717 | ||
|
|
60ef7848fb | ||
|
|
fa6d6806d1 | ||
|
|
5cd7cf182a | ||
|
|
b6d6e2de8c | ||
|
|
b4b63ed898 | ||
|
|
d9ed4a63df | ||
|
|
f8b6bc7243 | ||
|
|
205aae364c | ||
|
|
b418338af7 | ||
|
|
34f36665a6 | ||
|
|
7ae3e353ea | ||
|
|
7b99d1f851 | ||
|
|
12edad89e8 | ||
|
|
4c5c6a84dc | ||
|
|
84ff5e334b | ||
|
|
24c47c805d | ||
|
|
11034a0986 | ||
|
|
b0ae7d5725 | ||
|
|
cc9e5f68da | ||
|
|
ead0c375f6 | ||
|
|
8adcb37964 | ||
|
|
01f97a8aaa | ||
|
|
d9fc93e0c5 | ||
|
|
3182447fbf | ||
|
|
8e05e1cfed | ||
|
|
bc7c121713 | ||
|
|
9280ca8830 | ||
|
|
b7e2d66557 | ||
|
|
a9cb687899 | ||
|
|
b1a2aaf1f5 | ||
|
|
bd011bf418 | ||
|
|
38cd8ad6a1 | ||
|
|
96ff998d18 | ||
|
|
fb9c03186c | ||
|
|
2cf42bf7a4 | ||
|
|
8d015f5c9f | ||
|
|
bc7907728c | ||
|
|
1471bd5b53 | ||
|
|
acf186490c | ||
|
|
2988ac3839 | ||
|
|
97d39e0c28 | ||
|
|
3e3e050aaf | ||
|
|
223ade9b3f | ||
|
|
0d80021433 | ||
|
|
62fcb6bd96 | ||
|
|
406cf7adcd | ||
|
|
48ae8ce0a8 | ||
|
|
143151f284 | ||
|
|
9120f5fada | ||
|
|
e612ccda92 | ||
|
|
5198c87597 | ||
|
|
5c1aa578ef | ||
|
|
54c659f4aa | ||
|
|
ac87f7a977 | ||
|
|
833320a34a | ||
|
|
a981f99b06 | ||
|
|
7477b7c869 | ||
|
|
a2f99cc69e | ||
|
|
d54d27cda4 | ||
|
|
e9aab2b722 | ||
|
|
1faa1b5df6 | ||
|
|
a2a3233f5e | ||
|
|
a05d05088e | ||
|
|
347bed8be5 | ||
|
|
c6d718d126 | ||
|
|
ae4cff4982 | ||
|
|
7defc4b87d | ||
|
|
7b3140fbb3 | ||
|
|
c56f495cf1 | ||
|
|
cfc0247e5c | ||
|
|
58d46ddd46 | ||
|
|
074ec3e17d | ||
|
|
b0ceeb19c3 | ||
|
|
4ec15c84fa | ||
|
|
542e1db913 | ||
|
|
59ce9e6dc7 | ||
|
|
95f76efd80 | ||
|
|
d89ea4dac7 | ||
|
|
c0a1e6ea15 | ||
|
|
2a6b7dbaf9 | ||
|
|
5c8962823e | ||
|
|
daae8253c6 | ||
|
|
763a25e934 | ||
|
|
cab2ea757d | ||
|
|
b565258f12 | ||
|
|
2f1bc7ab93 | ||
|
|
340332cf5b | ||
|
|
854762092d | ||
|
|
fe7dbb42b3 | ||
|
|
73ea9197c5 | ||
|
|
ed2789a0e4 | ||
|
|
732489ee4a | ||
|
|
ca87fb8bc5 | ||
|
|
e0697763f8 | ||
|
|
7032499e2a | ||
|
|
9eb86caa82 | ||
|
|
cb87787ffb | ||
|
|
b6cf2ce524 | ||
|
|
5543689c14 | ||
|
|
a5ccf97a64 | ||
|
|
7555952738 | ||
|
|
195a1c1810 | ||
|
|
84282ca016 | ||
|
|
4039488654 | ||
|
|
a3db80af04 | ||
|
|
7140d01336 | ||
|
|
a029925818 | ||
|
|
162913ccd0 | ||
|
|
f6bb10503f | ||
|
|
af1acf6e60 | ||
|
|
379013a5da | ||
|
|
881f3e4255 | ||
|
|
715e027183 | ||
|
|
f4c7339870 | ||
|
|
ab268b6e77 | ||
|
|
7e2157fbed | ||
|
|
de50a985b4 | ||
|
|
fb1740f208 | ||
|
|
b426d87d82 | ||
|
|
c8bb4e961c | ||
|
|
6c7f6a425e | ||
|
|
0c9a0707ce | ||
|
|
1eb3a3e6d1 | ||
|
|
8e084267fa | ||
|
|
7abf678bbe | ||
|
|
7e6be7feac | ||
|
|
dbdb81381b | ||
|
|
6f8369ed6b | ||
|
|
92491c90e0 | ||
|
|
afe9f3ae85 | ||
|
|
3aa6270de6 | ||
|
|
8985a48a34 | ||
|
|
0974149c82 | ||
|
|
fef679846c | ||
|
|
b9fa941ca6 | ||
|
|
250109f0b4 | ||
|
|
af78c75d66 | ||
|
|
e6e7a29b68 | ||
|
|
83e048ee45 | ||
|
|
eda8028dd6 | ||
|
|
6af418663e | ||
|
|
e8ee3bc1ad | ||
|
|
2a7bdd9b08 | ||
|
|
325d64b5ed | ||
|
|
6937857446 | ||
|
|
3e7c0a086b | ||
|
|
190a051ee9 | ||
|
|
cd2968d849 | ||
|
|
ebd6104c63 | ||
|
|
9ee66892a0 | ||
|
|
f6ce07289a | ||
|
|
1c66e1d27d | ||
|
|
881c2323fd | ||
|
|
64af03042a | ||
|
|
9032231300 | ||
|
|
4cc37a74dc | ||
|
|
f7e92980ab | ||
|
|
e3896e45fc | ||
|
|
797aebb161 | ||
|
|
cb6aeb4f96 | ||
|
|
21a93eb6e8 | ||
|
|
aa1900d8dd | ||
|
|
692a6067e9 | ||
|
|
1e027de3e1 | ||
|
|
dac09679a5 | ||
|
|
c38859b77a | ||
|
|
9e4b8077f3 | ||
|
|
6409004244 | ||
|
|
315aac9aab | ||
|
|
418fc79698 | ||
|
|
1dbe308527 | ||
|
|
e99e65929e | ||
|
|
1f6e140eb6 | ||
|
|
1d17e4051f | ||
|
|
4a728fa3c6 | ||
|
|
496860e254 | ||
|
|
bb50087dd0 | ||
|
|
7fa081e884 | ||
|
|
c7fcbe8c16 | ||
|
|
bc1703323e | ||
|
|
d5b5dafb3a | ||
|
|
54ecb1b23e | ||
|
|
dcfd3f6aa5 | ||
|
|
b592842a66 | ||
|
|
2ed32be514 | ||
|
|
64192b3506 | ||
|
|
331c0fe326 | ||
|
|
ced15b7934 | ||
|
|
45cc19f315 | ||
|
|
0896edf06c | ||
|
|
849a790617 | ||
|
|
4ec2966f47 | ||
|
|
f1e7b4c499 | ||
|
|
fb705ab3ef | ||
|
|
441325347c | ||
|
|
4a0c637ee8 | ||
|
|
58efe4fdd1 | ||
|
|
063011ec8d | ||
|
|
c81ba6e4a9 | ||
|
|
1a67ab8c95 | ||
|
|
c34fb39cf3 | ||
|
|
4241ad34b6 | ||
|
|
7ee2b6f397 | ||
|
|
a540d1ab17 | ||
|
|
90c33da521 | ||
|
|
33dd7d4965 | ||
|
|
06e21aae6e | ||
|
|
37fffca615 | ||
|
|
231e180ff3 | ||
|
|
d2eff3efa3 | ||
|
|
866ca966b1 | ||
|
|
3009687326 | ||
|
|
84a54406dc | ||
|
|
8c7fc9890c | ||
|
|
a4d93362c3 | ||
|
|
27665e44a9 | ||
|
|
ebbe3c9144 | ||
|
|
56c4e60e45 | ||
|
|
bd3508d803 | ||
|
|
8aea47a7ee | ||
|
|
0822284cba | ||
|
|
7453f459c9 | ||
|
|
5aaac8b774 | ||
|
|
fd0511144a | ||
|
|
c1ad5cded0 | ||
|
|
3df7309dbf | ||
|
|
f068687306 | ||
|
|
e7bcb270e4 | ||
|
|
d9506ce3a6 | ||
|
|
c6e5b2339e | ||
|
|
6888511e03 | ||
|
|
c41558aa6e | ||
|
|
659010993f | ||
|
|
08352151e3 | ||
|
|
ac1bdd2c84 | ||
|
|
ba164f9e48 | ||
|
|
0c34eb6138 | ||
|
|
19bc6f961d | ||
|
|
6385c8c530 | ||
|
|
2762470096 | ||
|
|
ba39b6f551 | ||
|
|
e8a4808f16 | ||
|
|
93eded4803 | ||
|
|
801c4f9181 | ||
|
|
7399c758d3 | ||
|
|
33baf418cd | ||
|
|
8573eda852 | ||
|
|
00e7aa4976 | ||
|
|
32e2a4e9ce | ||
|
|
6ba2df7fa4 | ||
|
|
9455d0da7f | ||
|
|
b1955f72d7 | ||
|
|
252a3e6be4 | ||
|
|
bada3bc75b | ||
|
|
de22f659e8 | ||
|
|
c90c065431 | ||
|
|
c2f8984e6c | ||
|
|
0546c9bf64 | ||
|
|
089cdcf777 | ||
|
|
9f9cf08d72 | ||
|
|
f15ccea6dd | ||
|
|
dbe283cb1f | ||
|
|
966aca437c | ||
|
|
627b19c8fb | ||
|
|
3284c24ece | ||
|
|
f582e690eb | ||
|
|
ae84889235 | ||
|
|
640115d646 | ||
|
|
6aced66406 | ||
|
|
061445ef6e | ||
|
|
325ab97a7d | ||
|
|
b9172a7823 | ||
|
|
2a6fc45ab5 | ||
|
|
f954970db8 | ||
|
|
8112063a8b | ||
|
|
02fb432b05 | ||
|
|
4d6da0017c | ||
|
|
475c2a0b42 | ||
|
|
092cad4ba1 | ||
|
|
5ee79b51ca | ||
|
|
45a4596e8b | ||
|
|
061c1f520c | ||
|
|
df5c4df894 | ||
|
|
c418758a3a | ||
|
|
dfe01c7bb1 | ||
|
|
b5f6aa0c9d | ||
|
|
bb61f44d92 | ||
|
|
104881763c | ||
|
|
be7ffd89e2 | ||
|
|
892263302f | ||
|
|
07fe1a6b5a | ||
|
|
e0a6604d06 | ||
|
|
6aa7e2edce | ||
|
|
0ff144af73 | ||
|
|
b7c088fbf3 |
7
.github/CODEOWNERS
vendored
7
.github/CODEOWNERS
vendored
@@ -55,3 +55,10 @@
|
||||
#Jezi
|
||||
/Content.*/Medical @Jezithyr
|
||||
/Content.*/Body @Jezithyr
|
||||
|
||||
# Sloth
|
||||
/Content.*/Audio @metalgearsloth
|
||||
/Content.*/Movement @metalgearsloth
|
||||
/Content.*/NPC @metalgearsloth
|
||||
/Content.*/Shuttles @metalgearsloth
|
||||
/Content.*/Weapons @metalgearsloth
|
||||
|
||||
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -5,8 +5,8 @@
|
||||
"Changes: Map":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'Resources/Maps/*.yml'
|
||||
- 'Resources/Prototypes/Maps/*.yml'
|
||||
- 'Resources/Maps/**/*.yml'
|
||||
- 'Resources/Prototypes/Maps/**/*.yml'
|
||||
|
||||
"Changes: UI":
|
||||
- changed-files:
|
||||
|
||||
1
.github/workflows/labeler-untriaged.yml
vendored
1
.github/workflows/labeler-untriaged.yml
vendored
@@ -9,5 +9,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
if: join(github.event.issue.labels) == ''
|
||||
with:
|
||||
labels: "Status: Untriaged"
|
||||
|
||||
42
.github/workflows/publish.yml
vendored
42
.github/workflows/publish.yml
vendored
@@ -41,31 +41,22 @@ jobs:
|
||||
- name: Package client
|
||||
run: dotnet run --project Content.Packaging client --no-wipe-release
|
||||
|
||||
- name: Update Build Info
|
||||
run: Tools/gen_build_info.py
|
||||
|
||||
- name: Shuffle files around
|
||||
run: |
|
||||
mkdir "release/${{ github.sha }}"
|
||||
mv release/*.zip "release/${{ github.sha }}"
|
||||
|
||||
- name: Upload files to centcomm
|
||||
uses: appleboy/scp-action@master
|
||||
- name: Upload build artifact
|
||||
id: artifact-upload-step
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
host: centcomm.spacestation14.io
|
||||
username: wizards-build-push
|
||||
key: ${{ secrets.CENTCOMM_WIZARDS_BUILDS_PUSH_KEY }}
|
||||
source: "release/${{ github.sha }}"
|
||||
target: "/home/wizards-build-push/builds_dir/builds/"
|
||||
strip_components: 1
|
||||
name: build
|
||||
path: release/*.zip
|
||||
compression-level: 0
|
||||
retention-days: 0
|
||||
|
||||
- name: Update manifest JSON
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: centcomm.spacestation14.io
|
||||
username: wizards-build-push
|
||||
key: ${{ secrets.CENTCOMM_WIZARDS_BUILDS_PUSH_KEY }}
|
||||
script: /home/wizards-build-push/push.ps1 ${{ github.sha }}
|
||||
- name: Publish version
|
||||
run: Tools/publish_github_artifact.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
|
||||
ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }}
|
||||
GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }}
|
||||
|
||||
- name: Publish changelog (Discord)
|
||||
run: Tools/actions_changelogs_since_last_run.py
|
||||
@@ -77,3 +68,8 @@ jobs:
|
||||
run: Tools/actions_changelog_rss.py
|
||||
env:
|
||||
CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }}
|
||||
|
||||
- uses: geekyeggo/delete-artifact@v5
|
||||
if: always()
|
||||
with:
|
||||
name: build
|
||||
|
||||
8
.github/workflows/test-packaging.yml
vendored
8
.github/workflows/test-packaging.yml
vendored
@@ -64,11 +64,3 @@ jobs:
|
||||
|
||||
- name: Package client
|
||||
run: dotnet run --project Content.Packaging client --no-wipe-release
|
||||
|
||||
- name: Update Build Info
|
||||
run: Tools/gen_build_info.py
|
||||
|
||||
- name: Shuffle files around
|
||||
run: |
|
||||
mkdir "release/${{ github.sha }}"
|
||||
mv release/*.zip "release/${{ github.sha }}"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -306,3 +306,4 @@ Resources/MapImages
|
||||
|
||||
# Direnv stuff
|
||||
.direnv/
|
||||
/Tools/_CP14/LocalizationHelper/last_launch
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"omnisharp.analyzeOpenDocumentsOnly": true,
|
||||
"dotnet.defaultSolution": "SpaceStation14.sln"
|
||||
}
|
||||
@@ -12,11 +12,18 @@ namespace Content.Client.Access.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AccessLevelControl : GridContainer
|
||||
{
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public readonly Dictionary<ProtoId<AccessLevelPrototype>, Button> ButtonsList = new();
|
||||
|
||||
public AccessLevelControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sawmill = _logManager.GetSawmill("accesslevelcontrol");
|
||||
}
|
||||
|
||||
public void Populate(List<ProtoId<AccessLevelPrototype>> accessLevels, IPrototypeManager prototypeManager)
|
||||
@@ -25,7 +32,7 @@ public sealed partial class AccessLevelControl : GridContainer
|
||||
{
|
||||
if (!prototypeManager.TryIndex(access, out var accessLevel))
|
||||
{
|
||||
Logger.Error($"Unable to find accesslevel for {access}");
|
||||
_sawmill.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.Stylesheets;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -77,9 +77,12 @@ namespace Content.Client.Actions.UI
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = {StyleNano.StyleClassTooltipActionRequirements}
|
||||
};
|
||||
requiresLabel.SetMessage(FormattedMessage.FromMarkup("[color=#635c5c]" +
|
||||
requires +
|
||||
"[/color]"));
|
||||
|
||||
if (!FormattedMessage.TryFromMarkup("[color=#635c5c]" + requires + "[/color]", out var markup))
|
||||
return;
|
||||
|
||||
requiresLabel.SetMessage(markup);
|
||||
|
||||
vbox.AddChild(requiresLabel);
|
||||
}
|
||||
}
|
||||
@@ -97,8 +100,11 @@ namespace Content.Client.Actions.UI
|
||||
if (timeLeft > TimeSpan.Zero)
|
||||
{
|
||||
var duration = Cooldown.Value.End - Cooldown.Value.Start;
|
||||
_cooldownLabel.SetMessage(FormattedMessage.FromMarkup(
|
||||
$"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]"));
|
||||
|
||||
if (!FormattedMessage.TryFromMarkup($"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]", out var markup))
|
||||
return;
|
||||
|
||||
_cooldownLabel.SetMessage(markup);
|
||||
_cooldownLabel.Visible = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -3,38 +3,57 @@ using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Administration.UI
|
||||
namespace Content.Client.Administration.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminMenuWindow : DefaultWindow
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminMenuWindow : DefaultWindow
|
||||
public event Action? OnDisposed;
|
||||
|
||||
public AdminMenuWindow()
|
||||
{
|
||||
public event Action? OnDisposed;
|
||||
MinSize = new Vector2(650, 250);
|
||||
Title = Loc.GetString("admin-menu-title");
|
||||
RobustXamlLoader.Load(this);
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Admin, Loc.GetString("admin-menu-admin-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Adminbus, Loc.GetString("admin-menu-adminbus-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Atmos, Loc.GetString("admin-menu-atmos-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Round, Loc.GetString("admin-menu-round-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Server, Loc.GetString("admin-menu-server-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.PanicBunker, Loc.GetString("admin-menu-panic-bunker-tab"));
|
||||
/*
|
||||
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
|
||||
*/
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.BabyJail, Loc.GetString("admin-menu-baby-jail-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Players, Loc.GetString("admin-menu-players-tab"));
|
||||
MasterTabContainer.SetTabTitle((int) TabIndex.Objects, Loc.GetString("admin-menu-objects-tab"));
|
||||
MasterTabContainer.OnTabChanged += OnTabChanged;
|
||||
}
|
||||
|
||||
public AdminMenuWindow()
|
||||
{
|
||||
MinSize = new Vector2(650, 250);
|
||||
Title = Loc.GetString("admin-menu-title");
|
||||
RobustXamlLoader.Load(this);
|
||||
MasterTabContainer.SetTabTitle(0, Loc.GetString("admin-menu-admin-tab"));
|
||||
MasterTabContainer.SetTabTitle(1, Loc.GetString("admin-menu-adminbus-tab"));
|
||||
MasterTabContainer.SetTabTitle(2, Loc.GetString("admin-menu-atmos-tab"));
|
||||
MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab"));
|
||||
MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab"));
|
||||
MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-panic-bunker-tab"));
|
||||
/*
|
||||
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
|
||||
*/
|
||||
MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-baby-jail-tab"));
|
||||
MasterTabContainer.SetTabTitle(7, Loc.GetString("admin-menu-players-tab"));
|
||||
MasterTabContainer.SetTabTitle(8, Loc.GetString("admin-menu-objects-tab"));
|
||||
}
|
||||
private void OnTabChanged(int tabIndex)
|
||||
{
|
||||
var tabEnum = (TabIndex)tabIndex;
|
||||
if (tabEnum == TabIndex.Objects)
|
||||
ObjectsTabControl.RefreshObjectList();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
OnDisposed?.Invoke();
|
||||
base.Dispose(disposing);
|
||||
OnDisposed = null;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
OnDisposed?.Invoke();
|
||||
base.Dispose(disposing);
|
||||
OnDisposed = null;
|
||||
}
|
||||
|
||||
private enum TabIndex
|
||||
{
|
||||
Admin = 0,
|
||||
Adminbus,
|
||||
Atmos,
|
||||
Round,
|
||||
Server,
|
||||
PanicBunker,
|
||||
BabyJail,
|
||||
Players,
|
||||
Objects,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<LineEdit Name="FilterLineEdit"
|
||||
MinSize="100 0"
|
||||
HorizontalExpand="True"
|
||||
PlaceHolder="{Loc Filter}"/>
|
||||
PlaceHolder="{Loc player-list-filter}"/>
|
||||
<PanelContainer Name="BackgroundPanel"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True">
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<Popup xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
|
||||
<PanelContainer StyleClasses="BackgroundDark">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BorderThickness="1" BorderColor="#18181B"/>
|
||||
<gfx:StyleBoxFlat BorderThickness="2" BorderColor="#18181B" BackgroundColor="#25252a"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Vertical" Margin="4 4 4 4">
|
||||
<Label Name="PlayerNameLabel"/>
|
||||
<Label Name="IdLabel"/>
|
||||
<Label Name="TypeLabel"/>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Title="{Loc admin-player-actions-window-title}" MinSize="425 272">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Reason}" MinWidth="100" />
|
||||
<Label Text="{Loc admin-player-actions-reason}" MinWidth="100" />
|
||||
<Control MinWidth="50" />
|
||||
<LineEdit Name="ReasonLine" MinWidth="100" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Title="{Loc Teleport}" MinSize="425 230">
|
||||
Title="{Loc admin-ui-teleport}" MinSize="425 230">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<cc:PlayerListControl Name="PlayerList" />
|
||||
<Button Name="SubmitButton" Text="{Loc Teleport}" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-teleport}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io" Title="{Loc Load Blueprint}">
|
||||
xmlns="https://spacestation14.io" Title="{Loc admin-ui-blueprint-load}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Map}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-blueprint-map}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="MapOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Path}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-blueprint-path}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<LineEdit Name="MapPath" MinSize="200 0" HorizontalExpand="True" Text="/Maps/" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc X}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-blueprint-x}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="XCoordinate" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Y}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-blueprint-y}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="YCoordinate" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Rotation}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-blueprint-rotation}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="RotationSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<Button Name="SubmitButton" Text="{Loc Load Blueprint}" />
|
||||
<Button Name="TeleportButton" Text="{Loc Teleport to}" />
|
||||
<Button Name="ResetButton" Text="{Loc Reset to default}"></Button>
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-blueprint-load}" />
|
||||
<Button Name="TeleportButton" Text="{Loc admin-ui-blueprint-teleport}" />
|
||||
<Button Name="ResetButton" Text="{Loc admin-ui-blueprint-reset}"></Button>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io" Title="{Loc Add Atmos}">
|
||||
xmlns="https://spacestation14.io" Title="{Loc admin-ui-atmos-add}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Grid}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-grid}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<Button Name="SubmitButton" Text="{Loc Add Atmos}" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-atmos-add}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
while (query.MoveNext(out var uid, out var grid))
|
||||
{
|
||||
_data.Add((uid, grid));
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? Loc.GetString($"admin-ui-atmos-grid-current") : "")}");
|
||||
}
|
||||
|
||||
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io" Title="{Loc Add Gas}">
|
||||
xmlns="https://spacestation14.io" Title="{Loc admin-ui-atmos-add-gas}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Grid}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-grid}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc TileX}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-tile-x}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="TileXSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc TileY}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-tile-y}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="TileYSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Gas}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-gas}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GasOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Amount}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-gas-amount}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="AmountSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<Button Name="SubmitButton" Text="{Loc Add Gas}" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-atmos-add-gas}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
_gridData.Add(entManager.GetNetEntity(uid));
|
||||
var player = playerManager.LocalEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? Loc.GetString("admin-ui-atmos-grid-current") : "")}");
|
||||
}
|
||||
|
||||
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
Margin="4"
|
||||
MinSize="50 50">
|
||||
<GridContainer Columns="4">
|
||||
<cc:UICommandButton Text="{Loc Add Atmos}" Command="addatmos" WindowType="{x:Type at:AddAtmosWindow}" />
|
||||
<cc:UICommandButton Text="{Loc Add Gas}" Command="addgas" WindowType="{x:Type at:AddGasWindow}" />
|
||||
<cc:UICommandButton Text="{Loc Fill Gas}" Command="fillgas" WindowType="{x:Type at:FillGasWindow}" />
|
||||
<cc:UICommandButton Text="{Loc Set Temperature}" Command="settemp"
|
||||
<cc:UICommandButton Text="{Loc admin-ui-atmos-add}" Command="addatmos" WindowType="{x:Type at:AddAtmosWindow}" />
|
||||
<cc:UICommandButton Text="{Loc admin-ui-atmos-add-gas}" Command="addgas" WindowType="{x:Type at:AddGasWindow}" />
|
||||
<cc:UICommandButton Text="{Loc admin-ui-atmos-fill-gas}" Command="fillgas" WindowType="{x:Type at:FillGasWindow}" />
|
||||
<cc:UICommandButton Text="{Loc admin-ui-atmos-set-temperature}" Command="settemp"
|
||||
WindowType="{x:Type at:SetTemperatureWindow}" />
|
||||
</GridContainer>
|
||||
</Control>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io" Title="{Loc Fill Gas}">
|
||||
xmlns="https://spacestation14.io" Title="{Loc admin-ui-atmos-fill-gas}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Grid}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-grid}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Gas}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-gas}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GasOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Amount}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-gas-amount}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="AmountSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<Button Name="SubmitButton" Text="{Loc Fill Gas}" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-atmos-fill-gas}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
{
|
||||
var player = playerManager.LocalEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? Loc.GetString($"admin-ui-atmos-grid-current") : "")}");
|
||||
_gridData.Add(entManager.GetNetEntity(uid));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io" Title="{Loc Set Temperature}">
|
||||
xmlns="https://spacestation14.io" Title="{Loc admin-ui-atmos-set-temperature}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Grid}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-grid}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc TileX}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-tile-x}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="TileXSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc TileY}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-tile-y}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="TileYSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc Temperature}" MinSize="100 0" />
|
||||
<Label Text="{Loc admin-ui-atmos-temperature}" MinSize="100 0" />
|
||||
<Control MinSize="50 0" />
|
||||
<SpinBox Name="TemperatureSpin" MinSize="100 0" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<Button Name="SubmitButton" Text="{Loc Set Temperature}" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-atmos-set-temperature}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
{
|
||||
var player = playerManager.LocalEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? Loc.GetString($"admin-ui-atmos-grid-current") : "")}");
|
||||
_data.Add(entManager.GetNetEntity(uid));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,17 @@
|
||||
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label HorizontalExpand="True" SizeFlagsStretchRatio="0.50"
|
||||
Text="{Loc Object type:}" />
|
||||
<LineEdit Name="SearchLineEdit" PlaceHolder="{Loc Search...}" HorizontalExpand="True" SizeFlagsStretchRatio="1"/>
|
||||
<OptionButton Name="ObjectTypeOptions" HorizontalExpand="True" SizeFlagsStretchRatio="0.25"/>
|
||||
<Label Text="{Loc object-tab-object-type}" />
|
||||
<OptionButton Name="ObjectTypeOptions" HorizontalAlignment="Left" />
|
||||
<LineEdit Name="SearchLineEdit" PlaceHolder="{Loc object-tab-object-search}" HorizontalExpand="True"
|
||||
SizeFlagsStretchRatio="1" />
|
||||
<Button Name="RefreshListButton" Text="{Loc object-tab-refresh-button}" ToggleMode="False" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
</BoxContainer>
|
||||
<cc:HSeparator/>
|
||||
<cc:HSeparator />
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ot:ObjectsTabHeader Name="ListHeader"/>
|
||||
<cc:HSeparator/>
|
||||
<co:SearchListContainer Name="SearchList" Access="Public" VerticalExpand="True"/>
|
||||
<ot:ObjectsTabHeader Name="ListHeader" />
|
||||
<cc:HSeparator />
|
||||
<co:SearchListContainer Name="SearchList" Access="Public" VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -15,17 +16,14 @@ public sealed partial class ObjectsTab : Control
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private readonly List<ObjectsTabEntry> _objects = new();
|
||||
private readonly List<ObjectsTabSelection> _selections = new();
|
||||
private bool _ascending = false; // Set to false for descending order by default
|
||||
private ObjectsTabHeader.Header _headerClicked = ObjectsTabHeader.Header.ObjectName;
|
||||
private readonly Color _altColor = Color.FromHex("#292B38");
|
||||
private readonly Color _defaultColor = Color.FromHex("#2F2F3B");
|
||||
|
||||
public event Action<GUIBoundKeyEventArgs, ListData>? OnEntryKeyBindDown;
|
||||
private bool _ascending;
|
||||
private ObjectsTabHeader.Header _headerClicked = ObjectsTabHeader.Header.ObjectName;
|
||||
|
||||
private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(2);
|
||||
private TimeSpan _nextUpdate;
|
||||
private readonly List<ObjectsTabSelection> _selections = [];
|
||||
public event Action<GUIBoundKeyEventArgs, ListData>? OnEntryKeyBindDown;
|
||||
|
||||
public ObjectsTab()
|
||||
{
|
||||
@@ -38,40 +36,25 @@ public sealed partial class ObjectsTab : Control
|
||||
RefreshObjectList(_selections[ev.Id]);
|
||||
};
|
||||
|
||||
foreach (var type in Enum.GetValues(typeof(ObjectsTabSelection)))
|
||||
foreach (var type in Enum.GetValues<ObjectsTabSelection>())
|
||||
{
|
||||
_selections.Add((ObjectsTabSelection)type!);
|
||||
ObjectTypeOptions.AddItem(Enum.GetName((ObjectsTabSelection)type)!);
|
||||
_selections.Add(type);
|
||||
ObjectTypeOptions.AddItem(GetLocalizedEnumValue(type));
|
||||
}
|
||||
|
||||
ListHeader.OnHeaderClicked += HeaderClicked;
|
||||
SearchList.SearchBar = SearchLineEdit;
|
||||
SearchList.GenerateItem += GenerateButton;
|
||||
SearchList.DataFilterCondition += DataFilterCondition;
|
||||
SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data);
|
||||
RefreshListButton.OnPressed += _ => RefreshObjectList();
|
||||
|
||||
RefreshObjectList();
|
||||
// Set initial selection and refresh the list to apply the initial sort order
|
||||
var defaultSelection = ObjectsTabSelection.Grids;
|
||||
ObjectTypeOptions.SelectId((int)defaultSelection); // Set the default selection
|
||||
RefreshObjectList(defaultSelection); // Refresh the list with the default selection
|
||||
|
||||
// Initialize the next update time
|
||||
_nextUpdate = TimeSpan.Zero;
|
||||
ObjectTypeOptions.SelectId((int) defaultSelection);
|
||||
RefreshObjectList(defaultSelection);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
if (_timing.CurTime < _nextUpdate)
|
||||
return;
|
||||
|
||||
_nextUpdate = _timing.CurTime + _updateFrequency;
|
||||
|
||||
RefreshObjectList();
|
||||
}
|
||||
|
||||
private void RefreshObjectList()
|
||||
public void RefreshObjectList()
|
||||
{
|
||||
RefreshObjectList(_selections[ObjectTypeOptions.SelectedId]);
|
||||
}
|
||||
@@ -101,6 +84,7 @@ public sealed partial class ObjectsTab : Control
|
||||
{
|
||||
entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -111,14 +95,18 @@ public sealed partial class ObjectsTab : Control
|
||||
{
|
||||
var valueA = GetComparableValue(a, _headerClicked);
|
||||
var valueB = GetComparableValue(b, _headerClicked);
|
||||
return _ascending ? Comparer<object>.Default.Compare(valueA, valueB) : Comparer<object>.Default.Compare(valueB, valueA);
|
||||
return _ascending
|
||||
? Comparer<object>.Default.Compare(valueA, valueB)
|
||||
: Comparer<object>.Default.Compare(valueB, valueA);
|
||||
});
|
||||
|
||||
var listData = new List<ObjectsListData>();
|
||||
for (int index = 0; index < entities.Count; index++)
|
||||
for (var index = 0; index < entities.Count; index++)
|
||||
{
|
||||
var info = entities[index];
|
||||
listData.Add(new ObjectsListData(info, $"{info.Name} {info.Entity}", index % 2 == 0 ? _altColor : _defaultColor));
|
||||
listData.Add(new ObjectsListData(info,
|
||||
$"{info.Name} {info.Entity}",
|
||||
index % 2 == 0 ? _altColor : _defaultColor));
|
||||
}
|
||||
|
||||
SearchList.PopulateList(listData);
|
||||
@@ -129,10 +117,11 @@ public sealed partial class ObjectsTab : Control
|
||||
if (data is not ObjectsListData { Info: var info, BackgroundColor: var backgroundColor })
|
||||
return;
|
||||
|
||||
var entry = new ObjectsTabEntry(info.Name, info.Entity, new StyleBoxFlat { BackgroundColor = backgroundColor });
|
||||
var entry = new ObjectsTabEntry(info.Name,
|
||||
info.Entity,
|
||||
new StyleBoxFlat { BackgroundColor = backgroundColor });
|
||||
button.ToolTip = $"{info.Name}, {info.Entity}";
|
||||
|
||||
button.OnKeyBindDown += args => OnEntryKeyBindDown?.Invoke(args, data);
|
||||
button.AddChild(entry);
|
||||
}
|
||||
|
||||
@@ -154,7 +143,7 @@ public sealed partial class ObjectsTab : Control
|
||||
{
|
||||
ObjectsTabHeader.Header.ObjectName => entity.Name,
|
||||
ObjectsTabHeader.Header.EntityID => entity.Entity.ToString(),
|
||||
_ => entity.Name
|
||||
_ => entity.Name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,6 +163,17 @@ public sealed partial class ObjectsTab : Control
|
||||
RefreshObjectList();
|
||||
}
|
||||
|
||||
private string GetLocalizedEnumValue(ObjectsTabSelection selection)
|
||||
{
|
||||
return selection switch
|
||||
{
|
||||
ObjectsTabSelection.Grids => Loc.GetString("object-tab-object-type-grids"),
|
||||
ObjectsTabSelection.Maps => Loc.GetString("object-tab-object-type-maps"),
|
||||
ObjectsTabSelection.Stations => Loc.GetString("object-tab-object-type-stations"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(selection), selection, null),
|
||||
};
|
||||
}
|
||||
|
||||
private enum ObjectsTabSelection
|
||||
{
|
||||
Grids,
|
||||
@@ -182,4 +182,5 @@ public sealed partial class ObjectsTab : Control
|
||||
}
|
||||
}
|
||||
|
||||
public record ObjectsListData((string Name, NetEntity Entity) Info, string FilteringString, Color BackgroundColor) : ListData;
|
||||
public record ObjectsListData((string Name, NetEntity Entity) Info, string FilteringString, Color BackgroundColor)
|
||||
: ListData;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="PlayerCount" HorizontalExpand="True" Text="{Loc Player Count}" />
|
||||
<Label Name="PlayerCount" HorizontalExpand="True" Text="{Loc player-tab-player-count}" />
|
||||
<LineEdit Name="SearchLineEdit" HorizontalExpand="True"
|
||||
PlaceHolder="{Loc player-tab-filter-line-edit-placeholder}" />
|
||||
<Button Name="ShowDisconnectedButton" HorizontalExpand="True"
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab
|
||||
private void RefreshPlayerList(IReadOnlyList<PlayerInfo> players)
|
||||
{
|
||||
_players = players;
|
||||
PlayerCount.Text = $"Players: {_playerMan.PlayerCount}";
|
||||
PlayerCount.Text = Loc.GetString("player-tab-player-count", ("count", _playerMan.PlayerCount));
|
||||
|
||||
var filteredPlayers = players.Where(info => _showDisconnected || info.Connected).ToList();
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
MinSize="50 50">
|
||||
<GridContainer
|
||||
Columns="3">
|
||||
<cc:CommandButton Command="startround" Text="{Loc Start Round}" />
|
||||
<cc:CommandButton Command="endround" Text="{Loc End Round}" />
|
||||
<cc:CommandButton Command="restartround" Text="{Loc Restart Round}" />
|
||||
<cc:CommandButton Command="startround" Text="{Loc administration-ui-round-tab-start-round}" />
|
||||
<cc:CommandButton Command="endround" Text="{Loc administration-ui-round-tab-end-round}" />
|
||||
<cc:CommandButton Command="restartround" Text="{Loc administration-ui-round-tab-restart-round}" />
|
||||
<cc:CommandButton Command="restartroundnow" Text="{Loc administration-ui-round-tab-restart-round-now}" />
|
||||
</GridContainer>
|
||||
</Control>
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed class AudioUIController : UIController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
var resource = _cache.GetResource<AudioResource>(value);
|
||||
var resource = GetSoundOrFallback(value, CCVars.UIClickSound.DefaultValue);
|
||||
var source =
|
||||
_audioManager.CreateAudioSource(resource);
|
||||
|
||||
@@ -77,7 +77,7 @@ public sealed class AudioUIController : UIController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
var hoverResource = _cache.GetResource<AudioResource>(value);
|
||||
var hoverResource = GetSoundOrFallback(value, CCVars.UIHoverSound.DefaultValue);
|
||||
var hoverSource =
|
||||
_audioManager.CreateAudioSource(hoverResource);
|
||||
|
||||
@@ -95,4 +95,12 @@ public sealed class AudioUIController : UIController
|
||||
UIManager.SetHoverSound(null);
|
||||
}
|
||||
}
|
||||
|
||||
private AudioResource GetSoundOrFallback(string path, string fallback)
|
||||
{
|
||||
if (!_cache.TryGetResource(path, out AudioResource? resource))
|
||||
return _cache.GetResource<AudioResource>(fallback);
|
||||
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Audio;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Random.Rules;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
@@ -116,6 +117,7 @@ public sealed partial class ContentAudioSystem
|
||||
|
||||
private void OnRoundEndMessage(RoundEndMessageEvent ev)
|
||||
{
|
||||
OnRoundEndMessageAmbientLoop(); //CP14
|
||||
// If scoreboard shows then just stop the music
|
||||
_ambientMusicStream = _audio.Stop(_ambientMusicStream);
|
||||
_nextAudio = TimeSpan.FromMinutes(3);
|
||||
|
||||
122
Content.Client/Audio/ContentAudioSystem.CP14AmbientLoop.cs
Normal file
122
Content.Client/Audio/ContentAudioSystem.CP14AmbientLoop.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Audio;
|
||||
|
||||
public sealed partial class ContentAudioSystem
|
||||
{
|
||||
private const float AmbientLoopFadeInTime = 1f;
|
||||
private const float AmbientLoopFadeOutTime = 4f;
|
||||
|
||||
private Dictionary<CP14AmbientLoopPrototype, EntityUid> _loopStreams = new();
|
||||
|
||||
private TimeSpan _nextUpdateTime = TimeSpan.Zero;
|
||||
private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(1f);
|
||||
|
||||
private void CP14InitializeAmbientLoops()
|
||||
{
|
||||
Subs.CVar(_configManager, CCVars.AmbientMusicVolume, AmbienceCVarChangedAmbientMusic, true);
|
||||
}
|
||||
|
||||
private void AmbienceCVarChangedAmbientMusic(float obj)
|
||||
{
|
||||
_volumeSlider = SharedAudioSystem.GainToVolume(obj);
|
||||
|
||||
foreach (var loop in _loopStreams)
|
||||
{
|
||||
_audio.SetVolume(loop.Value, loop.Key.Sound.Params.Volume + _volumeSlider);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRoundEndMessageAmbientLoop()
|
||||
{
|
||||
foreach (var loop in _loopStreams)
|
||||
{
|
||||
StopAmbientLoop(loop.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private void CP14UpdateAmbientLoops()
|
||||
{
|
||||
if (_timing.CurTime <= _nextUpdateTime)
|
||||
return;
|
||||
|
||||
_nextUpdateTime = _timing.CurTime + _updateFrequency;
|
||||
|
||||
|
||||
if (_state.CurrentState is not GameplayState)
|
||||
return;
|
||||
|
||||
var requiredLoops = GetAmbientLoops();
|
||||
|
||||
foreach (var loop in _loopStreams)
|
||||
{
|
||||
if (!requiredLoops.Contains(loop.Key)) //If ambient is playing and it shouldn't, stop it.
|
||||
StopAmbientLoop(loop.Key);
|
||||
}
|
||||
|
||||
foreach (var loop in requiredLoops)
|
||||
{
|
||||
if (!_loopStreams.ContainsKey(loop)) //If it's not playing, but should, run it
|
||||
StartAmbientLoop(loop);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartAmbientLoop(CP14AmbientLoopPrototype proto)
|
||||
{
|
||||
if (_loopStreams.ContainsKey(proto))
|
||||
return;
|
||||
|
||||
var newLoop = _audio.PlayGlobal(
|
||||
proto.Sound,
|
||||
Filter.Local(),
|
||||
false,
|
||||
AudioParams.Default
|
||||
.WithLoop(true)
|
||||
.WithVolume(proto.Sound.Params.Volume + _volumeSlider)
|
||||
.WithPlayOffset(_random.NextFloat(0f, 100f)));
|
||||
_loopStreams.Add(proto, newLoop.Value.Entity);
|
||||
|
||||
FadeIn(newLoop.Value.Entity, newLoop.Value.Component, AmbientLoopFadeInTime);
|
||||
}
|
||||
|
||||
private void StopAmbientLoop(CP14AmbientLoopPrototype proto)
|
||||
{
|
||||
if (!_loopStreams.TryGetValue(proto, out var audioEntity))
|
||||
return;
|
||||
|
||||
FadeOut(audioEntity, duration: AmbientLoopFadeOutTime);
|
||||
_loopStreams.Remove(proto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the player's environment, and returns a list of all ambients that should currently be playing around the player
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<CP14AmbientLoopPrototype> GetAmbientLoops()
|
||||
{
|
||||
List<CP14AmbientLoopPrototype> list = new();
|
||||
|
||||
var player = _player.LocalEntity;
|
||||
|
||||
if (player == null)
|
||||
return list;
|
||||
|
||||
var ambientLoops = _proto.EnumeratePrototypes<CP14AmbientLoopPrototype>().ToList();
|
||||
|
||||
foreach (var loop in ambientLoops)
|
||||
{
|
||||
if (_rules.IsTrue(player.Value, _proto.Index(loop.Rules)))
|
||||
{
|
||||
list.Add(loop);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -29,13 +29,14 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
|
||||
public const float AmbientMusicMultiplier = 3f;
|
||||
public const float LobbyMultiplier = 3f;
|
||||
public const float InterfaceMultiplier = 2f;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesOutsidePrediction = true;
|
||||
InitializeAmbientMusic();
|
||||
CP14InitializeAmbientLoops(); //CP14 ambient loops
|
||||
InitializeLobbyMusic();
|
||||
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
|
||||
}
|
||||
@@ -82,6 +83,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
|
||||
return;
|
||||
|
||||
UpdateAmbientMusic();
|
||||
CP14UpdateAmbientLoops(); //CP14
|
||||
UpdateLobbyMusic();
|
||||
UpdateFades(frameTime);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Client.BarSign.Ui;
|
||||
using Content.Shared.BarSign;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -8,6 +9,7 @@ namespace Content.Client.BarSign;
|
||||
public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -17,6 +19,9 @@ public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
|
||||
|
||||
private void OnAfterAutoHandleState(EntityUid uid, BarSignComponent component, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
if (_ui.TryGetOpenUi<BarSignBoundUserInterface>(uid, BarSignUiKey.Key, out var bui))
|
||||
bui.Update(component.Current);
|
||||
|
||||
UpdateAppearance(uid, component);
|
||||
}
|
||||
|
||||
@@ -34,9 +39,9 @@ public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
|
||||
|
||||
if (powered
|
||||
&& sign.Current != null
|
||||
&& _prototypeManager.TryIndex(sign.Current, out BarSignPrototype? proto))
|
||||
&& _prototypeManager.TryIndex(sign.Current, out var proto))
|
||||
{
|
||||
sprite.LayerSetState(0, proto.Icon);
|
||||
sprite.LayerSetSprite(0, proto.Icon);
|
||||
sprite.LayerSetShader(0, "unshaded");
|
||||
}
|
||||
else
|
||||
|
||||
50
Content.Client/BarSign/Ui/BarSignBoundUserInterface.cs
Normal file
50
Content.Client/BarSign/Ui/BarSignBoundUserInterface.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.BarSign;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.BarSign.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class BarSignBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
private BarSignMenu? _menu;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
var sign = EntMan.GetComponentOrNull<BarSignComponent>(Owner)?.Current is { } current
|
||||
? _prototype.Index(current)
|
||||
: null;
|
||||
var allSigns = Shared.BarSign.BarSignSystem.GetAllBarSigns(_prototype)
|
||||
.OrderBy(p => Loc.GetString(p.Name))
|
||||
.ToList();
|
||||
_menu = new(sign, allSigns);
|
||||
|
||||
_menu.OnSignSelected += id =>
|
||||
{
|
||||
SendMessage(new SetBarSignMessage(id));
|
||||
};
|
||||
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
public void Update(ProtoId<BarSignPrototype>? sign)
|
||||
{
|
||||
if (_prototype.TryIndex(sign, out var signPrototype))
|
||||
_menu?.UpdateState(signPrototype);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
_menu?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
19
Content.Client/BarSign/Ui/BarSignMenu.xaml
Normal file
19
Content.Client/BarSign/Ui/BarSignMenu.xaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<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 'barsign-ui-menu'}"
|
||||
MinSize="280 180"
|
||||
SetSize="280 180">
|
||||
<BoxContainer VerticalExpand="True" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10 5 10 10">
|
||||
<BoxContainer Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<BoxContainer Orientation="Vertical" HorizontalAlignment="Center">
|
||||
<Label Text="{Loc 'barsign-ui-set-label'}" HorizontalAlignment="Center" StyleClasses="LabelSubText" Margin="30 0"/>
|
||||
<customControls:HSeparator Margin="0 0 0 5"/>
|
||||
</BoxContainer>
|
||||
<OptionButton Name="SignOptions" HorizontalAlignment="Center" VerticalAlignment="Center" MinSize="175 60" Margin="0 0 0 20"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
||||
|
||||
50
Content.Client/BarSign/Ui/BarSignMenu.xaml.cs
Normal file
50
Content.Client/BarSign/Ui/BarSignMenu.xaml.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.BarSign;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.BarSign.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BarSignMenu : FancyWindow
|
||||
{
|
||||
private string? _currentId;
|
||||
|
||||
private readonly List<BarSignPrototype> _cachedPrototypes = new();
|
||||
|
||||
public event Action<string>? OnSignSelected;
|
||||
|
||||
public BarSignMenu(BarSignPrototype? currentSign, List<BarSignPrototype> signs)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_currentId = currentSign?.ID;
|
||||
|
||||
_cachedPrototypes.Clear();
|
||||
_cachedPrototypes = signs;
|
||||
foreach (var proto in _cachedPrototypes)
|
||||
{
|
||||
SignOptions.AddItem(Loc.GetString(proto.Name));
|
||||
}
|
||||
|
||||
SignOptions.OnItemSelected += idx =>
|
||||
{
|
||||
OnSignSelected?.Invoke(_cachedPrototypes[idx.Id].ID);
|
||||
SignOptions.SelectId(idx.Id);
|
||||
};
|
||||
|
||||
if (currentSign != null)
|
||||
{
|
||||
var idx = _cachedPrototypes.IndexOf(currentSign);
|
||||
SignOptions.TrySelectId(idx);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateState(BarSignPrototype newSign)
|
||||
{
|
||||
if (_currentId != null && newSign.ID == _currentId)
|
||||
return;
|
||||
_currentId = newSign.ID;
|
||||
var idx = _cachedPrototypes.IndexOf(newSign);
|
||||
SignOptions.TrySelectId(idx);
|
||||
}
|
||||
}
|
||||
@@ -65,14 +65,13 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
|
||||
{
|
||||
if (_isClientTyping == isClientTyping)
|
||||
return;
|
||||
_isClientTyping = isClientTyping;
|
||||
|
||||
// check if player controls any pawn
|
||||
// check if player controls any entity.
|
||||
if (_playerManager.LocalEntity == null)
|
||||
return;
|
||||
|
||||
// send a networked event to server
|
||||
RaiseNetworkEvent(new TypingChangedEvent(isClientTyping));
|
||||
_isClientTyping = isClientTyping;
|
||||
RaisePredictiveEvent(new TypingChangedEvent(isClientTyping));
|
||||
}
|
||||
|
||||
private void OnShowTypingChanged(bool showTyping)
|
||||
|
||||
@@ -2,21 +2,36 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Inventory;
|
||||
|
||||
namespace Content.Client.Chat.TypingIndicator;
|
||||
|
||||
public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingIndicatorComponent>
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
|
||||
|
||||
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
if (!_prototypeManager.TryIndex<TypingIndicatorPrototype>(component.Prototype, out var proto))
|
||||
var currentTypingIndicator = component.TypingIndicatorPrototype;
|
||||
|
||||
var evt = new BeforeShowTypingIndicatorEvent();
|
||||
|
||||
if (TryComp<InventoryComponent>(uid, out var inventoryComp))
|
||||
_inventory.RelayEvent((uid, inventoryComp), ref evt);
|
||||
|
||||
var overrideIndicator = evt.GetMostRecentIndicator();
|
||||
|
||||
if (overrideIndicator != null)
|
||||
currentTypingIndicator = overrideIndicator.Value;
|
||||
|
||||
if (!_prototypeManager.TryIndex(currentTypingIndicator, out var proto))
|
||||
{
|
||||
Log.Error($"Unknown typing indicator id: {component.Prototype}");
|
||||
Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Content.Client.Clickable
|
||||
Angle cardinalSnapping = sprite.SnapCardinals ? relativeRotation.GetCardinalDir().ToAngle() : Angle.Zero;
|
||||
|
||||
// First we get `localPos`, the clicked location in the sprite-coordinate frame.
|
||||
var entityXform = Matrix3Helpers.CreateInverseTransform(transform.WorldPosition, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping);
|
||||
var entityXform = Matrix3Helpers.CreateInverseTransform(spritePos, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping);
|
||||
var localPos = Vector2.Transform(Vector2.Transform(worldPos, entityXform), invSpriteMatrix);
|
||||
|
||||
// Check explicitly defined click-able bounds
|
||||
@@ -58,8 +58,11 @@ namespace Content.Client.Clickable
|
||||
// Next check each individual sprite layer using automatically computed click maps.
|
||||
foreach (var spriteLayer in sprite.AllLayers)
|
||||
{
|
||||
if (!spriteLayer.Visible || spriteLayer is not Layer layer)
|
||||
// TODO: Move this to a system and also use SpriteSystem.IsVisible instead.
|
||||
if (!spriteLayer.Visible || spriteLayer is not Layer layer || layer.CopyToShaderParameters != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the layer's texture, if it has one
|
||||
if (layer.Texture != null)
|
||||
|
||||
26
Content.Client/Clock/ClockSystem.cs
Normal file
26
Content.Client/Clock/ClockSystem.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Shared.Clock;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Clock;
|
||||
|
||||
public sealed class ClockSystem : SharedClockSystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ClockComponent, SpriteComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp, out var sprite))
|
||||
{
|
||||
if (!sprite.LayerMapTryGet(ClockVisualLayers.HourHand, out var hourLayer) ||
|
||||
!sprite.LayerMapTryGet(ClockVisualLayers.MinuteHand, out var minuteLayer))
|
||||
continue;
|
||||
|
||||
var time = GetClockTime((uid, comp));
|
||||
var hourState = $"{comp.HoursBase}{time.Hours % 12}";
|
||||
var minuteState = $"{comp.MinutesBase}{time.Minutes / 5}";
|
||||
sprite.LayerSetState(hourLayer, hourState);
|
||||
sprite.LayerSetState(minuteLayer, minuteState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,7 +331,19 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var displacementLayer = _serialization.CreateCopy(displacementData.Layer, notNullableOverride: true);
|
||||
//CP14 48*48 displacement maps support
|
||||
var displacementDataLayer = displacementData.Layer;
|
||||
var actualRSI = sprite.LayerGetActualRSI(index);
|
||||
if (actualRSI != null)
|
||||
{
|
||||
var layerSize = actualRSI.Size;
|
||||
if (layerSize.X == 48 && displacementData.Layer48 != null)
|
||||
displacementDataLayer = displacementData.Layer48;
|
||||
}
|
||||
|
||||
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
|
||||
//CP14 48*48 displacement maps support end
|
||||
|
||||
displacementLayer.CopyToShaderParameters!.LayerKey = key;
|
||||
|
||||
// Add before main layer for this item.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Clothing.Systems;
|
||||
using Content.Client.Stylesheets;
|
||||
@@ -74,13 +74,9 @@ public sealed partial class ChameleonMenu : DefaultWindow
|
||||
};
|
||||
button.OnPressed += _ => OnIdSelected?.Invoke(id);
|
||||
Grid.AddChild(button);
|
||||
|
||||
var texture = _sprite.GetPrototypeIcon(proto);
|
||||
button.AddChild(new TextureRect
|
||||
{
|
||||
Stretch = TextureRect.StretchMode.KeepAspectCentered,
|
||||
Texture = texture.Default
|
||||
});
|
||||
var entityPrototypeView = new EntityPrototypeView();
|
||||
button.AddChild(entityPrototypeView);
|
||||
entityPrototypeView.SetPrototype(proto);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public sealed class ZoomCommand : LocalizedCommands
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
Vector2 zoom;
|
||||
if (args.Length is not (1 or 2))
|
||||
if (args.Length is not (1 or 2 or 3))
|
||||
{
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
@@ -57,11 +57,18 @@ public sealed class ZoomCommand : LocalizedCommands
|
||||
}
|
||||
}
|
||||
|
||||
var scalePvs = true;
|
||||
if (args.Length == 3 && !bool.TryParse(args[2], out scalePvs))
|
||||
{
|
||||
shell.WriteError(LocalizationManager.GetString("cmd-parse-failure-bool", ("arg", args[2])));
|
||||
return;
|
||||
}
|
||||
|
||||
var player = _playerManager.LocalSession?.AttachedEntity;
|
||||
|
||||
if (_entityManager.TryGetComponent<ContentEyeComponent>(player, out var content))
|
||||
{
|
||||
_entityManager.System<ContentEyeSystem>().RequestZoom(player.Value, zoom, true, content);
|
||||
_entityManager.System<ContentEyeSystem>().RequestZoom(player.Value, zoom, true, scalePvs, content);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,9 @@ namespace Content.Client.Communications.UI
|
||||
}
|
||||
|
||||
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle");
|
||||
CountdownLabel.SetMessage($"Time remaining\n{Owner.Countdown.ToString()}s");
|
||||
var infoText = Loc.GetString($"comms-console-menu-time-remaining",
|
||||
("time", Owner.Countdown.ToString()));
|
||||
CountdownLabel.SetMessage(infoText);
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace Content.Client.Construction
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.OpenCraftingMenu,
|
||||
new PointerInputCmdHandler(HandleOpenCraftingMenu, outsidePrediction:true))
|
||||
new PointerInputCmdHandler(HandleOpenCraftingMenu, outsidePrediction: true))
|
||||
.Bind(EngineKeyFunctions.Use,
|
||||
new PointerInputCmdHandler(HandleUse, outsidePrediction: true))
|
||||
.Bind(ContentKeyFunctions.EditorFlipObject,
|
||||
new PointerInputCmdHandler(HandleFlip, outsidePrediction:true))
|
||||
new PointerInputCmdHandler(HandleFlip, outsidePrediction: true))
|
||||
.Register<ConstructionSystem>();
|
||||
|
||||
SubscribeLocalEvent<ConstructionGhostComponent, ExaminedEvent>(HandleConstructionGhostExamined);
|
||||
@@ -196,7 +196,7 @@ namespace Content.Client.Construction
|
||||
if (GhostPresent(loc))
|
||||
return false;
|
||||
|
||||
var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager, _transformSystem));
|
||||
var predicate = GetPredicate(prototype.CanBuildInImpassable, _transformSystem.ToMapCoordinates(loc));
|
||||
if (!_examineSystem.InRangeUnOccluded(user, loc, 20f, predicate: predicate))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5">
|
||||
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/>
|
||||
<OptionButton Name="Category" Access="Public" MinSize="130 0"/>
|
||||
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/>
|
||||
</BoxContainer>
|
||||
<ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/>
|
||||
</BoxContainer>
|
||||
<Control MinSize="10 0"/>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
|
||||
<Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
|
||||
HorizontalAlignment="Right" Margin="0 0 0 15"/>
|
||||
<Control>
|
||||
<BoxContainer Orientation="Horizontal" Align="Center">
|
||||
<TextureRect Name="TargetTexture" HorizontalAlignment="Right" Stretch="Keep"/>
|
||||
<Control MinSize="10 0"/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<RichTextLabel Name="TargetName"/>
|
||||
<RichTextLabel Name="TargetDesc"/>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5">
|
||||
<BoxContainer Orientation="Horizontal" Align="Center">
|
||||
<TextureRect Name="TargetTexture" HorizontalAlignment="Right" Stretch="Keep" Margin="0 0 10 0"/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<RichTextLabel Name="TargetName"/>
|
||||
<RichTextLabel Name="TargetDesc"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
<ItemList Name="RecipeStepList" Access="Public" VerticalExpand="True"/>
|
||||
<ItemList Name="RecipeStepList" Access="Public" VerticalExpand="True" Margin="0 0 0 5"/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Button Name="BuildButton" Disabled="True" ToggleMode="True" VerticalExpand="True" SizeFlagsStretchRatio="0.5"/>
|
||||
<Button Name="BuildButton" Disabled="True" ToggleMode="True"
|
||||
VerticalExpand="True" SizeFlagsStretchRatio="0.5"/>
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True" SizeFlagsStretchRatio="0.5">
|
||||
<Button Name="EraseButton" ToggleMode="True" HorizontalExpand="True" SizeFlagsStretchRatio="0.7"/>
|
||||
<Button Name="EraseButton" ToggleMode="True"
|
||||
HorizontalExpand="True" SizeFlagsStretchRatio="0.7"/>
|
||||
<Button Name="ClearButton" HorizontalExpand="True" SizeFlagsStretchRatio="0.3"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Content.Client.Construction.UI
|
||||
// It isn't optimal to expose UI controls like this, but the UI control design is
|
||||
// questionable so it can't be helped.
|
||||
string[] Categories { get; set; }
|
||||
OptionButton Category { get; }
|
||||
OptionButton OptionCategories { get; }
|
||||
|
||||
bool EraseButtonPressed { get; set; }
|
||||
bool BuildButtonPressed { get; set; }
|
||||
@@ -32,12 +32,13 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
event EventHandler<(string search, string catagory)> PopulateRecipes;
|
||||
event EventHandler<ItemList.Item?> RecipeSelected;
|
||||
event EventHandler RecipeFavorited;
|
||||
event EventHandler<bool> BuildButtonToggled;
|
||||
event EventHandler<bool> EraseButtonToggled;
|
||||
event EventHandler ClearAllGhosts;
|
||||
|
||||
void ClearRecipeInfo();
|
||||
void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem);
|
||||
void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem, bool isFavorite);
|
||||
void ResetPlacement();
|
||||
|
||||
#region Window Control
|
||||
@@ -84,10 +85,12 @@ namespace Content.Client.Construction.UI
|
||||
Recipes.OnItemSelected += obj => RecipeSelected?.Invoke(this, obj.ItemList[obj.ItemIndex]);
|
||||
Recipes.OnItemDeselected += _ => RecipeSelected?.Invoke(this, null);
|
||||
|
||||
SearchBar.OnTextChanged += _ => PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[Category.SelectedId]));
|
||||
Category.OnItemSelected += obj =>
|
||||
SearchBar.OnTextChanged += _ =>
|
||||
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId]));
|
||||
OptionCategories.OnItemSelected += obj =>
|
||||
{
|
||||
Category.SelectId(obj.Id);
|
||||
OptionCategories.SelectId(obj.Id);
|
||||
SearchBar.SetText(string.Empty);
|
||||
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[obj.Id]));
|
||||
};
|
||||
|
||||
@@ -97,12 +100,14 @@ namespace Content.Client.Construction.UI
|
||||
ClearButton.OnPressed += _ => ClearAllGhosts?.Invoke(this, EventArgs.Empty);
|
||||
EraseButton.Text = Loc.GetString("construction-menu-eraser-mode");
|
||||
EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed);
|
||||
|
||||
FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler? ClearAllGhosts;
|
||||
|
||||
public event EventHandler<(string search, string catagory)>? PopulateRecipes;
|
||||
public event EventHandler<ItemList.Item?>? RecipeSelected;
|
||||
public event EventHandler? RecipeFavorited;
|
||||
public event EventHandler<bool>? BuildButtonToggled;
|
||||
public event EventHandler<bool>? EraseButtonToggled;
|
||||
|
||||
@@ -112,13 +117,17 @@ namespace Content.Client.Construction.UI
|
||||
EraseButton.Pressed = false;
|
||||
}
|
||||
|
||||
public void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem)
|
||||
public void SetRecipeInfo(
|
||||
string name, string description, Texture iconTexture, bool isItem, bool isFavorite)
|
||||
{
|
||||
BuildButton.Disabled = false;
|
||||
BuildButton.Text = Loc.GetString(isItem ? "construction-menu-place-ghost" : "construction-menu-craft");
|
||||
TargetName.SetMessage(name);
|
||||
TargetDesc.SetMessage(description);
|
||||
TargetTexture.Texture = iconTexture;
|
||||
FavoriteButton.Visible = true;
|
||||
FavoriteButton.Text = Loc.GetString(
|
||||
isFavorite ? "construction-add-favorite-button" : "construction-remove-from-favorite-button");
|
||||
}
|
||||
|
||||
public void ClearRecipeInfo()
|
||||
@@ -127,6 +136,7 @@ namespace Content.Client.Construction.UI
|
||||
TargetName.SetMessage(string.Empty);
|
||||
TargetDesc.SetMessage(string.Empty);
|
||||
TargetTexture.Texture = null;
|
||||
FavoriteButton.Visible = false;
|
||||
RecipeStepList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
private ConstructionSystem? _constructionSystem;
|
||||
private ConstructionPrototype? _selected;
|
||||
|
||||
private List<ConstructionPrototype> _favoritedRecipes = [];
|
||||
private string _selectedCategory = string.Empty;
|
||||
private string _favoriteCatName = "construction-category-favorites";
|
||||
private string _forAllCategoryName = "construction-category-all";
|
||||
private bool CraftingAvailable
|
||||
{
|
||||
get => _uiManager.GetActiveUIWidget<GameTopMenuBar>().CraftingButton.Visible;
|
||||
@@ -65,7 +68,7 @@ namespace Content.Client.Construction.UI
|
||||
else
|
||||
_constructionView.OpenCentered();
|
||||
|
||||
if(_selected != null)
|
||||
if (_selected != null)
|
||||
PopulateInfo(_selected);
|
||||
}
|
||||
else
|
||||
@@ -105,9 +108,10 @@ namespace Content.Client.Construction.UI
|
||||
_constructionView.EraseButtonPressed = b;
|
||||
};
|
||||
|
||||
_constructionView.RecipeFavorited += (_, _) => OnViewFavoriteRecipe();
|
||||
|
||||
PopulateCategories();
|
||||
OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty));
|
||||
|
||||
}
|
||||
|
||||
public void OnHudCraftingButtonToggled(ButtonToggledEventArgs args)
|
||||
@@ -154,6 +158,13 @@ namespace Content.Client.Construction.UI
|
||||
recipesList.Clear();
|
||||
var recipes = new List<ConstructionPrototype>();
|
||||
|
||||
var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName;
|
||||
|
||||
if (isEmptyCategory)
|
||||
_selectedCategory = string.Empty;
|
||||
else
|
||||
_selectedCategory = category;
|
||||
|
||||
foreach (var recipe in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
|
||||
{
|
||||
if (recipe.Hide)
|
||||
@@ -173,10 +184,19 @@ namespace Content.Client.Construction.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(category) && category != "construction-category-all")
|
||||
if (!isEmptyCategory)
|
||||
{
|
||||
if (recipe.Category != category)
|
||||
if (category == _favoriteCatName)
|
||||
{
|
||||
if (!_favoritedRecipes.Contains(recipe))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (recipe.Category != category)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
recipes.Add(recipe);
|
||||
@@ -192,13 +212,10 @@ namespace Content.Client.Construction.UI
|
||||
// There is apparently no way to set which
|
||||
}
|
||||
|
||||
private void PopulateCategories()
|
||||
private void PopulateCategories(string? selectCategory = null)
|
||||
{
|
||||
var uniqueCategories = new HashSet<string>();
|
||||
|
||||
// hard-coded to show all recipes
|
||||
uniqueCategories.Add("construction-category-all");
|
||||
|
||||
foreach (var prototype in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
|
||||
{
|
||||
var category = prototype.Category;
|
||||
@@ -207,25 +224,49 @@ namespace Content.Client.Construction.UI
|
||||
uniqueCategories.Add(category);
|
||||
}
|
||||
|
||||
_constructionView.Category.Clear();
|
||||
var isFavorites = _favoritedRecipes.Count > 0;
|
||||
var categoriesArray = new string[isFavorites ? uniqueCategories.Count + 2 : uniqueCategories.Count + 1];
|
||||
|
||||
var array = uniqueCategories.OrderBy(Loc.GetString).ToArray();
|
||||
Array.Sort(array);
|
||||
// hard-coded to show all recipes
|
||||
var idx = 0;
|
||||
categoriesArray[idx++] = _forAllCategoryName;
|
||||
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
// hard-coded to show favorites if it need
|
||||
if (isFavorites)
|
||||
{
|
||||
var category = array[i];
|
||||
_constructionView.Category.AddItem(Loc.GetString(category), i);
|
||||
categoriesArray[idx++] = _favoriteCatName;
|
||||
}
|
||||
|
||||
_constructionView.Categories = array;
|
||||
var sortedProtoCategories = uniqueCategories.OrderBy(Loc.GetString);
|
||||
|
||||
foreach (var cat in sortedProtoCategories)
|
||||
{
|
||||
categoriesArray[idx++] = cat;
|
||||
}
|
||||
|
||||
_constructionView.OptionCategories.Clear();
|
||||
|
||||
for (var i = 0; i < categoriesArray.Length; i++)
|
||||
{
|
||||
_constructionView.OptionCategories.AddItem(Loc.GetString(categoriesArray[i]), i);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectCategory) && selectCategory == categoriesArray[i])
|
||||
_constructionView.OptionCategories.SelectId(i);
|
||||
|
||||
}
|
||||
|
||||
_constructionView.Categories = categoriesArray;
|
||||
}
|
||||
|
||||
private void PopulateInfo(ConstructionPrototype prototype)
|
||||
{
|
||||
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
|
||||
_constructionView.ClearRecipeInfo();
|
||||
_constructionView.SetRecipeInfo(prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon), prototype.Type != ConstructionType.Item);
|
||||
|
||||
_constructionView.SetRecipeInfo(
|
||||
prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon),
|
||||
prototype.Type != ConstructionType.Item,
|
||||
!_favoritedRecipes.Contains(prototype));
|
||||
|
||||
var stepList = _constructionView.RecipeStepList;
|
||||
GenerateStepList(prototype, stepList);
|
||||
@@ -243,7 +284,7 @@ namespace Content.Client.Construction.UI
|
||||
var text = entry.Arguments != null
|
||||
? Loc.GetString(entry.Localization, entry.Arguments) : Loc.GetString(entry.Localization);
|
||||
|
||||
if (entry.EntryNumber is {} number)
|
||||
if (entry.EntryNumber is { } number)
|
||||
{
|
||||
text = Loc.GetString("construction-presenter-step-wrapper",
|
||||
("step-number", number), ("text", text));
|
||||
@@ -335,6 +376,26 @@ namespace Content.Client.Construction.UI
|
||||
if (args.System is ConstructionSystem) SystemBindingChanged(null);
|
||||
}
|
||||
|
||||
private void OnViewFavoriteRecipe()
|
||||
{
|
||||
if (_selected is not ConstructionPrototype recipe)
|
||||
return;
|
||||
|
||||
if (!_favoritedRecipes.Remove(_selected))
|
||||
_favoritedRecipes.Add(_selected);
|
||||
|
||||
if (_selectedCategory == _favoriteCatName)
|
||||
{
|
||||
if (_favoritedRecipes.Count > 0)
|
||||
OnViewPopulateRecipes(_constructionView, (string.Empty, _favoriteCatName));
|
||||
else
|
||||
OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty));
|
||||
}
|
||||
|
||||
PopulateInfo(_selected);
|
||||
PopulateCategories(_selectedCategory);
|
||||
}
|
||||
|
||||
private void SystemBindingChanged(ConstructionSystem? newSystem)
|
||||
{
|
||||
if (newSystem is null)
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
if (_combatMode.IsInCombatMode(args.Session?.AttachedEntity))
|
||||
return false;
|
||||
|
||||
var coords = args.Coordinates.ToMap(_entityManager, _xform);
|
||||
var coords = _xform.ToMapCoordinates(args.Coordinates);
|
||||
|
||||
if (_verbSystem.TryGetEntityMenuEntities(coords, out var entities))
|
||||
OpenRootMenu(entities);
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
|
||||
namespace Content.Client.DebugMon;
|
||||
|
||||
/// <summary>
|
||||
/// This handles preventing certain debug monitors from appearing.
|
||||
/// This handles preventing certain debug monitors from being usable by non-admins.
|
||||
/// </summary>
|
||||
public sealed class DebugMonitorSystem : EntitySystem
|
||||
internal sealed class DebugMonitorManager
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IClientAdminManager _admin = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterface = default!;
|
||||
[Dependency] private readonly IBaseClient _baseClient = default!;
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
public void FrameUpdate()
|
||||
{
|
||||
if (!_admin.IsActive() && _cfg.GetCVar(CCVars.DebugCoordinatesAdminOnly))
|
||||
if (_baseClient.RunLevel == ClientRunLevel.InGame
|
||||
&& !_admin.IsActive()
|
||||
&& _cfg.GetCVar(CCVars.DebugCoordinatesAdminOnly))
|
||||
{
|
||||
_userInterface.DebugMonitors.SetMonitor(DebugMonitor.Coords, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Robust.Client.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Client.DoAfter;
|
||||
|
||||
@@ -19,6 +20,7 @@ public sealed class DoAfterOverlay : Overlay
|
||||
private readonly SharedTransformSystem _transform;
|
||||
private readonly MetaDataSystem _meta;
|
||||
private readonly ProgressColorSystem _progressColor;
|
||||
private readonly SharedContainerSystem _container;
|
||||
|
||||
private readonly Texture _barTexture;
|
||||
private readonly ShaderInstance _unshadedShader;
|
||||
@@ -41,6 +43,7 @@ public sealed class DoAfterOverlay : Overlay
|
||||
_player = player;
|
||||
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
|
||||
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
|
||||
_container = _entManager.EntitySysManager.GetEntitySystem<SharedContainerSystem>();
|
||||
_progressColor = _entManager.System<ProgressColorSystem>();
|
||||
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
|
||||
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
|
||||
@@ -98,11 +101,13 @@ public sealed class DoAfterOverlay : Overlay
|
||||
|
||||
var offset = 0f;
|
||||
|
||||
var isInContainer = _container.IsEntityOrParentInContainer(uid, meta, xform);
|
||||
|
||||
foreach (var doAfter in comp.DoAfters.Values)
|
||||
{
|
||||
// Hide some DoAfters from other players for stealthy actions (ie: thieving gloves)
|
||||
var alpha = 1f;
|
||||
if (doAfter.Args.Hidden)
|
||||
if (doAfter.Args.Hidden || isInContainer)
|
||||
{
|
||||
if (uid != localEnt)
|
||||
continue;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
using Content.Client.DebugMon;
|
||||
using Content.Client.Eui;
|
||||
using Content.Client.Fullscreen;
|
||||
using Content.Client.GhostKick;
|
||||
@@ -34,6 +35,7 @@ using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Replays;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Entry
|
||||
{
|
||||
@@ -69,6 +71,7 @@ namespace Content.Client.Entry
|
||||
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
|
||||
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
@@ -206,5 +209,13 @@ namespace Content.Client.Entry
|
||||
_stateManager.RequestStateChange<MainScreen>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
||||
{
|
||||
if (level == ModUpdateLevel.FramePreEngine)
|
||||
{
|
||||
_debugMonitorManager.FrameUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Client.Verbs;
|
||||
using Content.Shared.Eye.Blinding;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
@@ -16,8 +15,6 @@ using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using Content.Shared.Eye.Blinding.Components;
|
||||
using Robust.Client;
|
||||
using static Content.Shared.Interaction.SharedInteractionSystem;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using Content.Shared.Interaction.Events;
|
||||
@@ -46,6 +43,8 @@ namespace Content.Client.Examine
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesOutsidePrediction = true;
|
||||
|
||||
SubscribeLocalEvent<GetVerbsEvent<ExamineVerb>>(AddExamineVerb);
|
||||
@@ -358,10 +357,7 @@ namespace Content.Client.Examine
|
||||
|
||||
FormattedMessage message;
|
||||
|
||||
// Basically this just predicts that we can't make out the entity if we have poor vision.
|
||||
var canSeeClearly = !HasComp<BlurryVisionComponent>(playerEnt);
|
||||
|
||||
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false, knowTarget: canSeeClearly);
|
||||
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false);
|
||||
|
||||
// Always update tooltip info from client first.
|
||||
// If we get it wrong, server will correct us later anyway.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
using Content.Shared.Extinguisher;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.Extinguisher;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent;
|
||||
@@ -16,7 +16,7 @@ public sealed class AdminFaxEui : BaseEui
|
||||
_window.OnClose += () => SendMessage(new AdminFaxEuiMsg.Close());
|
||||
_window.OnFollowFax += entity => SendMessage(new AdminFaxEuiMsg.Follow(entity));
|
||||
_window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.entity, args.title,
|
||||
args.stampedBy, args.message, args.stampSprite, args.stampColor));
|
||||
args.stampedBy, args.message, args.stampSprite, args.stampColor, args.locked));
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</BoxContainer>
|
||||
<Label Text="{Loc admin-fax-stamp-color}" />
|
||||
<ColorSelectorSliders Margin="12 0 0 0" Name="StampColorSelector" Color="#BB3232"/>
|
||||
<Control MinHeight="10" />
|
||||
<Button Name="SendButton" Text="{Loc admin-fax-send}"></Button>
|
||||
<CheckBox Name="LockPageCheckbox" Text="{Loc admin-fax-lock-page}" ToolTip="{Loc admin-fax-lock-page-tooltip}"/>
|
||||
<Button Name="SendButton" Text="{Loc admin-fax-send}" Margin="0 10 0 0" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -14,7 +14,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
|
||||
{
|
||||
private const string StampsRsiPath = "/Textures/Objects/Misc/bureaucracy.rsi";
|
||||
|
||||
public Action<(NetEntity entity, string title, string stampedBy, string message, string stampSprite, Color stampColor)>? OnMessageSend;
|
||||
public Action<(NetEntity entity, string title, string stampedBy, string message, string stampSprite, Color stampColor, bool locked)>? OnMessageSend;
|
||||
public Action<NetEntity>? OnFollowFax;
|
||||
|
||||
[Dependency] private readonly IResourceCache _resCache = default!;
|
||||
@@ -98,6 +98,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
|
||||
|
||||
var from = FromEdit.Text;
|
||||
var stampColor = StampColorSelector.Color;
|
||||
OnMessageSend?.Invoke((faxEntity.Value, title, from, message, stamp, stampColor));
|
||||
var locked = LockPageCheckbox.Pressed;
|
||||
OnMessageSend?.Invoke((faxEntity.Value, title, from, message, stamp, stampColor, locked));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
using Content.Shared.Flash;
|
||||
using Content.Shared.Flash.Components;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Client.Viewport;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace Content.Client.Flash
|
||||
{
|
||||
public sealed class FlashOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IClyde _displayManager = default!;
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private readonly StatusEffectsSystem _statusSys;
|
||||
private readonly StatusEffectsSystem _statusSys;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
private readonly ShaderInstance _shader;
|
||||
@@ -56,20 +51,6 @@ namespace Content.Client.Flash
|
||||
PercentComplete = timeDone / lastsFor;
|
||||
}
|
||||
|
||||
public void ReceiveFlash()
|
||||
{
|
||||
if (_stateManager.CurrentState is IMainViewportState state)
|
||||
{
|
||||
// take a screenshot
|
||||
// note that the callback takes a while and ScreenshotTexture will be null the first few Draws
|
||||
state.Viewport.Viewport.Screenshot(image =>
|
||||
{
|
||||
var rgba32Image = image.CloneAs<Rgba32>(SixLabors.ImageSharp.Configuration.Default);
|
||||
ScreenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp))
|
||||
@@ -82,6 +63,11 @@ namespace Content.Client.Flash
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (RequestScreenTexture && ScreenTexture != null)
|
||||
{
|
||||
ScreenshotTexture = ScreenTexture;
|
||||
RequestScreenTexture = false; // we only need the first frame, so we can stop the request now for performance reasons
|
||||
}
|
||||
if (ScreenshotTexture == null)
|
||||
return;
|
||||
|
||||
@@ -96,7 +82,6 @@ namespace Content.Client.Flash
|
||||
{
|
||||
base.DisposeBehavior();
|
||||
ScreenshotTexture = null;
|
||||
PercentComplete = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ public sealed class FlashSystem : SharedFlashSystem
|
||||
SubscribeLocalEvent<FlashedComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<FlashedComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<FlashedComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<FlashedComponent, StatusEffectAddedEvent>(OnStatusAdded);
|
||||
|
||||
_overlay = new();
|
||||
}
|
||||
@@ -34,8 +33,8 @@ public sealed class FlashSystem : SharedFlashSystem
|
||||
|
||||
private void OnPlayerDetached(EntityUid uid, FlashedComponent component, LocalPlayerDetachedEvent args)
|
||||
{
|
||||
_overlay.PercentComplete = 1.0f;
|
||||
_overlay.ScreenshotTexture = null;
|
||||
_overlay.RequestScreenTexture = false;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
|
||||
@@ -43,6 +42,7 @@ public sealed class FlashSystem : SharedFlashSystem
|
||||
{
|
||||
if (_player.LocalEntity == uid)
|
||||
{
|
||||
_overlay.RequestScreenTexture = true;
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
}
|
||||
@@ -51,17 +51,9 @@ public sealed class FlashSystem : SharedFlashSystem
|
||||
{
|
||||
if (_player.LocalEntity == uid)
|
||||
{
|
||||
_overlay.PercentComplete = 1.0f;
|
||||
_overlay.ScreenshotTexture = null;
|
||||
_overlay.RequestScreenTexture = false;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStatusAdded(EntityUid uid, FlashedComponent component, StatusEffectAddedEvent args)
|
||||
{
|
||||
if (_player.LocalEntity == uid && args.Key == FlashedKey)
|
||||
{
|
||||
_overlay.ReceiveFlash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace Content.Client.Gameplay
|
||||
|
||||
public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates)
|
||||
{
|
||||
return GetClickableEntities(coordinates.ToMap(_entityManager, _entitySystemManager.GetEntitySystem<SharedTransformSystem>()));
|
||||
var transformSystem = _entitySystemManager.GetEntitySystem<SharedTransformSystem>();
|
||||
return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates));
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates)
|
||||
|
||||
@@ -15,6 +15,7 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Hands.Systems
|
||||
@@ -28,6 +29,7 @@ namespace Content.Client.Hands.Systems
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly StrippableSystem _stripSys = default!;
|
||||
[Dependency] private readonly ExamineSystem _examine = default!;
|
||||
[Dependency] private readonly ISerializationManager _serialization = default!; //CP14
|
||||
|
||||
public event Action<string, HandLocation>? OnPlayerAddHand;
|
||||
public event Action<string>? OnPlayerRemoveHand;
|
||||
@@ -322,6 +324,8 @@ namespace Content.Client.Hands.Systems
|
||||
return;
|
||||
}
|
||||
|
||||
var displacementData = handComp.Displacements.GetValueOrDefault("Hands"); //CP14 hands displacements
|
||||
|
||||
// add the new layers
|
||||
foreach (var (key, layerData) in ev.Layers)
|
||||
{
|
||||
@@ -345,6 +349,39 @@ namespace Content.Client.Hands.Systems
|
||||
}
|
||||
|
||||
sprite.LayerSetData(index, layerData);
|
||||
|
||||
//CP14 Hands displacement maps
|
||||
if (displacementData != null)
|
||||
{
|
||||
if (displacementData.ShaderOverride != null)
|
||||
sprite.LayerSetShader(index, displacementData.ShaderOverride);
|
||||
|
||||
var displacementKey = $"{key}-displacement";
|
||||
if (!revealedLayers.Add(displacementKey))
|
||||
{
|
||||
Log.Warning($"Duplicate key for inhand layers DISPLACEMENT: {displacementKey}.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var displacementDataLayer = displacementData.Layer;
|
||||
var actualRSI = sprite.LayerGetActualRSI(index);
|
||||
if (actualRSI != null)
|
||||
{
|
||||
var layerSize = actualRSI.Size;
|
||||
if (layerSize.X == 48 && displacementData.Layer48 != null)
|
||||
displacementDataLayer = displacementData.Layer48;
|
||||
}
|
||||
|
||||
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
|
||||
displacementLayer.CopyToShaderParameters!.LayerKey = key;
|
||||
|
||||
// Add before main layer for this item.
|
||||
sprite.AddLayer(displacementLayer, index);
|
||||
sprite.LayerMapSet(displacementKey, index);
|
||||
|
||||
revealedLayers.Add(displacementKey);
|
||||
}
|
||||
//CP14 Hands displacement maps - end
|
||||
}
|
||||
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
using Content.Client.Clickable;
|
||||
using Content.Client.DebugMon;
|
||||
using Content.Client.Eui;
|
||||
using Content.Client.GhostKick;
|
||||
using Content.Client.Launcher;
|
||||
@@ -48,6 +49,7 @@ namespace Content.Client.IoC
|
||||
collection.Register<DocumentParsingManager>();
|
||||
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
||||
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
||||
collection.Register<DebugMonitorManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Content.Shared.Item.ItemToggle;
|
||||
|
||||
namespace Content.Shared.Item;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class ItemToggleSystem : SharedItemToggleSystem
|
||||
{
|
||||
|
||||
}
|
||||
@@ -48,6 +48,9 @@ namespace Content.Client.Jittering
|
||||
if(args.Key != _jitterAnimationKey)
|
||||
return;
|
||||
|
||||
if (!args.Finished)
|
||||
return;
|
||||
|
||||
if (TryComp(uid, out AnimationPlayerComponent? animationPlayer)
|
||||
&& TryComp(uid, out SpriteComponent? sprite))
|
||||
_animationPlayer.Play(uid, animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey);
|
||||
|
||||
@@ -217,12 +217,12 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||
queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
|
||||
|
||||
var queuedRecipeProto = new EntityPrototypeView();
|
||||
queuedRecipeBox.AddChild(queuedRecipeProto);
|
||||
if (_prototypeManager.TryIndex(recipe.Result, out EntityPrototype? entityProto) && entityProto != null)
|
||||
queuedRecipeProto.SetPrototype(entityProto);
|
||||
|
||||
var queuedRecipeLabel = new Label();
|
||||
queuedRecipeLabel.Text = $"{idx}. {recipe.Name}";
|
||||
queuedRecipeBox.AddChild(queuedRecipeProto);
|
||||
queuedRecipeBox.AddChild(queuedRecipeLabel);
|
||||
QueueList.AddChild(queuedRecipeBox);
|
||||
idx++;
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Content.Client.Launcher
|
||||
private void ChangeLoginTip()
|
||||
{
|
||||
var tipsDataset = _cfg.GetCVar(CCVars.LoginTipsDataset);
|
||||
var loginTipsEnabled = _prototype.TryIndex<DatasetPrototype>(tipsDataset, out var tips);
|
||||
var loginTipsEnabled = _prototype.TryIndex<LocalizedDatasetPrototype>(tipsDataset, out var tips);
|
||||
|
||||
LoginTips.Visible = loginTipsEnabled;
|
||||
if (!loginTipsEnabled)
|
||||
@@ -131,7 +131,7 @@ namespace Content.Client.Launcher
|
||||
|
||||
var randomIndex = _random.Next(tipList.Count);
|
||||
var tip = tipList[randomIndex];
|
||||
LoginTip.SetMessage(tip);
|
||||
LoginTip.SetMessage(Loc.GetString(tip));
|
||||
|
||||
LoginTipTitle.Text = Loc.GetString("connecting-window-tip", ("numberTip", randomIndex));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||
|
||||
private void OnBehaviorAnimationCompleted(EntityUid uid, LightBehaviourComponent component, AnimationCompletedEvent args)
|
||||
{
|
||||
if (!args.Finished)
|
||||
return;
|
||||
|
||||
var container = component.Animations.FirstOrDefault(x => x.FullKey == args.Key);
|
||||
|
||||
if (container == null)
|
||||
|
||||
@@ -69,6 +69,9 @@ public sealed class RotatingLightSystem : SharedRotatingLightSystem
|
||||
|
||||
private void OnAnimationComplete(EntityUid uid, RotatingLightComponent comp, AnimationCompletedEvent args)
|
||||
{
|
||||
if (!args.Finished)
|
||||
return;
|
||||
|
||||
PlayAnimation(uid, comp);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
|
||||
private CharacterSetupGui? _characterSetup;
|
||||
private HumanoidProfileEditor? _profileEditor;
|
||||
private CharacterSetupGuiSavePanel? _savePanel;
|
||||
|
||||
/// <summary>
|
||||
/// This is the characher preview panel in the chat. This should only update if their character updates.
|
||||
@@ -214,6 +215,46 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
ReloadCharacterSetup();
|
||||
}
|
||||
|
||||
private void CloseProfileEditor()
|
||||
{
|
||||
if (_profileEditor == null)
|
||||
return;
|
||||
|
||||
_profileEditor.SetProfile(null, null);
|
||||
_profileEditor.Visible = false;
|
||||
|
||||
if (_stateManager.CurrentState is LobbyState lobbyGui)
|
||||
{
|
||||
lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenSavePanel()
|
||||
{
|
||||
if (_savePanel is { IsOpen: true })
|
||||
return;
|
||||
|
||||
_savePanel = new CharacterSetupGuiSavePanel();
|
||||
|
||||
_savePanel.SaveButton.OnPressed += _ =>
|
||||
{
|
||||
SaveProfile();
|
||||
|
||||
_savePanel.Close();
|
||||
|
||||
CloseProfileEditor();
|
||||
};
|
||||
|
||||
_savePanel.NoSaveButton.OnPressed += _ =>
|
||||
{
|
||||
_savePanel.Close();
|
||||
|
||||
CloseProfileEditor();
|
||||
};
|
||||
|
||||
_savePanel.OpenCentered();
|
||||
}
|
||||
|
||||
private (CharacterSetupGui, HumanoidProfileEditor) EnsureGui()
|
||||
{
|
||||
if (_characterSetup != null && _profileEditor != null)
|
||||
@@ -240,14 +281,16 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
|
||||
_characterSetup.CloseButton.OnPressed += _ =>
|
||||
{
|
||||
// Reset sliders etc.
|
||||
_profileEditor.SetProfile(null, null);
|
||||
_profileEditor.Visible = false;
|
||||
|
||||
if (_stateManager.CurrentState is LobbyState lobbyGui)
|
||||
// Open the save panel if we have unsaved changes.
|
||||
if (_profileEditor.Profile != null && _profileEditor.IsDirty)
|
||||
{
|
||||
lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default);
|
||||
OpenSavePanel();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset sliders etc.
|
||||
CloseProfileEditor();
|
||||
};
|
||||
|
||||
_profileEditor.Save += SaveProfile;
|
||||
|
||||
10
Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml
Normal file
10
Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
Title="{Loc 'character-setup-gui-save-panel-title'}"
|
||||
Resizable="False">
|
||||
|
||||
<BoxContainer Orientation="Horizontal" SeparationOverride="4" MinSize="200 40">
|
||||
<Button Name="SaveButton" Access="Public" Text="{Loc 'character-setup-gui-save-panel-save'}" StyleClasses="ButtonBig"/>
|
||||
<Button Name="NoSaveButton" Access="Public" Text="{Loc 'character-setup-gui-save-panel-nosave'}" StyleClasses="ButtonBig"/>
|
||||
<Button Name="CancelButton" Access="Public" Text="{Loc 'character-setup-gui-save-panel-cancel'}" StyleClasses="ButtonBig"/>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
21
Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml.cs
Normal file
21
Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Lobby.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CharacterSetupGuiSavePanel : DefaultWindow
|
||||
{
|
||||
public CharacterSetupGuiSavePanel()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
CancelButton.OnPressed += _ =>
|
||||
{
|
||||
Close();
|
||||
};
|
||||
|
||||
CloseButton.Visible = false;
|
||||
}
|
||||
}
|
||||
@@ -480,10 +480,10 @@ namespace Content.Client.Lobby.UI
|
||||
return;
|
||||
}
|
||||
|
||||
//Setup model
|
||||
Dictionary<string, List<string>> model = new();
|
||||
// Setup model
|
||||
Dictionary<string, List<string>> traitGroups = new();
|
||||
List<string> defaultTraits = new();
|
||||
model.Add("default", defaultTraits);
|
||||
traitGroups.Add(TraitCategoryPrototype.Default, defaultTraits);
|
||||
|
||||
foreach (var trait in traits)
|
||||
{
|
||||
@@ -493,18 +493,19 @@ namespace Content.Client.Lobby.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!model.ContainsKey(trait.Category))
|
||||
{
|
||||
model.Add(trait.Category, new());
|
||||
}
|
||||
model[trait.Category].Add(trait.ID);
|
||||
if (!_prototypeManager.HasIndex(trait.Category))
|
||||
continue;
|
||||
|
||||
var group = traitGroups.GetOrNew(trait.Category);
|
||||
group.Add(trait.ID);
|
||||
}
|
||||
|
||||
//Create UI view from model
|
||||
foreach (var (categoryId, traitId) in model)
|
||||
// Create UI view from model
|
||||
foreach (var (categoryId, categoryTraits) in traitGroups)
|
||||
{
|
||||
TraitCategoryPrototype? category = null;
|
||||
if (categoryId != "default")
|
||||
|
||||
if (categoryId != TraitCategoryPrototype.Default)
|
||||
{
|
||||
category = _prototypeManager.Index<TraitCategoryPrototype>(categoryId);
|
||||
// Label
|
||||
@@ -519,7 +520,7 @@ namespace Content.Client.Lobby.UI
|
||||
List<TraitPreferenceSelector?> selectors = new();
|
||||
var selectionCount = 0;
|
||||
|
||||
foreach (var traitProto in traitId)
|
||||
foreach (var traitProto in categoryTraits)
|
||||
{
|
||||
var trait = _prototypeManager.Index<TraitPrototype>(traitProto);
|
||||
var selector = new TraitPreferenceSelector(trait);
|
||||
@@ -530,7 +531,15 @@ namespace Content.Client.Lobby.UI
|
||||
|
||||
selector.PreferenceChanged += preference =>
|
||||
{
|
||||
Profile = Profile?.WithTraitPreference(trait.ID, categoryId, preference);
|
||||
if (preference)
|
||||
{
|
||||
Profile = Profile?.WithTraitPreference(trait.ID, _prototypeManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
Profile = Profile?.WithoutTraitPreference(trait.ID, _prototypeManager);
|
||||
}
|
||||
|
||||
SetDirty();
|
||||
RefreshTraits(); // If too many traits are selected, they will be reset to the real value.
|
||||
};
|
||||
@@ -1198,7 +1207,7 @@ namespace Content.Client.Lobby.UI
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
private bool IsDirty
|
||||
public bool IsDirty
|
||||
{
|
||||
get => _isDirty;
|
||||
set
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Content.Client.MainMenu
|
||||
[Dependency] private readonly IGameController _controllerProxy = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
private MainMenuControl _mainMenuControl = default!;
|
||||
private bool _isConnecting;
|
||||
@@ -35,6 +38,8 @@ namespace Content.Client.MainMenu
|
||||
/// <inheritdoc />
|
||||
protected override void Startup()
|
||||
{
|
||||
_sawmill = _logManager.GetSawmill("mainmenu");
|
||||
|
||||
_mainMenuControl = new MainMenuControl(_resourceCache, _configurationManager);
|
||||
_userInterfaceManager.StateRoot.AddChild(_mainMenuControl);
|
||||
|
||||
@@ -116,7 +121,7 @@ namespace Content.Client.MainMenu
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
_userInterfaceManager.Popup($"Unable to connect: {e.Message}", "Connection error.");
|
||||
Logger.Warning(e.ToString());
|
||||
_sawmill.Warning(e.ToString());
|
||||
_netManager.ConnectFailed -= _onConnectFailed;
|
||||
_setConnectingState(false);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Materials;
|
||||
@@ -49,7 +49,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
|
||||
{
|
||||
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition))
|
||||
return false;
|
||||
_transform.DetachParentToNull(toInsert, Transform(toInsert));
|
||||
_transform.DetachEntity(toInsert, Transform(toInsert));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.Replays.Loading;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -46,13 +45,19 @@ public sealed class MouseRotatorSystem : SharedMouseRotatorSystem
|
||||
// only raise event if the cardinal direction has changed
|
||||
if (rotator.Simple4DirMode)
|
||||
{
|
||||
var angleDir = angle.GetCardinalDir();
|
||||
if (angleDir == curRot.GetCardinalDir())
|
||||
var eyeRot = _eye.CurrentEye.Rotation; // camera rotation
|
||||
var angleDir = (angle + eyeRot).GetCardinalDir(); // apply GetCardinalDir in the camera frame, not in the world frame
|
||||
if (angleDir == (curRot + eyeRot).GetCardinalDir())
|
||||
return;
|
||||
|
||||
RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent()
|
||||
var rotation = angleDir.ToAngle() - eyeRot; // convert back to world frame
|
||||
if (rotation >= Math.PI) // convert to [-PI, +PI)
|
||||
rotation -= 2 * Math.PI;
|
||||
else if (rotation < -Math.PI)
|
||||
rotation += 2 * Math.PI;
|
||||
RaisePredictiveEvent(new RequestMouseRotatorRotationEvent
|
||||
{
|
||||
Direction = angleDir,
|
||||
Rotation = rotation
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
@@ -9,7 +9,7 @@ public sealed class ContentEyeSystem : SharedContentEyeSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
public void RequestZoom(EntityUid uid, Vector2 zoom, bool ignoreLimit, ContentEyeComponent? content = null)
|
||||
public void RequestZoom(EntityUid uid, Vector2 zoom, bool ignoreLimit, bool scalePvs, ContentEyeComponent? content = null)
|
||||
{
|
||||
if (!Resolve(uid, ref content, false))
|
||||
return;
|
||||
@@ -19,6 +19,14 @@ public sealed class ContentEyeSystem : SharedContentEyeSystem
|
||||
TargetZoom = zoom,
|
||||
IgnoreLimit = ignoreLimit,
|
||||
});
|
||||
|
||||
if (scalePvs)
|
||||
RequestPvsScale(Math.Max(zoom.X, zoom.Y));
|
||||
}
|
||||
|
||||
public void RequestPvsScale(float scale)
|
||||
{
|
||||
RaiseNetworkEvent(new RequestPvsScaleEvent(scale));
|
||||
}
|
||||
|
||||
public void RequestToggleFov()
|
||||
|
||||
@@ -15,6 +15,7 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ClothingSystem _clothing = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -73,11 +74,11 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
|
||||
var uidXform = Transform(uid);
|
||||
var coordinates = uidXform.Coordinates;
|
||||
var gridUid = coordinates.GetGridUid(EntityManager);
|
||||
var gridUid = _transform.GetGrid(coordinates);
|
||||
|
||||
if (TryComp<MapGridComponent>(gridUid, out var grid))
|
||||
{
|
||||
coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform)));
|
||||
coordinates = new EntityCoordinates(gridUid.Value, _mapSystem.WorldToLocal(gridUid.Value, grid, _transform.ToMapCoordinates(coordinates).Position));
|
||||
}
|
||||
else if (uidXform.MapUid != null)
|
||||
{
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace Content.Client.NPC
|
||||
if (found || !_system.Breadcrumbs.TryGetValue(netGrid, out var crumbs) || !xformQuery.TryGetComponent(grid, out var gridXform))
|
||||
continue;
|
||||
|
||||
var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||
var localAABB = invWorldMatrix.TransformBox(aabb.Enlarged(float.Epsilon - SharedPathfindingSystem.ChunkSize));
|
||||
|
||||
foreach (var chunk in crumbs)
|
||||
@@ -287,7 +287,7 @@ namespace Content.Client.NPC
|
||||
return;
|
||||
}
|
||||
|
||||
var invGridMatrix = gridXform.InvWorldMatrix;
|
||||
var invGridMatrix = _transformSystem.GetInvWorldMatrix(gridXform);
|
||||
DebugPathPoly? nearest = null;
|
||||
|
||||
foreach (var poly in tile)
|
||||
@@ -359,7 +359,7 @@ namespace Content.Client.NPC
|
||||
continue;
|
||||
}
|
||||
|
||||
var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||
worldHandle.SetTransform(worldMatrix);
|
||||
var localAABB = invWorldMatrix.TransformBox(aabb);
|
||||
|
||||
@@ -419,7 +419,7 @@ namespace Content.Client.NPC
|
||||
!xformQuery.TryGetComponent(grid, out var gridXform))
|
||||
continue;
|
||||
|
||||
var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||
worldHandle.SetTransform(worldMatrix);
|
||||
var localAABB = invWorldMatrix.TransformBox(aabb);
|
||||
|
||||
@@ -458,7 +458,7 @@ namespace Content.Client.NPC
|
||||
!xformQuery.TryGetComponent(grid, out var gridXform))
|
||||
continue;
|
||||
|
||||
var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||
worldHandle.SetTransform(worldMatrix);
|
||||
var localAABB = invMatrix.TransformBox(aabb);
|
||||
|
||||
@@ -483,7 +483,7 @@ namespace Content.Client.NPC
|
||||
if (neighborPoly.NetEntity != poly.GraphUid)
|
||||
{
|
||||
color = Color.Green;
|
||||
var neighborMap = _entManager.GetCoordinates(neighborPoly).ToMap(_entManager, _transformSystem);
|
||||
var neighborMap = _transformSystem.ToMapCoordinates(_entManager.GetCoordinates(neighborPoly));
|
||||
|
||||
if (neighborMap.MapId != args.MapId)
|
||||
continue;
|
||||
@@ -517,7 +517,7 @@ namespace Content.Client.NPC
|
||||
!xformQuery.TryGetComponent(grid, out var gridXform))
|
||||
continue;
|
||||
|
||||
var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv();
|
||||
var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||
worldHandle.SetTransform(worldMatrix);
|
||||
var localAABB = invWorldMatrix.TransformBox(args.WorldBounds);
|
||||
|
||||
@@ -544,7 +544,7 @@ namespace Content.Client.NPC
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(_entManager.GetEntity(node.GraphUid), out var graphXform))
|
||||
continue;
|
||||
|
||||
worldHandle.SetTransform(graphXform.WorldMatrix);
|
||||
worldHandle.SetTransform(_transformSystem.GetWorldMatrix(graphXform));
|
||||
worldHandle.DrawRect(node.Box, Color.Orange.WithAlpha(0.10f));
|
||||
}
|
||||
}
|
||||
@@ -568,7 +568,7 @@ namespace Content.Client.NPC
|
||||
continue;
|
||||
|
||||
matrix = graph;
|
||||
worldHandle.SetTransform(graphXform.WorldMatrix);
|
||||
worldHandle.SetTransform(_transformSystem.GetWorldMatrix(graphXform));
|
||||
}
|
||||
|
||||
worldHandle.DrawRect(node.Box, new Color(0f, cost / highestGScore, 1f - (cost / highestGScore), 0.10f));
|
||||
|
||||
5
Content.Client/Ninja/Systems/ItemCreatorSystem.cs
Normal file
5
Content.Client/Ninja/Systems/ItemCreatorSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Ninja.Systems;
|
||||
|
||||
namespace Content.Client.Ninja.Systems;
|
||||
|
||||
public sealed class ItemCreatorSystem : SharedItemCreatorSystem;
|
||||
@@ -2,9 +2,4 @@ using Content.Shared.Ninja.Systems;
|
||||
|
||||
namespace Content.Client.Ninja.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Does nothing special, only exists to provide a client implementation.
|
||||
/// </summary>
|
||||
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
|
||||
{
|
||||
}
|
||||
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem;
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
using Content.Shared.Clothing.EntitySystems;
|
||||
using Content.Shared.Ninja.Components;
|
||||
using Content.Shared.Ninja.Systems;
|
||||
|
||||
namespace Content.Client.Ninja.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Disables cloak prediction since client has no knowledge of battery power.
|
||||
/// Cloak will still be enabled after server tells it.
|
||||
/// </summary>
|
||||
public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NinjaSuitComponent, AttemptStealthEvent>(OnAttemptStealth);
|
||||
}
|
||||
|
||||
private void OnAttemptStealth(EntityUid uid, NinjaSuitComponent comp, AttemptStealthEvent args)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
public sealed class NinjaSuitSystem : SharedNinjaSuitSystem;
|
||||
|
||||
@@ -2,11 +2,4 @@ using Content.Shared.Ninja.Systems;
|
||||
|
||||
namespace Content.Client.Ninja.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Currently does nothing special clientside.
|
||||
/// All functionality is in shared and server.
|
||||
/// Only exists to prevent crashing.
|
||||
/// </summary>
|
||||
public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
|
||||
{
|
||||
}
|
||||
public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem;
|
||||
|
||||
5
Content.Client/Ninja/Systems/SpiderChargeSystem.cs
Normal file
5
Content.Client/Ninja/Systems/SpiderChargeSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Ninja.Systems;
|
||||
|
||||
namespace Content.Client.Ninja.Systems;
|
||||
|
||||
public sealed class SpiderChargeSystem : SharedSpiderChargeSystem;
|
||||
6
Content.Client/Options/UI/OptionDropDown.xaml
Normal file
6
Content.Client/Options/UI/OptionDropDown.xaml
Normal file
@@ -0,0 +1,6 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="NameLabel" MinWidth="400" />
|
||||
<OptionButton Name="Button" Access="Public" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
21
Content.Client/Options/UI/OptionDropDown.xaml.cs
Normal file
21
Content.Client/Options/UI/OptionDropDown.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Options.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Standard UI control used for drop-downs in the options menu. Intended for use with <see cref="OptionsTabControlRow"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow.AddOptionDropDown{T}"/>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class OptionDropDown : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The text describing what this drop-down controls.
|
||||
/// </summary>
|
||||
public string? Title
|
||||
{
|
||||
get => NameLabel.Text;
|
||||
set => NameLabel.Text = value;
|
||||
}
|
||||
}
|
||||
7
Content.Client/Options/UI/OptionSlider.xaml
Normal file
7
Content.Client/Options/UI/OptionSlider.xaml
Normal file
@@ -0,0 +1,7 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="NameLabel" MinWidth="400" />
|
||||
<Slider Name="Slider" Access="Public" HorizontalExpand="True" />
|
||||
<Label Name="ValueLabel" Access="Public" Margin="8 0 4 0" MinWidth="48" Align="Right" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
22
Content.Client/Options/UI/OptionSlider.xaml.cs
Normal file
22
Content.Client/Options/UI/OptionSlider.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Options.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Standard UI control used for sliders in the options menu. Intended for use with <see cref="OptionsTabControlRow"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow.AddOptionSlider"/>
|
||||
/// <seealso cref="OptionsTabControlRow.AddOptionPercentSlider"/>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class OptionSlider : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The text describing what this slider controls.
|
||||
/// </summary>
|
||||
public string? Title
|
||||
{
|
||||
get => NameLabel.Text;
|
||||
set => NameLabel.Text = value;
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,6 @@
|
||||
<tabs:GraphicsTab Name="GraphicsTab" />
|
||||
<tabs:KeyRebindTab Name="KeyRebindTab" />
|
||||
<tabs:AudioTab Name="AudioTab" />
|
||||
<tabs:AccessibilityTab Name="AccessibilityTab" />
|
||||
</TabContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.IoC;
|
||||
using Content.Client.Options.UI.Tabs;
|
||||
|
||||
|
||||
namespace Content.Client.Options.UI
|
||||
{
|
||||
@@ -19,13 +16,17 @@ namespace Content.Client.Options.UI
|
||||
Tabs.SetTabTitle(1, Loc.GetString("ui-options-tab-graphics"));
|
||||
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
|
||||
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
|
||||
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
|
||||
|
||||
UpdateTabs();
|
||||
}
|
||||
|
||||
public void UpdateTabs()
|
||||
{
|
||||
GraphicsTab.UpdateProperties();
|
||||
GraphicsTab.Control.ReloadValues();
|
||||
MiscTab.Control.ReloadValues();
|
||||
AccessibilityTab.Control.ReloadValues();
|
||||
AudioTab.Control.ReloadValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
Content.Client/Options/UI/OptionsTabControlRow.xaml
Normal file
18
Content.Client/Options/UI/OptionsTabControlRow.xaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<controls:StripeBack HasBottomEdge="False">
|
||||
<BoxContainer Orientation="Horizontal" Align="End" Margin="2">
|
||||
<Button Name="DefaultButton"
|
||||
Text="{Loc 'ui-options-default'}"
|
||||
TextAlign="Center"
|
||||
Margin="8 0" />
|
||||
|
||||
<Button Name="ResetButton"
|
||||
Text="{Loc 'ui-options-reset-all'}"
|
||||
StyleClasses="Caution" />
|
||||
<Button Name="ApplyButton"
|
||||
Text="{Loc 'ui-options-apply'}"
|
||||
StyleClasses="OpenLeft" />
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
</Control>
|
||||
684
Content.Client/Options/UI/OptionsTabControlRow.xaml.cs
Normal file
684
Content.Client/Options/UI/OptionsTabControlRow.xaml.cs
Normal file
@@ -0,0 +1,684 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Stylesheets;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.Options.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Control used on all tabs of the in-game options menu,
|
||||
/// contains the "save" and "reset" buttons and controls the entire logic.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Basic operation is simple: options tabs put this control at the bottom of the tab,
|
||||
/// they bind UI controls to it with calls such as <see cref="AddOptionCheckBox"/>,
|
||||
/// then they call <see cref="Initialize"/>. The rest is all handled by the control.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Individual options are implementations of <see cref="BaseOption"/>. See the type for details.
|
||||
/// Common implementations for building on top of CVars are already exist,
|
||||
/// but tabs can define their own if they need to.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Generally, options are added via helper methods such as <see cref="AddOptionCheckBox"/>,
|
||||
/// however it is totally possible to directly instantiate the backing types
|
||||
/// and add them via <see cref="AddOption{T}"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The options system is general purpose enough that <see cref="OptionsTabControlRow"/> does not, itself,
|
||||
/// know what a CVar is. It does automatically save CVars to config when save is pressed, but otherwise CVar interaction
|
||||
/// is handled by <see cref="BaseOption"/> implementations.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Behaviorally, the row has 3 control buttons: save, reset changed, and reset to default.
|
||||
/// "Save" writes the configuration changes and saves the configuration.
|
||||
/// "Reset changed" discards changes made in the menu and re-loads the saved settings.
|
||||
/// "Reset to default" resets the settings on the menu to be the default, out-of-the-box values.
|
||||
/// Note that "Reset to default" does not save immediately, the user must still press save manually.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The disabled state of the 3 buttons is updated dynamically based on the values of the options.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class OptionsTabControlRow : Control
|
||||
{
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
private ValueList<BaseOption> _options;
|
||||
|
||||
public OptionsTabControlRow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
ResetButton.StyleClasses.Add(StyleBase.ButtonOpenRight);
|
||||
ApplyButton.OnPressed += ApplyButtonPressed;
|
||||
ResetButton.OnPressed += ResetButtonPressed;
|
||||
DefaultButton.OnPressed += DefaultButtonPressed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new option to be tracked by the control.
|
||||
/// </summary>
|
||||
/// <param name="option">The option object that manages this object's logic</param>
|
||||
/// <typeparam name="T">
|
||||
/// The type of option being passed in. Necessary to allow the return type to match the parameter type
|
||||
/// for easy chaining.
|
||||
/// </typeparam>
|
||||
/// <returns>The same <paramref name="option"/> as passed in, for easy chaining.</returns>
|
||||
public T AddOption<T>(T option) where T : BaseOption
|
||||
{
|
||||
_options.Add(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a checkbox option backed by a simple boolean CVar.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar represented by the checkbox.</param>
|
||||
/// <param name="checkBox">The UI control for the option.</param>
|
||||
/// <param name="invert">
|
||||
/// If true, the checkbox is inverted relative to the CVar: if the CVar is true, the checkbox will be unchecked.
|
||||
/// </param>
|
||||
/// <returns>The option instance backing the added option.</returns>
|
||||
/// <seealso cref="OptionCheckboxCVar"/>
|
||||
public OptionCheckboxCVar AddOptionCheckBox(CVarDef<bool> cVar, CheckBox checkBox, bool invert = false)
|
||||
{
|
||||
return AddOption(new OptionCheckboxCVar(this, _cfg, cVar, checkBox, invert));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a slider option, displayed in percent, backed by a simple float CVar.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar represented by the slider.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
/// <param name="min">The minimum value the slider should allow. The default value represents "0%"</param>
|
||||
/// <param name="max">The maximum value the slider should allow. The default value represents "100%"</param>
|
||||
/// <param name="scale">
|
||||
/// Scale with which to multiply slider values when mapped to the backing CVar.
|
||||
/// For example, if a scale of 2 is set, a slider at 75% writes a value of 1.5 to the CVar.
|
||||
/// </param>
|
||||
/// <returns>The option instance backing the added option.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Note that percentage values are represented as ratios in code, i.e. a value of 100% is "1".
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public OptionSliderFloatCVar AddOptionPercentSlider(
|
||||
CVarDef<float> cVar,
|
||||
OptionSlider slider,
|
||||
float min = 0,
|
||||
float max = 1,
|
||||
float scale = 1)
|
||||
{
|
||||
return AddOption(new OptionSliderFloatCVar(this, _cfg, cVar, slider, min, max, scale, FormatPercent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a slider option, backed by a simple integer CVar.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar represented by the slider.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
/// <param name="min">The minimum value the slider should allow.</param>
|
||||
/// <param name="max">The maximum value the slider should allow.</param>
|
||||
/// <param name="format">
|
||||
/// An optional delegate used to format the textual value display of the slider.
|
||||
/// If not provided, the default behavior is to directly format the integer value as text.
|
||||
/// </param>
|
||||
/// <returns>The option instance backing the added option.</returns>
|
||||
public OptionSliderIntCVar AddOptionSlider(
|
||||
CVarDef<int> cVar,
|
||||
OptionSlider slider,
|
||||
int min,
|
||||
int max,
|
||||
Func<OptionSliderIntCVar, int, string>? format = null)
|
||||
{
|
||||
return AddOption(new OptionSliderIntCVar(this, _cfg, cVar, slider, min, max, format ?? FormatInt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a drop-down option, backed by a CVar.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar represented by the drop-down.</param>
|
||||
/// <param name="dropDown">The UI control for the option.</param>
|
||||
/// <param name="options">
|
||||
/// The set of options that will be shown in the drop-down. Items are ordered as provided.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the CVar being controlled.</typeparam>
|
||||
/// <returns>The option instance backing the added option.</returns>
|
||||
public OptionDropDownCVar<T> AddOptionDropDown<T>(
|
||||
CVarDef<T> cVar,
|
||||
OptionDropDown dropDown,
|
||||
IReadOnlyCollection<OptionDropDownCVar<T>.ValueOption> options)
|
||||
where T : notnull
|
||||
{
|
||||
return AddOption(new OptionDropDownCVar<T>(this, _cfg, cVar, dropDown, options));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the control row. This should be called after all options have been added.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
foreach (var option in _options)
|
||||
{
|
||||
option.LoadValue();
|
||||
}
|
||||
|
||||
UpdateButtonState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-loads options in the settings from backing values.
|
||||
/// Should be called when the options window is opened to make sure all values are up-to-date.
|
||||
/// </summary>
|
||||
public void ReloadValues()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="BaseOption"/> to signal that an option's value changed through user interaction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="BaseOption"/> implementations should not call this function directly,
|
||||
/// instead they should call <see cref="BaseOption.ValueChanged"/>.
|
||||
/// </remarks>
|
||||
public void ValueChanged()
|
||||
{
|
||||
UpdateButtonState();
|
||||
}
|
||||
|
||||
private void UpdateButtonState()
|
||||
{
|
||||
var anyModified = _options.Any(option => option.IsModified());
|
||||
var anyModifiedFromDefault = _options.Any(option => option.IsModifiedFromDefault());
|
||||
|
||||
DefaultButton.Disabled = !anyModifiedFromDefault;
|
||||
ApplyButton.Disabled = !anyModified;
|
||||
ResetButton.Disabled = !anyModified;
|
||||
}
|
||||
|
||||
private void ApplyButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
foreach (var option in _options)
|
||||
{
|
||||
if (option.IsModified())
|
||||
option.SaveValue();
|
||||
}
|
||||
|
||||
_cfg.SaveToFile();
|
||||
UpdateButtonState();
|
||||
}
|
||||
|
||||
private void ResetButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
foreach (var option in _options)
|
||||
{
|
||||
option.LoadValue();
|
||||
}
|
||||
|
||||
UpdateButtonState();
|
||||
}
|
||||
|
||||
private void DefaultButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
foreach (var option in _options)
|
||||
{
|
||||
option.ResetToDefault();
|
||||
}
|
||||
|
||||
UpdateButtonState();
|
||||
}
|
||||
|
||||
private string FormatPercent(OptionSliderFloatCVar slider, float value)
|
||||
{
|
||||
return _loc.GetString("ui-options-value-percent", ("value", value));
|
||||
}
|
||||
|
||||
private static string FormatInt(OptionSliderIntCVar slider, int value)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class of a single "option" for <see cref="OptionsTabControlRow"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Implementations of this class handle loading values from backing storage or defaults,
|
||||
/// handling UI controls, and saving. The main <see cref="OptionsTabControlRow"/> does not know what a CVar is.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <see cref="BaseOptionCVar{TValue}"/> is a derived class that makes it easier to work with options
|
||||
/// backed by a single CVar.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public abstract class BaseOption(OptionsTabControlRow controller)
|
||||
{
|
||||
/// <summary>
|
||||
/// Should be called by derived implementations to indicate that their value changed, due to user interaction.
|
||||
/// </summary>
|
||||
protected virtual void ValueChanged()
|
||||
{
|
||||
controller.ValueChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the value represented by this option from its backing store, into the UI state.
|
||||
/// </summary>
|
||||
public abstract void LoadValue();
|
||||
|
||||
/// <summary>
|
||||
/// Saves the value in the UI state to the backing store.
|
||||
/// </summary>
|
||||
public abstract void SaveValue();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the UI state to that of the factory-default value. This should not write to the backing store.
|
||||
/// </summary>
|
||||
public abstract void ResetToDefault();
|
||||
|
||||
/// <summary>
|
||||
/// Called to check if this option's UI value is different from the backing store value.
|
||||
/// </summary>
|
||||
/// <returns>If true, the UI value is different and was modified by the user.</returns>
|
||||
public abstract bool IsModified();
|
||||
|
||||
/// <summary>
|
||||
/// Called to check if this option's UI value is different from the backing store's default value.
|
||||
/// </summary>
|
||||
/// <returns>If true, the UI value is different.</returns>
|
||||
public abstract bool IsModifiedFromDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Derived class of <see cref="BaseOption"/> intended for making mappings to simple CVars easier.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of the CVar.</typeparam>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public abstract class BaseOptionCVar<TValue> : BaseOption
|
||||
where TValue : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised immediately when the UI value of this option is changed by the user, even before saving.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This can be used to update parts of the options UI based on the state of a checkbox.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public event Action<TValue>? ImmediateValueChanged;
|
||||
|
||||
private readonly IConfigurationManager _cfg;
|
||||
private readonly CVarDef<TValue> _cVar;
|
||||
|
||||
/// <summary>
|
||||
/// Sets and gets the actual CVar value to/from the frontend UI state or control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// In the simplest case, this function should set a UI control's state to represent the CVar,
|
||||
/// and inversely conver the UI control's state to the CVar value. For simple controls like a checkbox or slider,
|
||||
/// this just means passing through their value property.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected abstract TValue Value { get; set; }
|
||||
|
||||
protected BaseOptionCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<TValue> cVar)
|
||||
: base(controller)
|
||||
{
|
||||
_cfg = cfg;
|
||||
_cVar = cVar;
|
||||
}
|
||||
|
||||
public override void LoadValue()
|
||||
{
|
||||
Value = _cfg.GetCVar(_cVar);
|
||||
}
|
||||
|
||||
public override void SaveValue()
|
||||
{
|
||||
_cfg.SetCVar(_cVar, Value);
|
||||
}
|
||||
|
||||
public override void ResetToDefault()
|
||||
{
|
||||
Value = _cVar.DefaultValue;
|
||||
}
|
||||
|
||||
public override bool IsModified()
|
||||
{
|
||||
return !IsValueEqual(Value, _cfg.GetCVar(_cVar));
|
||||
}
|
||||
|
||||
public override bool IsModifiedFromDefault()
|
||||
{
|
||||
return !IsValueEqual(Value, _cVar.DefaultValue);
|
||||
}
|
||||
|
||||
protected virtual bool IsValueEqual(TValue a, TValue b)
|
||||
{
|
||||
// Use different logic for floats so there's some error margin.
|
||||
// This check is handled cleanly at compile-time by the JIT.
|
||||
if (typeof(TValue) == typeof(float))
|
||||
return MathHelper.CloseToPercent((float) (object) a, (float) (object) b);
|
||||
|
||||
return EqualityComparer<TValue>.Default.Equals(a, b);
|
||||
}
|
||||
|
||||
protected override void ValueChanged()
|
||||
{
|
||||
base.ValueChanged();
|
||||
|
||||
ImmediateValueChanged?.Invoke(Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a CVar option that simply corresponds with a <see cref="CheckBox"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Generally, you should just call <c>AddOption</c> methods on <see cref="OptionsTabControlRow"/>
|
||||
/// instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public sealed class OptionCheckboxCVar : BaseOptionCVar<bool>
|
||||
{
|
||||
private readonly CheckBox _checkBox;
|
||||
private readonly bool _invert;
|
||||
|
||||
protected override bool Value
|
||||
{
|
||||
get => _checkBox.Pressed ^ _invert;
|
||||
set => _checkBox.Pressed = value ^ _invert;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of this type.
|
||||
/// </summary>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <param name="cfg">The configuration manager to get and set values from.</param>
|
||||
/// <param name="cVar">The CVar that is being controlled by this option.</param>
|
||||
/// <param name="checkBox">The UI control for the option.</param>
|
||||
/// <param name="invert">
|
||||
/// If true, the checkbox is inverted relative to the CVar: if the CVar is true, the checkbox will be unchecked.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
|
||||
/// such as <see cref="OptionsTabControlRow.AddOptionCheckBox"/> instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public OptionCheckboxCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<bool> cVar,
|
||||
CheckBox checkBox,
|
||||
bool invert)
|
||||
: base(controller, cfg, cVar)
|
||||
{
|
||||
_checkBox = checkBox;
|
||||
_invert = invert;
|
||||
checkBox.OnToggled += _ =>
|
||||
{
|
||||
ValueChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a CVar option that simply corresponds with a floating-point <see cref="OptionSlider"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public sealed class OptionSliderFloatCVar : BaseOptionCVar<float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Scale with which to multiply slider values when mapped to the backing CVar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, if a scale of 2 is set, a slider at 75% writes a value of 1.5 to the CVar.
|
||||
/// </remarks>
|
||||
public float Scale { get; }
|
||||
|
||||
private readonly OptionSlider _slider;
|
||||
private readonly Func<OptionSliderFloatCVar, float, string> _format;
|
||||
|
||||
protected override float Value
|
||||
{
|
||||
get => _slider.Slider.Value * Scale;
|
||||
set
|
||||
{
|
||||
_slider.Slider.Value = value / Scale;
|
||||
UpdateLabelValue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of this type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
|
||||
/// such as <see cref="OptionsTabControlRow.AddOptionPercentSlider"/> instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <param name="cfg">The configuration manager to get and set values from.</param>
|
||||
/// <param name="cVar">The CVar that is being controlled by this option.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
/// <param name="minValue">The minimum value the slider should allow.</param>
|
||||
/// <param name="maxValue">The maximum value the slider should allow.</param>
|
||||
/// <param name="scale">
|
||||
/// Scale with which to multiply slider values when mapped to the backing CVar. See <see cref="Scale"/>.
|
||||
/// </param>
|
||||
/// <param name="format">Function that will be called to format the value display next to the slider.</param>
|
||||
public OptionSliderFloatCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<float> cVar,
|
||||
OptionSlider slider,
|
||||
float minValue,
|
||||
float maxValue,
|
||||
float scale,
|
||||
Func<OptionSliderFloatCVar, float, string> format) : base(controller, cfg, cVar)
|
||||
{
|
||||
Scale = scale;
|
||||
_slider = slider;
|
||||
_format = format;
|
||||
|
||||
slider.Slider.MinValue = minValue;
|
||||
slider.Slider.MaxValue = maxValue;
|
||||
|
||||
slider.Slider.OnValueChanged += _ =>
|
||||
{
|
||||
ValueChanged();
|
||||
UpdateLabelValue();
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateLabelValue()
|
||||
{
|
||||
_slider.ValueLabel.Text = _format(this, _slider.Slider.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a CVar option that simply corresponds with an integer <see cref="OptionSlider"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public sealed class OptionSliderIntCVar : BaseOptionCVar<int>
|
||||
{
|
||||
private readonly OptionSlider _slider;
|
||||
private readonly Func<OptionSliderIntCVar, int, string> _format;
|
||||
|
||||
protected override int Value
|
||||
{
|
||||
get => (int) _slider.Slider.Value;
|
||||
set
|
||||
{
|
||||
_slider.Slider.Value = value;
|
||||
UpdateLabelValue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of this type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
|
||||
/// such as <see cref="OptionsTabControlRow.AddOptionPercentSlider"/> instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <param name="cfg">The configuration manager to get and set values from.</param>
|
||||
/// <param name="cVar">The CVar that is being controlled by this option.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
/// <param name="minValue">The minimum value the slider should allow.</param>
|
||||
/// <param name="maxValue">The maximum value the slider should allow.</param>
|
||||
/// <param name="format">Function that will be called to format the value display next to the slider.</param>
|
||||
public OptionSliderIntCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<int> cVar,
|
||||
OptionSlider slider,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
Func<OptionSliderIntCVar, int, string> format) : base(controller, cfg, cVar)
|
||||
{
|
||||
_slider = slider;
|
||||
_format = format;
|
||||
|
||||
slider.Slider.MinValue = minValue;
|
||||
slider.Slider.MaxValue = maxValue;
|
||||
slider.Slider.Rounded = true;
|
||||
|
||||
slider.Slider.OnValueChanged += _ =>
|
||||
{
|
||||
ValueChanged();
|
||||
UpdateLabelValue();
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateLabelValue()
|
||||
{
|
||||
_slider.ValueLabel.Text = _format(this, (int) _slider.Slider.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a CVar option via a drop-down.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow"/>
|
||||
public sealed class OptionDropDownCVar<T> : BaseOptionCVar<T> where T : notnull
|
||||
{
|
||||
private readonly OptionDropDown _dropDown;
|
||||
private readonly ItemEntry[] _entries;
|
||||
|
||||
protected override T Value
|
||||
{
|
||||
get => (T) _dropDown.Button.SelectedMetadata!;
|
||||
set => _dropDown.Button.SelectId(FindValueId(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of this type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
|
||||
/// such as <see cref="OptionsTabControlRow.AddOptionDropDown{T}"/> instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <param name="cfg">The configuration manager to get and set values from.</param>
|
||||
/// <param name="cVar">The CVar that is being controlled by this option.</param>
|
||||
/// <param name="dropDown">The UI control for the option.</param>
|
||||
/// <param name="options">The list of options shown to the user.</param>
|
||||
public OptionDropDownCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<T> cVar,
|
||||
OptionDropDown dropDown,
|
||||
IReadOnlyCollection<ValueOption> options) : base(controller, cfg, cVar)
|
||||
{
|
||||
if (options.Count == 0)
|
||||
throw new ArgumentException("Need at least one option!");
|
||||
|
||||
_dropDown = dropDown;
|
||||
_entries = new ItemEntry[options.Count];
|
||||
|
||||
var button = dropDown.Button;
|
||||
var i = 0;
|
||||
foreach (var option in options)
|
||||
{
|
||||
_entries[i] = new ItemEntry
|
||||
{
|
||||
Key = option.Key,
|
||||
};
|
||||
|
||||
button.AddItem(option.Label, i);
|
||||
button.SetItemMetadata(button.GetIdx(i), option.Key);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
dropDown.Button.OnItemSelected += args =>
|
||||
{
|
||||
dropDown.Button.SelectId(args.Id);
|
||||
ValueChanged();
|
||||
};
|
||||
}
|
||||
|
||||
private int FindValueId(T value)
|
||||
{
|
||||
for (var i = 0; i < _entries.Length; i++)
|
||||
{
|
||||
if (IsValueEqual(_entries[i].Key, value))
|
||||
return i;
|
||||
}
|
||||
|
||||
// This will just default select the first entry or whatever.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single option for a drop-down.
|
||||
/// </summary>
|
||||
/// <param name="key">The value that this option has. This is what will be written to the CVar if selected.</param>
|
||||
/// <param name="label">The visual text shown to the user for the option.</param>
|
||||
/// <seealso cref="OptionDropDownCVar{T}"/>
|
||||
/// <seealso cref="OptionsTabControlRow.AddOptionDropDown{T}"/>
|
||||
public sealed class ValueOption(T key, string label)
|
||||
{
|
||||
/// <summary>
|
||||
/// The value that this option has. This is what will be written to the CVar if selected.
|
||||
/// </summary>
|
||||
public readonly T Key = key;
|
||||
|
||||
/// <summary>
|
||||
/// The visual text shown to the user for the option.
|
||||
/// </summary>
|
||||
public readonly string Label = label;
|
||||
}
|
||||
|
||||
private struct ItemEntry
|
||||
{
|
||||
public T Key;
|
||||
}
|
||||
}
|
||||
16
Content.Client/Options/UI/Tabs/AccessibilityTab.xaml
Normal file
16
Content.Client/Options/UI/Tabs/AccessibilityTab.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="clr-namespace:Content.Client.Options.UI">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
|
||||
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
|
||||
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
|
||||
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
|
||||
<ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" />
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
24
Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs
Normal file
24
Content.Client/Options/UI/Tabs/AccessibilityTab.xaml.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Options.UI.Tabs;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AccessibilityTab : Control
|
||||
{
|
||||
public AccessibilityTab()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox);
|
||||
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
|
||||
Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider);
|
||||
|
||||
Control.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,128 +1,26 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Content.Client.Stylesheets"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
xmlns:ui="clr-namespace:Content.Client.Options.UI">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
|
||||
<Label Text="{Loc 'ui-options-volume-label'}"
|
||||
FontColorOverride="{x:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<BoxContainer Orientation="Vertical" Margin="0 3 0 0">
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-master-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="MasterVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="MasterVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<Control MinSize="0 8" />
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-midi-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="MidiVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="MidiVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-ambient-music-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="AmbientMusicVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="AmbientMusicVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-ambience-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="AmbienceVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="AmbienceVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-lobby-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="LobbyVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="LobbyVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-interface-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="InterfaceVolumeSlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="InterfaceVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-ambience-max-sounds'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="AmbienceSoundsSlider"
|
||||
MinValue="0"
|
||||
MaxValue="1"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="AmbienceSoundsLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<Control MinSize="0 8" />
|
||||
<ui:OptionSlider Name="SliderVolumeMaster" Title="{Loc 'ui-options-master-volume'}"
|
||||
Margin="0 0 0 8" />
|
||||
<ui:OptionSlider Name="SliderVolumeMidi" Title="{Loc 'ui-options-midi-volume'}" />
|
||||
<ui:OptionSlider Name="SliderVolumeAmbientMusic" Title="{Loc 'ui-options-ambient-music-volume'}" />
|
||||
<ui:OptionSlider Name="SliderVolumeAmbience" Title="{Loc 'ui-options-ambience-volume'}" />
|
||||
<ui:OptionSlider Name="SliderVolumeLobby" Title="{Loc 'ui-options-lobby-volume'}" />
|
||||
<ui:OptionSlider Name="SliderVolumeInterface" Title="{Loc 'ui-options-interface-volume'}" />
|
||||
<ui:OptionSlider Name="SliderMaxAmbienceSounds" Title="{Loc 'ui-options-ambience-max-sounds'}"
|
||||
Margin="0 0 0 8" />
|
||||
<CheckBox Name="LobbyMusicCheckBox" Text="{Loc 'ui-options-lobby-music'}" />
|
||||
<CheckBox Name="RestartSoundsCheckBox" Text="{Loc 'ui-options-restart-sounds'}" />
|
||||
<CheckBox Name="EventMusicCheckBox" Text="{Loc 'ui-options-event-music'}" />
|
||||
<CheckBox Name="AdminSoundsCheckBox" Text="{Loc 'ui-options-admin-sounds'}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
Align="End"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<Button Name="ResetButton"
|
||||
Text="{Loc 'ui-options-reset-all'}"
|
||||
StyleClasses="Caution"
|
||||
HorizontalExpand="True"
|
||||
HorizontalAlignment="Right" />
|
||||
<Control MinSize="2 0" />
|
||||
<Button Name="ApplyButton"
|
||||
Text="{Loc 'ui-options-apply'}"
|
||||
TextAlign="Center"
|
||||
HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
||||
@@ -3,200 +3,72 @@ using Content.Shared.CCVar;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Range = Robust.Client.UserInterface.Controls.Range;
|
||||
|
||||
namespace Content.Client.Options.UI.Tabs
|
||||
namespace Content.Client.Options.UI.Tabs;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AudioTab : Control
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AudioTab : Control
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IAudioManager _audio = default!;
|
||||
|
||||
public AudioTab()
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
private readonly IAudioManager _audio;
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
public AudioTab()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
var masterVolume = Control.AddOptionPercentSlider(
|
||||
CVars.AudioMasterVolume,
|
||||
SliderVolumeMaster,
|
||||
scale: ContentAudioSystem.MasterVolumeMultiplier);
|
||||
masterVolume.ImmediateValueChanged += OnMasterVolumeSliderChanged;
|
||||
|
||||
_audio = IoCManager.Resolve<IAudioManager>();
|
||||
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
|
||||
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||
Control.AddOptionPercentSlider(
|
||||
CVars.MidiVolume,
|
||||
SliderVolumeMidi,
|
||||
scale: ContentAudioSystem.MidiVolumeMultiplier);
|
||||
|
||||
ApplyButton.OnPressed += OnApplyButtonPressed;
|
||||
ResetButton.OnPressed += OnResetButtonPressed;
|
||||
MasterVolumeSlider.OnValueChanged += OnMasterVolumeSliderChanged;
|
||||
MidiVolumeSlider.OnValueChanged += OnMidiVolumeSliderChanged;
|
||||
AmbientMusicVolumeSlider.OnValueChanged += OnAmbientMusicVolumeSliderChanged;
|
||||
AmbienceVolumeSlider.OnValueChanged += OnAmbienceVolumeSliderChanged;
|
||||
AmbienceSoundsSlider.OnValueChanged += OnAmbienceSoundsSliderChanged;
|
||||
LobbyVolumeSlider.OnValueChanged += OnLobbyVolumeSliderChanged;
|
||||
InterfaceVolumeSlider.OnValueChanged += OnInterfaceVolumeSliderChanged;
|
||||
LobbyMusicCheckBox.OnToggled += OnLobbyMusicCheckToggled;
|
||||
RestartSoundsCheckBox.OnToggled += OnRestartSoundsCheckToggled;
|
||||
EventMusicCheckBox.OnToggled += OnEventMusicCheckToggled;
|
||||
AdminSoundsCheckBox.OnToggled += OnAdminSoundsCheckToggled;
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.AmbientMusicVolume,
|
||||
SliderVolumeAmbientMusic,
|
||||
scale: ContentAudioSystem.AmbientMusicMultiplier);
|
||||
|
||||
AmbienceSoundsSlider.MinValue = _cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured);
|
||||
AmbienceSoundsSlider.MaxValue = _cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured);
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.AmbienceVolume,
|
||||
SliderVolumeAmbience,
|
||||
scale: ContentAudioSystem.AmbienceMultiplier);
|
||||
|
||||
Reset();
|
||||
}
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.LobbyMusicVolume,
|
||||
SliderVolumeLobby,
|
||||
scale: ContentAudioSystem.LobbyMultiplier);
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
ApplyButton.OnPressed -= OnApplyButtonPressed;
|
||||
ResetButton.OnPressed -= OnResetButtonPressed;
|
||||
MasterVolumeSlider.OnValueChanged -= OnMasterVolumeSliderChanged;
|
||||
MidiVolumeSlider.OnValueChanged -= OnMidiVolumeSliderChanged;
|
||||
AmbientMusicVolumeSlider.OnValueChanged -= OnAmbientMusicVolumeSliderChanged;
|
||||
AmbienceVolumeSlider.OnValueChanged -= OnAmbienceVolumeSliderChanged;
|
||||
LobbyVolumeSlider.OnValueChanged -= OnLobbyVolumeSliderChanged;
|
||||
InterfaceVolumeSlider.OnValueChanged -= OnInterfaceVolumeSliderChanged;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.InterfaceVolume,
|
||||
SliderVolumeInterface,
|
||||
scale: ContentAudioSystem.InterfaceMultiplier);
|
||||
|
||||
private void OnLobbyVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
Control.AddOptionSlider(
|
||||
CCVars.MaxAmbientSources,
|
||||
SliderMaxAmbienceSounds,
|
||||
_cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured),
|
||||
_cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured));
|
||||
|
||||
private void OnInterfaceVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
Control.AddOptionCheckBox(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.EventMusicEnabled, EventMusicCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox);
|
||||
|
||||
private void OnAmbientMusicVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
Control.Initialize();
|
||||
}
|
||||
|
||||
private void OnAmbienceVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnAmbienceSoundsSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnMasterVolumeSliderChanged(Range range)
|
||||
{
|
||||
_audio.SetMasterGain(MasterVolumeSlider.Value / 100f * ContentAudioSystem.MasterVolumeMultiplier);
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnMidiVolumeSliderChanged(Range range)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnLobbyMusicCheckToggled(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
private void OnRestartSoundsCheckToggled(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
private void OnEventMusicCheckToggled(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnAdminSoundsCheckToggled(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
_cfg.SetCVar(CVars.AudioMasterVolume, MasterVolumeSlider.Value / 100f * ContentAudioSystem.MasterVolumeMultiplier);
|
||||
// Want the CVar updated values to have the multiplier applied
|
||||
// For the UI we just display 0-100 still elsewhere
|
||||
_cfg.SetCVar(CVars.MidiVolume, MidiVolumeSlider.Value / 100f * ContentAudioSystem.MidiVolumeMultiplier);
|
||||
_cfg.SetCVar(CCVars.AmbienceVolume, AmbienceVolumeSlider.Value / 100f * ContentAudioSystem.AmbienceMultiplier);
|
||||
_cfg.SetCVar(CCVars.AmbientMusicVolume, AmbientMusicVolumeSlider.Value / 100f * ContentAudioSystem.AmbientMusicMultiplier);
|
||||
_cfg.SetCVar(CCVars.LobbyMusicVolume, LobbyVolumeSlider.Value / 100f * ContentAudioSystem.LobbyMultiplier);
|
||||
_cfg.SetCVar(CCVars.InterfaceVolume, InterfaceVolumeSlider.Value / 100f * ContentAudioSystem.InterfaceMultiplier);
|
||||
|
||||
_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);
|
||||
|
||||
_cfg.SetCVar(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.EventMusicEnabled, EventMusicCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox.Pressed);
|
||||
_cfg.SaveToFile();
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void OnResetButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
MasterVolumeSlider.Value = _cfg.GetCVar(CVars.AudioMasterVolume) * 100f / ContentAudioSystem.MasterVolumeMultiplier;
|
||||
MidiVolumeSlider.Value = _cfg.GetCVar(CVars.MidiVolume) * 100f / ContentAudioSystem.MidiVolumeMultiplier;
|
||||
AmbienceVolumeSlider.Value = _cfg.GetCVar(CCVars.AmbienceVolume) * 100f / ContentAudioSystem.AmbienceMultiplier;
|
||||
AmbientMusicVolumeSlider.Value = _cfg.GetCVar(CCVars.AmbientMusicVolume) * 100f / ContentAudioSystem.AmbientMusicMultiplier;
|
||||
LobbyVolumeSlider.Value = _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier;
|
||||
InterfaceVolumeSlider.Value = _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier;
|
||||
|
||||
AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);
|
||||
|
||||
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
|
||||
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void UpdateChanges()
|
||||
{
|
||||
// y'all need jesus.
|
||||
var isMasterVolumeSame =
|
||||
Math.Abs(MasterVolumeSlider.Value - _cfg.GetCVar(CVars.AudioMasterVolume) * 100f / ContentAudioSystem.MasterVolumeMultiplier) < 0.01f;
|
||||
var isMidiVolumeSame =
|
||||
Math.Abs(MidiVolumeSlider.Value - _cfg.GetCVar(CVars.MidiVolume) * 100f / ContentAudioSystem.MidiVolumeMultiplier) < 0.01f;
|
||||
var isAmbientVolumeSame =
|
||||
Math.Abs(AmbienceVolumeSlider.Value - _cfg.GetCVar(CCVars.AmbienceVolume) * 100f / ContentAudioSystem.AmbienceMultiplier) < 0.01f;
|
||||
var isAmbientMusicVolumeSame =
|
||||
Math.Abs(AmbientMusicVolumeSlider.Value - _cfg.GetCVar(CCVars.AmbientMusicVolume) * 100f / ContentAudioSystem.AmbientMusicMultiplier) < 0.01f;
|
||||
var isLobbyVolumeSame =
|
||||
Math.Abs(LobbyVolumeSlider.Value - _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier) < 0.01f;
|
||||
var isInterfaceVolumeSame =
|
||||
Math.Abs(InterfaceVolumeSlider.Value - _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier) < 0.01f;
|
||||
|
||||
var isAmbientSoundsSame = (int)AmbienceSoundsSlider.Value == _cfg.GetCVar(CCVars.MaxAmbientSources);
|
||||
var isLobbySame = LobbyMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.LobbyMusicEnabled);
|
||||
var isRestartSoundsSame = RestartSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||
var isEventSame = EventMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||
var isAdminSoundsSame = AdminSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame && isAmbientMusicVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
|
||||
&& isAdminSoundsSame && isLobbyVolumeSame && isInterfaceVolumeSame;
|
||||
ApplyButton.Disabled = isEverythingSame;
|
||||
ResetButton.Disabled = isEverythingSame;
|
||||
MasterVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
|
||||
MidiVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", MidiVolumeSlider.Value / 100));
|
||||
AmbientMusicVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", AmbientMusicVolumeSlider.Value / 100));
|
||||
AmbienceVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", AmbienceVolumeSlider.Value / 100));
|
||||
LobbyVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", LobbyVolumeSlider.Value / 100));
|
||||
InterfaceVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", InterfaceVolumeSlider.Value / 100));
|
||||
AmbienceSoundsLabel.Text = ((int)AmbienceSoundsSlider.Value).ToString();
|
||||
}
|
||||
private void OnMasterVolumeSliderChanged(float value)
|
||||
{
|
||||
// TODO: I was thinking of giving OptionsTabControlRow a flag to "set CVar immediately", but I'm deferring that
|
||||
// until there's a proper system for enforcing people don't close the window with pending changes.
|
||||
_audio.SetMasterGain(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,38 @@
|
||||
<tabs:GraphicsTab xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs">
|
||||
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
|
||||
xmlns:ui="clr-namespace:Content.Client.Options.UI">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
|
||||
<CheckBox Name="VSyncCheckBox" Text="{Loc 'ui-options-vsync'}" />
|
||||
<CheckBox Name="FullscreenCheckBox" Text="{Loc 'ui-options-fullscreen'}" />
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-lighting-label'}" />
|
||||
<Control MinSize="4 0" />
|
||||
<OptionButton Name="LightingPresetOption" MinSize="100 0" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-scale-label'}" />
|
||||
<Control MinSize="4 0" />
|
||||
<OptionButton Name="UIScaleOption" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Margin="8 8 8 8">
|
||||
<!-- Display -->
|
||||
<Label Text="{Loc 'ui-options-display-label'}" StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="VSyncCheckBox" Text="{Loc 'ui-options-vsync'}" />
|
||||
<CheckBox Name="FullscreenCheckBox" Text="{Loc 'ui-options-fullscreen'}" />
|
||||
|
||||
<!-- Quality -->
|
||||
<Label Text="{Loc 'ui-options-quality-label'}" StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionDropDown Name="DropDownLightingQuality" Title="{Loc 'ui-options-lighting-label'}" />
|
||||
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
|
||||
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
|
||||
|
||||
<!-- Interface -->
|
||||
<Label Text="{Loc 'ui-options-interface-label'}" StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionDropDown Name="DropDownUIScale" Title="{Loc 'ui-options-scale-label'}" />
|
||||
<CheckBox Name="ViewportStretchCheckBox" Text="{Loc 'ui-options-vp-stretch'}" />
|
||||
<BoxContainer Name="ViewportScaleBox" Orientation="Horizontal">
|
||||
<Label Name="ViewportScaleText" Margin="8 0" />
|
||||
<Slider Name="ViewportScaleSlider"
|
||||
MinValue="1"
|
||||
MaxValue="5"
|
||||
Rounded="True"
|
||||
MinWidth="200" />
|
||||
</BoxContainer>
|
||||
<ui:OptionSlider Name="ViewportScaleSlider" Title="{Loc ui-options-vp-scale}" />
|
||||
<ui:OptionSlider Name="ViewportWidthSlider" Title="{Loc ui-options-vp-width}" />
|
||||
<CheckBox Name="IntegerScalingCheckBox"
|
||||
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
||||
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
||||
<CheckBox Name="ViewportVerticalFitCheckBox"
|
||||
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
||||
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
||||
|
||||
<!-- Misc -->
|
||||
<Label Text="{Loc 'ui-options-misc-label'}" StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="ViewportWidthSliderDisplay" />
|
||||
<Control MinSize="4 0" />
|
||||
<Slider Name="ViewportWidthSlider"
|
||||
Rounded="True"
|
||||
MinWidth="200" />
|
||||
</BoxContainer>
|
||||
<CheckBox Name="IntegerScalingCheckBox"
|
||||
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
||||
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
||||
<CheckBox Name="ViewportVerticalFitCheckBox"
|
||||
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
||||
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
||||
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
|
||||
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
|
||||
<CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" />
|
||||
</BoxContainer>
|
||||
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
||||
<Button Name="ApplyButton"
|
||||
Text="{Loc 'ui-options-apply'}"
|
||||
TextAlign="Center"
|
||||
HorizontalAlignment="Right" />
|
||||
</controls:StripeBack>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
</BoxContainer>
|
||||
</tabs:GraphicsTab>
|
||||
|
||||
@@ -7,220 +7,141 @@ using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.Options.UI.Tabs
|
||||
namespace Content.Client.Options.UI.Tabs;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GraphicsTab : Control
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GraphicsTab : Control
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
public GraphicsTab()
|
||||
{
|
||||
private static readonly float[] UIScaleOptions =
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Control.AddOptionCheckBox(CVars.DisplayVSync, VSyncCheckBox);
|
||||
Control.AddOption(new OptionFullscreen(Control, _cfg, FullscreenCheckBox));
|
||||
Control.AddOption(new OptionLightingQuality(Control, _cfg, DropDownLightingQuality));
|
||||
|
||||
Control.AddOptionDropDown(
|
||||
CVars.DisplayUIScale,
|
||||
DropDownUIScale,
|
||||
[
|
||||
new OptionDropDownCVar<float>.ValueOption(
|
||||
0f,
|
||||
Loc.GetString("ui-options-scale-auto", ("scale", UserInterfaceManager.DefaultUIScale))),
|
||||
new OptionDropDownCVar<float>.ValueOption(0.75f, Loc.GetString("ui-options-scale-75")),
|
||||
new OptionDropDownCVar<float>.ValueOption(1.00f, Loc.GetString("ui-options-scale-100")),
|
||||
new OptionDropDownCVar<float>.ValueOption(1.25f, Loc.GetString("ui-options-scale-125")),
|
||||
new OptionDropDownCVar<float>.ValueOption(1.50f, Loc.GetString("ui-options-scale-150")),
|
||||
new OptionDropDownCVar<float>.ValueOption(1.75f, Loc.GetString("ui-options-scale-175")),
|
||||
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
|
||||
]);
|
||||
|
||||
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
|
||||
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
|
||||
Control.AddOptionSlider(
|
||||
CCVars.ViewportFixedScaleFactor,
|
||||
ViewportScaleSlider,
|
||||
1,
|
||||
5,
|
||||
(_, value) => Loc.GetString("ui-options-vp-scale-value", ("scale", value)));
|
||||
|
||||
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||
|
||||
Control.AddOptionSlider(
|
||||
CCVars.ViewportWidth,
|
||||
ViewportWidthSlider,
|
||||
(int)ViewportWidthSlider.Slider.MinValue,
|
||||
(int)ViewportWidthSlider.Slider.MaxValue);
|
||||
|
||||
Control.AddOption(new OptionIntegerScaling(Control, _cfg, IntegerScalingCheckBox));
|
||||
Control.AddOptionCheckBox(CCVars.ViewportScaleRender, ViewportLowResCheckBox, invert: true);
|
||||
Control.AddOptionCheckBox(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.HudFpsCounterVisible, FpsCounterCheckBox);
|
||||
|
||||
Control.Initialize();
|
||||
|
||||
_cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange());
|
||||
_cfg.OnValueChanged(CCVars.ViewportMaximumWidth, _ => UpdateViewportWidthRange());
|
||||
|
||||
UpdateViewportWidthRange();
|
||||
UpdateViewportSettingsVisibility();
|
||||
}
|
||||
|
||||
private void UpdateViewportSettingsVisibility()
|
||||
{
|
||||
ViewportScaleSlider.Visible = !ViewportStretchCheckBox.Pressed;
|
||||
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
|
||||
}
|
||||
|
||||
private void UpdateViewportWidthRange()
|
||||
{
|
||||
var min = _cfg.GetCVar(CCVars.ViewportMinimumWidth);
|
||||
var max = _cfg.GetCVar(CCVars.ViewportMaximumWidth);
|
||||
|
||||
ViewportWidthSlider.Slider.MinValue = min;
|
||||
ViewportWidthSlider.Slider.MaxValue = max;
|
||||
}
|
||||
|
||||
private sealed class OptionLightingQuality : BaseOption
|
||||
{
|
||||
private readonly IConfigurationManager _cfg;
|
||||
private readonly OptionDropDown _dropDown;
|
||||
|
||||
private const int QualityVeryLow = 0;
|
||||
private const int QualityLow = 1;
|
||||
private const int QualityMedium = 2;
|
||||
private const int QualityHigh = 3;
|
||||
|
||||
private const int QualityDefault = QualityMedium;
|
||||
|
||||
public OptionLightingQuality(OptionsTabControlRow controller, IConfigurationManager cfg, OptionDropDown dropDown) : base(controller)
|
||||
{
|
||||
0f,
|
||||
0.75f,
|
||||
1f,
|
||||
1.25f,
|
||||
1.50f,
|
||||
1.75f,
|
||||
2f
|
||||
};
|
||||
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
public GraphicsTab()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
VSyncCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
FullscreenCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
|
||||
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-very-low"));
|
||||
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-low"));
|
||||
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-medium"));
|
||||
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-high"));
|
||||
LightingPresetOption.OnItemSelected += OnLightingQualityChanged;
|
||||
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-auto",
|
||||
("scale", UserInterfaceManager.DefaultUIScale)));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-75"));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-100"));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-125"));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-150"));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-175"));
|
||||
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-200"));
|
||||
UIScaleOption.OnItemSelected += OnUIScaleChanged;
|
||||
|
||||
ViewportStretchCheckBox.OnToggled += _ =>
|
||||
{
|
||||
UpdateViewportScale();
|
||||
UpdateApplyButton();
|
||||
};
|
||||
|
||||
ViewportScaleSlider.OnValueChanged += _ =>
|
||||
{
|
||||
UpdateApplyButton();
|
||||
UpdateViewportScale();
|
||||
};
|
||||
|
||||
ViewportWidthSlider.OnValueChanged += _ =>
|
||||
{
|
||||
UpdateViewportWidthDisplay();
|
||||
UpdateApplyButton();
|
||||
};
|
||||
|
||||
ViewportVerticalFitCheckBox.OnToggled += _ =>
|
||||
{
|
||||
UpdateViewportScale();
|
||||
UpdateApplyButton();
|
||||
};
|
||||
|
||||
IntegerScalingCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
ViewportLowResCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
ParallaxLowQualityCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
FpsCounterCheckBox.OnToggled += OnCheckBoxToggled;
|
||||
ApplyButton.OnPressed += OnApplyButtonPressed;
|
||||
VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync);
|
||||
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
|
||||
LightingPresetOption.SelectId(GetConfigLightingQuality());
|
||||
UIScaleOption.SelectId(GetConfigUIScalePreset(ConfigUIScale));
|
||||
ViewportScaleSlider.Value = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
|
||||
ViewportStretchCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportStretch);
|
||||
IntegerScalingCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0;
|
||||
ViewportVerticalFitCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportVerticalFit);
|
||||
ViewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender);
|
||||
ParallaxLowQualityCheckBox.Pressed = _cfg.GetCVar(CCVars.ParallaxLowQuality);
|
||||
FpsCounterCheckBox.Pressed = _cfg.GetCVar(CCVars.HudFpsCounterVisible);
|
||||
ViewportWidthSlider.Value = _cfg.GetCVar(CCVars.ViewportWidth);
|
||||
|
||||
_cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange());
|
||||
_cfg.OnValueChanged(CCVars.ViewportMaximumWidth, _ => UpdateViewportWidthRange());
|
||||
|
||||
UpdateViewportWidthRange();
|
||||
UpdateViewportWidthDisplay();
|
||||
UpdateViewportScale();
|
||||
UpdateApplyButton();
|
||||
_cfg = cfg;
|
||||
_dropDown = dropDown;
|
||||
var button = dropDown.Button;
|
||||
button.AddItem(Loc.GetString("ui-options-lighting-very-low"), QualityVeryLow);
|
||||
button.AddItem(Loc.GetString("ui-options-lighting-low"), QualityLow);
|
||||
button.AddItem(Loc.GetString("ui-options-lighting-medium"), QualityMedium);
|
||||
button.AddItem(Loc.GetString("ui-options-lighting-high"), QualityHigh);
|
||||
button.OnItemSelected += OnOptionSelected;
|
||||
}
|
||||
|
||||
private void OnUIScaleChanged(OptionButton.ItemSelectedEventArgs args)
|
||||
private void OnOptionSelected(OptionButton.ItemSelectedEventArgs obj)
|
||||
{
|
||||
UIScaleOption.SelectId(args.Id);
|
||||
UpdateApplyButton();
|
||||
_dropDown.Button.SelectId(obj.Id);
|
||||
ValueChanged();
|
||||
}
|
||||
|
||||
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
public override void LoadValue()
|
||||
{
|
||||
_cfg.SetCVar(CVars.DisplayVSync, VSyncCheckBox.Pressed);
|
||||
SetConfigLightingQuality(LightingPresetOption.SelectedId);
|
||||
|
||||
_cfg.SetCVar(CVars.DisplayWindowMode,
|
||||
(int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
|
||||
_cfg.SetCVar(CVars.DisplayUIScale, UIScaleOptions[UIScaleOption.SelectedId]);
|
||||
_cfg.SetCVar(CCVars.ViewportStretch, ViewportStretchCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ViewportFixedScaleFactor, (int) ViewportScaleSlider.Value);
|
||||
_cfg.SetCVar(CCVars.ViewportSnapToleranceMargin,
|
||||
IntegerScalingCheckBox.Pressed ? CCVars.ViewportSnapToleranceMargin.DefaultValue : 0);
|
||||
_cfg.SetCVar(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ViewportScaleRender, !ViewportLowResCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.HudFpsCounterVisible, FpsCounterCheckBox.Pressed);
|
||||
_cfg.SetCVar(CCVars.ViewportWidth, (int) ViewportWidthSlider.Value);
|
||||
|
||||
_cfg.SaveToFile();
|
||||
UpdateApplyButton();
|
||||
_dropDown.Button.SelectId(GetConfigLightingQuality());
|
||||
}
|
||||
|
||||
private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
|
||||
public override void SaveValue()
|
||||
{
|
||||
UpdateApplyButton();
|
||||
}
|
||||
|
||||
private void OnLightingQualityChanged(OptionButton.ItemSelectedEventArgs args)
|
||||
{
|
||||
LightingPresetOption.SelectId(args.Id);
|
||||
UpdateApplyButton();
|
||||
}
|
||||
|
||||
private void UpdateApplyButton()
|
||||
{
|
||||
var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar(CVars.DisplayVSync);
|
||||
var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
|
||||
var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
|
||||
var isUIScaleSame = MathHelper.CloseToPercent(UIScaleOptions[UIScaleOption.SelectedId], ConfigUIScale);
|
||||
var isVPStretchSame = ViewportStretchCheckBox.Pressed == _cfg.GetCVar(CCVars.ViewportStretch);
|
||||
var isVPScaleSame = (int) ViewportScaleSlider.Value == _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
|
||||
var isIntegerScalingSame = IntegerScalingCheckBox.Pressed == (_cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0);
|
||||
var isVPVerticalFitSame = ViewportVerticalFitCheckBox.Pressed == _cfg.GetCVar(CCVars.ViewportVerticalFit);
|
||||
var isVPResSame = ViewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender);
|
||||
var isPLQSame = ParallaxLowQualityCheckBox.Pressed == _cfg.GetCVar(CCVars.ParallaxLowQuality);
|
||||
var isFpsCounterVisibleSame = FpsCounterCheckBox.Pressed == _cfg.GetCVar(CCVars.HudFpsCounterVisible);
|
||||
var isWidthSame = (int) ViewportWidthSlider.Value == _cfg.GetCVar(CCVars.ViewportWidth);
|
||||
|
||||
ApplyButton.Disabled = isVSyncSame &&
|
||||
isFullscreenSame &&
|
||||
isLightingQualitySame &&
|
||||
isUIScaleSame &&
|
||||
isVPStretchSame &&
|
||||
isVPScaleSame &&
|
||||
isIntegerScalingSame &&
|
||||
isVPVerticalFitSame &&
|
||||
isVPResSame &&
|
||||
isPLQSame &&
|
||||
isFpsCounterVisibleSame &&
|
||||
isWidthSame;
|
||||
}
|
||||
|
||||
private bool ConfigIsFullscreen =>
|
||||
_cfg.GetCVar(CVars.DisplayWindowMode) == (int) WindowMode.Fullscreen;
|
||||
|
||||
public void UpdateProperties()
|
||||
{
|
||||
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
|
||||
}
|
||||
|
||||
|
||||
private float ConfigUIScale => _cfg.GetCVar(CVars.DisplayUIScale);
|
||||
|
||||
private int GetConfigLightingQuality()
|
||||
{
|
||||
var val = _cfg.GetCVar(CVars.LightResolutionScale);
|
||||
var soft = _cfg.GetCVar(CVars.LightSoftShadows);
|
||||
if (val <= 0.125)
|
||||
switch (_dropDown.Button.SelectedId)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if ((val <= 0.5) && !soft)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (val <= 0.5)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConfigLightingQuality(int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
case QualityVeryLow:
|
||||
_cfg.SetCVar(CVars.LightResolutionScale, 0.125f);
|
||||
_cfg.SetCVar(CVars.LightSoftShadows, false);
|
||||
_cfg.SetCVar(CVars.LightBlur, false);
|
||||
break;
|
||||
case 1:
|
||||
case QualityLow:
|
||||
_cfg.SetCVar(CVars.LightResolutionScale, 0.5f);
|
||||
_cfg.SetCVar(CVars.LightSoftShadows, false);
|
||||
_cfg.SetCVar(CVars.LightBlur, true);
|
||||
break;
|
||||
case 2:
|
||||
default: // = QualityMedium
|
||||
_cfg.SetCVar(CVars.LightResolutionScale, 0.5f);
|
||||
_cfg.SetCVar(CVars.LightSoftShadows, true);
|
||||
_cfg.SetCVar(CVars.LightBlur, true);
|
||||
break;
|
||||
case 3:
|
||||
case QualityHigh:
|
||||
_cfg.SetCVar(CVars.LightResolutionScale, 1);
|
||||
_cfg.SetCVar(CVars.LightSoftShadows, true);
|
||||
_cfg.SetCVar(CVars.LightBlur, true);
|
||||
@@ -228,40 +149,83 @@ namespace Content.Client.Options.UI.Tabs
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetConfigUIScalePreset(float value)
|
||||
public override void ResetToDefault()
|
||||
{
|
||||
for (var i = 0; i < UIScaleOptions.Length; i++)
|
||||
_dropDown.Button.SelectId(QualityDefault);
|
||||
}
|
||||
|
||||
public override bool IsModified()
|
||||
{
|
||||
return _dropDown.Button.SelectedId != GetConfigLightingQuality();
|
||||
}
|
||||
|
||||
public override bool IsModifiedFromDefault()
|
||||
{
|
||||
return _dropDown.Button.SelectedId != QualityDefault;
|
||||
}
|
||||
|
||||
private int GetConfigLightingQuality()
|
||||
{
|
||||
var val = _cfg.GetCVar(CVars.LightResolutionScale);
|
||||
var soft = _cfg.GetCVar(CVars.LightSoftShadows);
|
||||
if (val <= 0.125)
|
||||
return QualityVeryLow;
|
||||
|
||||
if ((val <= 0.5) && !soft)
|
||||
return QualityLow;
|
||||
|
||||
if (val <= 0.5)
|
||||
return QualityMedium;
|
||||
|
||||
return QualityHigh;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class OptionFullscreen : BaseOptionCVar<int>
|
||||
{
|
||||
private readonly CheckBox _checkBox;
|
||||
|
||||
protected override int Value
|
||||
{
|
||||
get => _checkBox.Pressed ? (int) WindowMode.Fullscreen : (int) WindowMode.Windowed;
|
||||
set => _checkBox.Pressed = (value == (int) WindowMode.Fullscreen);
|
||||
}
|
||||
|
||||
public OptionFullscreen(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CheckBox checkBox)
|
||||
: base(controller, cfg, CVars.DisplayWindowMode)
|
||||
{
|
||||
_checkBox = checkBox;
|
||||
_checkBox.OnToggled += _ =>
|
||||
{
|
||||
if (MathHelper.CloseToPercent(UIScaleOptions[i], value))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
ValueChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
private sealed class OptionIntegerScaling : BaseOptionCVar<int>
|
||||
{
|
||||
private readonly CheckBox _checkBox;
|
||||
|
||||
protected override int Value
|
||||
{
|
||||
get => _checkBox.Pressed ? CCVars.ViewportSnapToleranceMargin.DefaultValue : 0;
|
||||
set => _checkBox.Pressed = (value != 0);
|
||||
}
|
||||
|
||||
private void UpdateViewportScale()
|
||||
public OptionIntegerScaling(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CheckBox checkBox)
|
||||
: base(controller, cfg, CCVars.ViewportSnapToleranceMargin)
|
||||
{
|
||||
ViewportScaleBox.Visible = !ViewportStretchCheckBox.Pressed;
|
||||
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||
ViewportWidthSlider.Visible = ViewportWidthSliderDisplay.Visible = !ViewportStretchCheckBox.Pressed || ViewportStretchCheckBox.Pressed && !ViewportVerticalFitCheckBox.Pressed;
|
||||
ViewportScaleText.Text = Loc.GetString("ui-options-vp-scale", ("scale", ViewportScaleSlider.Value));
|
||||
}
|
||||
|
||||
private void UpdateViewportWidthRange()
|
||||
{
|
||||
var min = _cfg.GetCVar(CCVars.ViewportMinimumWidth);
|
||||
var max = _cfg.GetCVar(CCVars.ViewportMaximumWidth);
|
||||
|
||||
ViewportWidthSlider.MinValue = min;
|
||||
ViewportWidthSlider.MaxValue = max;
|
||||
}
|
||||
|
||||
private void UpdateViewportWidthDisplay()
|
||||
{
|
||||
ViewportWidthSliderDisplay.Text = Loc.GetString("ui-options-vp-width", ("width", (int) ViewportWidthSlider.Value));
|
||||
_checkBox = checkBox;
|
||||
_checkBox.OnToggled += _ =>
|
||||
{
|
||||
ValueChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,34 @@
|
||||
<tabs:MiscTab xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
|
||||
xmlns:xNamespace="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Content.Client.Stylesheets">
|
||||
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="clr-namespace:Content.Client.Options.UI">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
|
||||
<Label Text="{Loc 'ui-options-general-ui-style'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-hud-theme'}" />
|
||||
<Control MinSize="4 0" />
|
||||
<OptionButton Name="HudThemeOption" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-hud-layout'}" />
|
||||
<Control MinSize="4 0" />
|
||||
<OptionButton Name="HudLayoutOption" />
|
||||
</BoxContainer>
|
||||
<Label Text="{Loc 'ui-options-general-accessibility'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
|
||||
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
|
||||
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-chat-window-opacity'}" Margin="8 0" />
|
||||
<Slider Name="ChatWindowOpacitySlider"
|
||||
MinValue="0"
|
||||
MaxValue="1"
|
||||
MinWidth="200" />
|
||||
<Label Name="ChatWindowOpacityLabel" Margin="8 0" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
|
||||
<Slider Name="ScreenShakeIntensitySlider"
|
||||
MinValue="0"
|
||||
MaxValue="100"
|
||||
Rounded="True"
|
||||
MinWidth="200" />
|
||||
<Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
|
||||
</BoxContainer>
|
||||
<ui:OptionDropDown Name="DropDownHudTheme" Title="{Loc 'ui-options-hud-theme'}" />
|
||||
<ui:OptionDropDown Name="DropDownHudLayout" Title="{Loc 'ui-options-hud-layout'}" />
|
||||
<Label Text="{Loc 'ui-options-general-discord'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
|
||||
<Label Text="{Loc 'ui-options-general-speech'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="ShowOocPatronColor" Text="{Loc 'ui-options-show-ooc-patron-color'}" />
|
||||
<CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
|
||||
<CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
|
||||
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
|
||||
<Label Text="{Loc 'ui-options-general-cursor'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
|
||||
<CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
|
||||
<Label Text="{Loc 'ui-options-general-storage'}"
|
||||
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
|
||||
<CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
|
||||
<!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
||||
<Button Name="ApplyButton"
|
||||
Text="{Loc 'ui-options-apply'}"
|
||||
TextAlign="Center"
|
||||
HorizontalAlignment="Right" />
|
||||
</controls:StripeBack>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
</BoxContainer>
|
||||
</tabs:MiscTab>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user