Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c299104f0c | ||
|
|
224bebeeb5 | ||
|
|
52c8e8ecdf | ||
|
|
ac636b2703 | ||
|
|
a892f9ac99 | ||
|
|
2ebee8f40c | ||
|
|
43741dc5fc | ||
|
|
da9467b678 | ||
|
|
8f24a7b4fc | ||
|
|
ff48959e97 | ||
|
|
09e648d086 | ||
|
|
1d1db2e109 | ||
|
|
6a902286cd | ||
|
|
933724e4ee | ||
|
|
53034e6f05 | ||
|
|
c076be95a6 | ||
|
|
7b732dd68a | ||
|
|
3e34b1414e | ||
|
|
8456cd90d1 | ||
|
|
d716e1ff62 | ||
|
|
8e9acc9191 | ||
|
|
773a068b7d | ||
|
|
b37bfff155 | ||
|
|
a14cce222b | ||
|
|
c077e09436 | ||
|
|
213955566b | ||
|
|
b98cd3e6e1 | ||
|
|
987c8e8229 | ||
|
|
fcbb97ec55 | ||
|
|
c1ac7aebdb | ||
|
|
e4b0d1a03c | ||
|
|
f13f9dc5cd | ||
|
|
1f6170c000 | ||
|
|
53c7ec8ddc | ||
|
|
e438e53d36 | ||
|
|
792608f0d0 | ||
|
|
7b5678fd0f | ||
|
|
88c328a636 | ||
|
|
f9573530a8 | ||
|
|
c1df7dcca7 | ||
|
|
f141a0033e | ||
|
|
227d047584 | ||
|
|
73b73cd9da | ||
|
|
66be082bdb | ||
|
|
ac43cf0de1 | ||
|
|
fb41601d9f | ||
|
|
f35dda3fb3 | ||
|
|
7ee14f6f4f | ||
|
|
97920b42ee | ||
|
|
8ace0ec254 | ||
|
|
a3606f1098 | ||
|
|
616d379902 | ||
|
|
a27f475715 | ||
|
|
6ee76e8f46 | ||
|
|
891c30c9be | ||
|
|
9757a4c3b6 | ||
|
|
5be2f610cd | ||
|
|
35324e0853 | ||
|
|
ac753cdb93 | ||
|
|
3edd39f0eb | ||
|
|
8f790c28be | ||
|
|
c253afaf8e | ||
|
|
a6ac1dced0 | ||
|
|
d1e0f2cd94 | ||
|
|
af861d289a | ||
|
|
753f3f8c0f | ||
|
|
5c2a5741ee | ||
|
|
26941a2013 | ||
|
|
fad4c20da2 | ||
|
|
2b79ef301d | ||
|
|
014491e674 | ||
|
|
2e70cd4f2e | ||
|
|
689e1baa12 | ||
|
|
c34e84378a | ||
|
|
9a44becc73 | ||
|
|
d324d9fcf3 | ||
|
|
74cd48401c | ||
|
|
43081c57e7 | ||
|
|
b80a51d03f | ||
|
|
e90d5e4977 | ||
|
|
979034906a | ||
|
|
9e4fd2905b | ||
|
|
914c269411 | ||
|
|
2cacc4cd49 | ||
|
|
3024094584 | ||
|
|
4c66451324 | ||
|
|
7e7d808c90 | ||
|
|
0538e89948 | ||
|
|
6376f7c35d | ||
|
|
37721f2327 | ||
|
|
b0d2404644 | ||
|
|
5f76cb4819 | ||
|
|
427a54fc67 | ||
|
|
1cd1fb905d | ||
|
|
33333f87d2 | ||
|
|
4e5b8ec1e2 | ||
|
|
007feb76b7 | ||
|
|
d34dcb81fb | ||
|
|
8abb366903 | ||
|
|
3e7ba7ca28 | ||
|
|
14d52a9da9 | ||
|
|
847f8d1fee | ||
|
|
0c8d7adf37 | ||
|
|
d68d803709 | ||
|
|
13ef514d3e | ||
|
|
e20cd248a0 | ||
|
|
b8a3bda31d | ||
|
|
001493d984 | ||
|
|
013a3e3e8c | ||
|
|
4c2d984835 | ||
|
|
21bb0f15e0 | ||
|
|
8d5162ef8d | ||
|
|
257913ac0e | ||
|
|
c90dfccbf4 | ||
|
|
9c7dc8876f | ||
|
|
fc8cbdf01f | ||
|
|
5af4bfa912 | ||
|
|
0c5a47ff9d | ||
|
|
b4b4a3864f | ||
|
|
dca8561881 | ||
|
|
ee58b5299d | ||
|
|
7868b12279 | ||
|
|
42e91e8c4d | ||
|
|
28c9326305 | ||
|
|
40b8772980 | ||
|
|
b6a548629a | ||
|
|
291a37924d | ||
|
|
0b5eccd60a | ||
|
|
866a324922 | ||
|
|
baf48a8dc1 | ||
|
|
a85b2dd43c | ||
|
|
43059b3985 | ||
|
|
4d6183d6af | ||
|
|
79f87f03ce | ||
|
|
01ede29fc4 | ||
|
|
fb54d0df1c | ||
|
|
5b65495fbc | ||
|
|
cec3a8c1c2 | ||
|
|
8bd0b459b9 | ||
|
|
7da50516f9 | ||
|
|
6cbb2135b8 | ||
|
|
66dbc05022 | ||
|
|
18cc385c70 | ||
|
|
384f672eec | ||
|
|
f49a29cfb3 | ||
|
|
e8b70877cf | ||
|
|
9b084ea6a9 | ||
|
|
51f2fc4259 | ||
|
|
bb27482e9f | ||
|
|
75912896c9 | ||
|
|
6e0632ae1b | ||
|
|
7c90da0402 | ||
|
|
313a3eb7f2 | ||
|
|
cb054f0761 | ||
|
|
579b21716d | ||
|
|
3ffdc8cc2d | ||
|
|
e68af15b40 | ||
|
|
8e5fafaf05 | ||
|
|
95f9418e56 | ||
|
|
23af814ebc | ||
|
|
ae7dda9dab | ||
|
|
c5899944a2 | ||
|
|
c0e0f65ebe | ||
|
|
3bdce98964 | ||
|
|
478ab3bec4 | ||
|
|
ae77ee3df4 | ||
|
|
86e4a558c5 | ||
|
|
15c1e8f7bf | ||
|
|
f38770dbb5 | ||
|
|
75d37f8309 | ||
|
|
ed641c8cc8 | ||
|
|
069ebbc8d0 | ||
|
|
720f33a12a | ||
|
|
08f1cfbc79 | ||
|
|
9896697919 | ||
|
|
057d50b60b | ||
|
|
e3dc446e9e | ||
|
|
c529f756af | ||
|
|
c07eaecacb | ||
|
|
ddc03a1d62 | ||
|
|
ca59cff07f | ||
|
|
df4ddfdf25 | ||
|
|
c667a326a3 | ||
|
|
0099442852 | ||
|
|
eecb104cc5 | ||
|
|
a54283e637 | ||
|
|
ed06107a9f | ||
|
|
2d833daa57 | ||
|
|
67dd0a9433 | ||
|
|
fcc16d67f7 | ||
|
|
394f51f70d | ||
|
|
538627328e | ||
|
|
b5a21ccc4d | ||
|
|
2d331ff786 | ||
|
|
9d9ad15274 | ||
|
|
114ec2e493 | ||
|
|
2fb45da0d7 | ||
|
|
54a693dfa7 | ||
|
|
4be572ba58 | ||
|
|
e22d6ea65c | ||
|
|
baf86b5b83 | ||
|
|
e56c77319c | ||
|
|
a170dbd716 | ||
|
|
b821833437 | ||
|
|
1bb9b8cae3 | ||
|
|
1e32eb135d | ||
|
|
b695ce581e | ||
|
|
8138fc5fa2 | ||
|
|
0b2693cb98 | ||
|
|
3d959c98ed | ||
|
|
0ccee0b496 | ||
|
|
b7b2a0ab5e | ||
|
|
375402c455 | ||
|
|
03505da382 | ||
|
|
f56219746b | ||
|
|
116c3e491c | ||
|
|
e94c2f039c | ||
|
|
2fd52ef3eb | ||
|
|
29659536aa | ||
|
|
338a2831ee | ||
|
|
c64c1aca5b | ||
|
|
0dd72f4434 | ||
|
|
891d1da208 | ||
|
|
f8e903c422 | ||
|
|
b373824cf5 | ||
|
|
6c3c51e816 | ||
|
|
9abc3fbee2 | ||
|
|
9f20c325ab | ||
|
|
e7308efdd7 | ||
|
|
c2113b5719 | ||
|
|
c43f7ea861 | ||
|
|
5fac3f4adb | ||
|
|
7a31525c3c | ||
|
|
1613f5e982 | ||
|
|
b6907e999d | ||
|
|
c73077014b | ||
|
|
ce9bf26204 | ||
|
|
85f716ef03 | ||
|
|
fba696ad6d | ||
|
|
ed4267df50 | ||
|
|
1afeac4b95 | ||
|
|
1c761737b6 | ||
|
|
a159db74f6 | ||
|
|
ac781e51ec | ||
|
|
e050af31af | ||
|
|
9ca1b8dae0 | ||
|
|
a59ab44199 | ||
|
|
45d4a67ff4 | ||
|
|
97f5131ce0 | ||
|
|
2d4ddd8bd1 | ||
|
|
c94e49ed08 | ||
|
|
30a72b1227 | ||
|
|
b5ac7752d4 | ||
|
|
04ed7e14e2 | ||
|
|
d168926f98 | ||
|
|
2a8887d0b4 | ||
|
|
f7f6b74fd3 | ||
|
|
7609a49c17 | ||
|
|
213db08566 | ||
|
|
ba2fbd99a8 | ||
|
|
8ed681d82e | ||
|
|
1032f10d85 | ||
|
|
4fc46ac814 | ||
|
|
1611fb00d8 | ||
|
|
57a1f2743e | ||
|
|
fd1a1d326c | ||
|
|
ca7fdacfeb | ||
|
|
80f05d7467 | ||
|
|
e84604f7e3 | ||
|
|
66c3013e39 | ||
|
|
717802fe54 | ||
|
|
977a840253 | ||
|
|
6051d4d358 | ||
|
|
0a00a8a109 | ||
|
|
9d1aff3a75 | ||
|
|
3332279e75 |
19
.github/CODEOWNERS
vendored
@@ -1,7 +1,20 @@
|
||||
# Last match in file takes precedence.
|
||||
|
||||
# Ping for all PRs
|
||||
* @Acruid @PJB3005 @Silvertorch5
|
||||
|
||||
/Robust.*/Audio/Midi/ @Zumorica
|
||||
|
||||
/Robust.Client.NameGenerator @PaulRitter
|
||||
/Robust.Client.Injectors @PaulRitter
|
||||
/Robust.Generators @PaulRitter
|
||||
/Robust.Analyzers @PaulRitter
|
||||
/Robust.*/GameStates @PaulRitter
|
||||
/Robust.Shared/Analyzers @PaulRitter
|
||||
/Robust.*/Serialization @PaulRitter
|
||||
/Robust.*/Prototypes @PaulRitter
|
||||
/Robust.Shared/GameObjects/ComponentDependencies @PaulRitter
|
||||
/Robust.*/Containers @PaulRitter
|
||||
|
||||
# Be they Fluent translations or Freemarker templates, I know them both!
|
||||
*.ftl @RemieRichards
|
||||
|
||||
# Ping for all PRs
|
||||
* @Acruid @PJB3005 @Silvertorch5
|
||||
22
.gitignore
vendored
@@ -41,18 +41,6 @@ _ReSharper*/
|
||||
|
||||
# Resources
|
||||
*.resources
|
||||
/Resources/textures/Animations/*.*
|
||||
/Resources/ResourcePack.zip
|
||||
/Resources/textures/*_Animations.png
|
||||
/Resources/textures/*_Decals.png
|
||||
/Resources/textures/*_Effects.png
|
||||
/Resources/textures/*_Items.png
|
||||
/Resources/textures/*_Objects.png
|
||||
/Resources/textures/*_Tiles.png
|
||||
/Resources/textures/*_UserInterface.png
|
||||
/Resources/textures/*.TAI
|
||||
/Resources/SpriteRenderer/Ogre.log
|
||||
/Resources/Spriterenderer/output
|
||||
/Media
|
||||
/setenv.bat
|
||||
|
||||
@@ -78,16 +66,6 @@ project.lock.json
|
||||
# Created by NUnit.
|
||||
TestResult.xml
|
||||
|
||||
NetSerializerDebug.dll
|
||||
|
||||
# We're not gonna ship Mac extlibs with the repo due to size. (11 MB)
|
||||
Third-Party/extlibs/Mac/
|
||||
# Or the automatically-fetched Windows natives, for that matter.
|
||||
Third-Party/extlibs/Windows/
|
||||
|
||||
# Actually I'll make this folder because SS14.Shared.Bsdiff isn't third-party is it?
|
||||
Dependencies/
|
||||
|
||||
# Python stuff
|
||||
__pycache__
|
||||
.mypy_cache
|
||||
|
||||
3
.gitmodules
vendored
@@ -13,9 +13,6 @@
|
||||
[submodule "ManagedHttpListener"]
|
||||
path = ManagedHttpListener
|
||||
url = https://github.com/space-wizards/ManagedHttpListener.git
|
||||
[submodule "Linguini"]
|
||||
path = Linguini
|
||||
url = https://github.com/space-wizards/Linguini
|
||||
[submodule "cefglue"]
|
||||
path = cefglue
|
||||
url = https://github.com/space-wizards/cefglue.git
|
||||
|
||||
1
Linguini
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<PropertyGroup><Version>0.8.2</Version></PropertyGroup>
|
||||
<PropertyGroup><Version>0.8.45</Version></PropertyGroup>
|
||||
</Project>
|
||||
|
||||
8
Resources/.gitignore
vendored
@@ -1,8 +0,0 @@
|
||||
# .import files are made by Godot because the assets are exposed if using symlinks.
|
||||
# IF you need to persist a .import file because of something used Godot-side (GUI-side),
|
||||
# you can do a negation with !.
|
||||
*.import
|
||||
# Negation would be like this:
|
||||
#!/Textures/UserInterface/1pxwhite.png.import
|
||||
!/Scenes/SS14Window/closewindow.png.import
|
||||
/I_MADE_THE_SYMLINK
|
||||
1
Resources/Locale/en-US/defaultwindow.ftl
Normal file
@@ -0,0 +1 @@
|
||||
defaultwindow-placeholder-title = Exemplary Window Title Here
|
||||
@@ -1 +0,0 @@
|
||||
ss14window-placeholder-title = Exemplary Window Title Here
|
||||
|
Before Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 927 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,2 +0,0 @@
|
||||
sample:
|
||||
filter: true
|
||||
@@ -1,152 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="113.67364mm"
|
||||
height="56.37999mm"
|
||||
viewBox="0 0 113.67364 56.37999"
|
||||
version="1.1"
|
||||
id="svg3223"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:export-filename="/home/pj/Projects/space-station-14/RobustToolbox/Resources/Textures/Logo/logo.png"
|
||||
inkscape:export-xdpi="67.034012"
|
||||
inkscape:export-ydpi="67.034012">
|
||||
<defs
|
||||
id="defs3217" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="159.25688"
|
||||
inkscape:cy="149.8376"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3220">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-56.556041,-109.30405)">
|
||||
<g
|
||||
transform="translate(-3.7799155,-23.482217)"
|
||||
id="g2559">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path148"
|
||||
style="fill:#e23229;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 143.44393,145.03077 0.1484,-0.70241 5.14257,-0.35974 -6.23062,29.75753 -0.69199,0.0483 6.08255,-29.05476 z m 1.18682,31.16724 7.31835,-35.07438 -10.43302,0.72923 -1.28514,6.12249 4.45021,-0.31125 -6.03235,28.95253 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path152"
|
||||
style="fill:#e23229;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 169.25392,142.53363 -3.53672,16.8925 4.79124,-0.32874 -0.15681,0.75402 -4.79234,0.32881 -2.53549,12.11072 -0.75405,0.052 2.53724,-12.11108 -11.37332,0.78724 z m -18.98495,21.327 11.37324,-0.78724 -2.5247,12.11146 5.98312,-0.41839 2.52513,-12.10406 4.82658,-0.33116 1.26721,-6.07903 -4.82564,0.33109 3.52398,-16.89101 -4.56014,0.33565 -16.70168,19.60839 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path156"
|
||||
style="fill:#fefefe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 88.591903,151.83158 -2.595368,0.18103 0.741705,-3.62685 2.595079,-0.182 z m -4.581719,-6.72375 -3.99857,19.05572 3.468889,-0.24195 1.774487,-8.38766 6.064403,-0.42299 2.224789,-10.66981 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path160"
|
||||
style="fill:#fefefe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 100.85029,147.82177 2.83371,-0.19837 -0.74166,3.60045 -2.83371,0.19836 z m -6.726869,15.77696 3.469312,-0.24198 1.774487,-8.38695 2.8337,-0.19837 -1.77453,8.38695 3.46938,-0.24296 3.99895,-19.05608 -9.771974,0.68329 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path164"
|
||||
style="fill:#fefefe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 108.80467,162.68768 9.74554,-0.68118 1.377,-6.50502 -3.4693,0.24296 -0.63527,2.9832 -2.80718,0.19654 2.51548,-12.01379 2.80731,-0.19754 -0.50239,2.4195 3.46902,-0.24294 1.24513,-5.93998 -9.74589,0.68119 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path168"
|
||||
style="fill:#fefefe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 135.66767,145.61788 0.7409,-3.5211 -8.95132,0.6259 -3.99824,19.0564 8.95097,-0.62626 0.74082,-3.52077 -5.4816,0.383 1.03272,-4.89224 3.78675,-0.26474 0.74189,-3.52113 -3.78675,0.26474 0.74081,-3.6011 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path172"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 71.070134,172.95255 -4.734664,0.33077 0.57447,-2.73456 2.139294,-0.14973 -0.376241,1.80924 2.595442,-0.18103 0.930868,-4.44332 -7.330114,0.5118 -1.66358,8.00131 4.734672,-0.33077 -0.773014,3.62025 -2.119829,0.1484 0.475696,-2.23174 -2.614982,0.18237 -1.030327,4.86616 7.330104,-0.5118 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path176"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 74.794828,169.99754 2.496095,-0.17422 -2.436556,11.62085 2.595151,-0.182 2.436903,-11.62086 2.496023,-0.17421 0.554678,-2.63441 -7.587516,0.53064 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path180"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 87.573322,171.75893 0.554606,-2.69318 2.119754,-0.1484 -0.554978,2.69354 z m 2.832629,8.59803 2.991888,-14.25529 -7.310379,0.51154 -2.99153,14.25493 2.595227,-0.18201 1.327293,-6.27378 2.11968,-0.14839 -1.327288,6.27414 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path184"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 98.977684,179.78056 2.436926,-11.62086 2.49608,-0.1752 0.55493,-2.63374 -7.587518,0.53065 -0.554634,2.63373 2.495947,-0.17421 -2.436599,11.6212 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path188"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 104.62426,179.38562 2.5951,-0.18101 2.9915,-14.25528 -2.59522,0.182 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path192"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 115.73198,167.18138 2.11975,-0.14839 -1.88236,8.98749 -2.11949,0.14838 z m -5.03203,11.80203 7.31001,-0.51042 2.99153,-14.25494 -7.31028,0.51044 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path196"
|
||||
style="fill:#d5d5d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 124.08538,178.07141 1.36653,-6.47511 1.18856,6.29603 2.25853,-0.15792 2.99192,-14.25493 -2.59522,0.18201 -1.36734,6.57353 -1.18854,-6.39514 -2.25854,0.15791 -2.99084,14.25493 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path200"
|
||||
style="fill:#fefefe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 66.677649,158.65784 -1.377018,6.50538 9.798398,-0.68471 2.489415,-11.87958 -6.329111,0.44214 0.767747,-3.65465 2.860076,-0.20018 -0.503204,2.41917 3.469299,-0.24297 1.244526,-5.93996 -4.328229,0.30289 -8.728772,0.56991 2.909827,1.489 -1.87565,9.01912 6.329037,-0.44213 -1.032406,4.83973 -2.833645,0.19738 0.635302,-2.98354 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path204"
|
||||
style="fill:#e23229;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 70.519326,139.92277 -0.277457,1.36553 103.473271,-7.11317 0.29445,-1.38886 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path208"
|
||||
style="fill:#e23229;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.34773216"
|
||||
d="m 60.335956,189.16626 103.473274,-7.11356 0.29444,-1.38885 -103.489968,7.13649 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1772"
|
||||
d="m 167.92741,145.26275 -12.87687,14.89523 9.91366,-0.68019 z m -3.743,7.27758 -1.02896,4.93612 -3.51544,0.2412 z"
|
||||
style="fill:#e23229;fill-opacity:1;stroke:none;stroke-width:0.2626844px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.4 KiB |
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -10,6 +11,8 @@ namespace Robust.Client.WebView.Cef
|
||||
{
|
||||
internal partial class WebViewManagerCef : IWebViewManagerImpl
|
||||
{
|
||||
private static readonly string BasePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!;
|
||||
|
||||
private CefApp _app = default!;
|
||||
|
||||
[Dependency] private readonly IDependencyCollection _dependencyCollection = default!;
|
||||
@@ -27,7 +30,7 @@ namespace Robust.Client.WebView.Cef
|
||||
else
|
||||
throw new NotSupportedException("Unsupported platform for CEF!");
|
||||
|
||||
var subProcessPath = PathHelpers.ExecutableRelativeFile(subProcessName);
|
||||
var subProcessPath = Path.Combine(BasePath, subProcessName);
|
||||
var cefResourcesPath = LocateCefResources();
|
||||
|
||||
// System.Console.WriteLine(AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES"));
|
||||
@@ -60,7 +63,7 @@ namespace Robust.Client.WebView.Cef
|
||||
|
||||
private static string? LocateCefResources()
|
||||
{
|
||||
if (ProbeDir(PathHelpers.GetExecutableDirectory(), out var path))
|
||||
if (ProbeDir(BasePath, out var path))
|
||||
return path;
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="Robust.Natives.Cef" Version="95.7.14" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -293,60 +293,50 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
|
||||
MapCoordinates? mapPos = null;
|
||||
var trackingEntity = renderer.TrackingEntity != null && !_entityManager.Deleted(renderer.TrackingEntity);
|
||||
if (trackingEntity)
|
||||
{
|
||||
renderer.TrackingCoordinates = _entityManager.GetComponent<TransformComponent>(renderer.TrackingEntity!.Value).Coordinates;
|
||||
}
|
||||
|
||||
if (renderer.TrackingCoordinates != null)
|
||||
{
|
||||
mapPos = renderer.TrackingCoordinates.Value.ToMap(_entityManager);
|
||||
}
|
||||
else if (renderer.TrackingEntity != null)
|
||||
{
|
||||
mapPos = _entityManager.GetComponent<TransformComponent>(renderer.TrackingEntity.Value).MapPosition;
|
||||
}
|
||||
|
||||
if (mapPos != null)
|
||||
if (mapPos != null && mapPos.Value.MapId == _eyeManager.CurrentMap)
|
||||
{
|
||||
var pos = mapPos.Value;
|
||||
if (pos.MapId != _eyeManager.CurrentMap)
|
||||
{
|
||||
renderer.Source.SetVolume(-10000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
|
||||
var occlusion = 0f;
|
||||
if (sourceRelative.Length > 0)
|
||||
{
|
||||
occlusion = _broadPhaseSystem.IntersectRayPenetration(
|
||||
pos.MapId,
|
||||
new CollisionRay(
|
||||
pos.Position,
|
||||
sourceRelative.Normalized,
|
||||
OcclusionCollisionMask),
|
||||
sourceRelative.Length,
|
||||
renderer.TrackingEntity);
|
||||
}
|
||||
|
||||
renderer.Source.SetOcclusion(occlusion);
|
||||
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
|
||||
var occlusion = 0f;
|
||||
if (sourceRelative.Length > 0)
|
||||
{
|
||||
occlusion = _broadPhaseSystem.IntersectRayPenetration(
|
||||
pos.MapId,
|
||||
new CollisionRay(
|
||||
pos.Position,
|
||||
sourceRelative.Normalized,
|
||||
OcclusionCollisionMask),
|
||||
sourceRelative.Length,
|
||||
renderer.TrackingEntity);
|
||||
}
|
||||
|
||||
if (renderer.Source.SetPosition(pos.Position))
|
||||
renderer.Source.SetOcclusion(occlusion);
|
||||
|
||||
if (!renderer.Source.SetPosition(pos.Position))
|
||||
{
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderer.TrackingEntity != null)
|
||||
if (trackingEntity)
|
||||
{
|
||||
renderer.Source.SetVelocity(renderer.TrackingEntity.Value.GlobalLinearVelocity());
|
||||
renderer.Source.SetVelocity(renderer.TrackingEntity!.Value.GlobalLinearVelocity());
|
||||
}
|
||||
|
||||
if (float.IsNaN(pos.Position.X) || float.IsNaN(pos.Position.Y))
|
||||
{
|
||||
// just duck out instead of move to NaN
|
||||
renderer.Source.SetOcclusion(float.MaxValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
_midiSawmill?.Warning("Interrupting positional audio, can't set position.");
|
||||
renderer.Source.StopPlaying();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Source.SetOcclusion(float.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace Robust.Client
|
||||
IoCManager.Register<IGameTiming, ClientGameTiming>();
|
||||
IoCManager.Register<IClientGameTiming, ClientGameTiming>();
|
||||
IoCManager.Register<IPrototypeManager, ClientPrototypeManager>();
|
||||
IoCManager.Register<IMapManager, ClientMapManager>();
|
||||
IoCManager.Register<IMapManagerInternal, ClientMapManager>();
|
||||
IoCManager.Register<IClientMapManager, ClientMapManager>();
|
||||
IoCManager.Register<IMapManager, NetworkedMapManager>();
|
||||
IoCManager.Register<IMapManagerInternal, NetworkedMapManager>();
|
||||
IoCManager.Register<INetworkedMapManager, NetworkedMapManager>();
|
||||
IoCManager.Register<IEntityManager, ClientEntityManager>();
|
||||
IoCManager.Register<IEntityLookup, EntityLookup>();
|
||||
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Robust.Client.Console
|
||||
|
||||
public bool CanCommand(string cmdName)
|
||||
{
|
||||
return _implementation?.CanCommand(cmdName) ?? false;
|
||||
return _implementation?.CanCommand(cmdName) ?? true;
|
||||
}
|
||||
|
||||
public bool CanViewVar()
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Log;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
@@ -40,6 +43,8 @@ namespace Robust.Client.Console
|
||||
/// <inheritdoc cref="IClientConsoleHost" />
|
||||
internal class ClientConsoleHost : ConsoleHost, IClientConsoleHost
|
||||
{
|
||||
[Dependency] private readonly IClientConGroupController _conGroup = default!;
|
||||
|
||||
private bool _requestedCommands;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -103,6 +108,14 @@ namespace Robust.Client.Console
|
||||
|
||||
if (AvailableCommands.ContainsKey(commandName))
|
||||
{
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
|
||||
if (!_conGroup.CanCommand(commandName) && playerManager.LocalPlayer?.Session.Status > SessionStatus.Connecting)
|
||||
{
|
||||
WriteError(null, $"Insufficient perms for command: {commandName}");
|
||||
return;
|
||||
}
|
||||
|
||||
var command1 = AvailableCommands[commandName];
|
||||
args.RemoveAt(0);
|
||||
var shell = new ConsoleShell(this, null);
|
||||
|
||||
@@ -449,15 +449,13 @@ namespace Robust.Client.Console.Commands
|
||||
var uiMgr = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
var res = IoCManager.Resolve<IResourceManager>();
|
||||
|
||||
using (var stream = res.UserData.Create(new ResourcePath("/guidump.txt")))
|
||||
using (var writer = new StreamWriter(stream, EncodingHelpers.UTF8))
|
||||
using var writer = res.UserData.OpenWriteText(new ResourcePath("/guidump.txt"));
|
||||
|
||||
foreach (var root in uiMgr.AllRoots)
|
||||
{
|
||||
foreach (var root in uiMgr.AllRoots)
|
||||
{
|
||||
writer.WriteLine($"ROOT: {root}");
|
||||
_writeNode(root, 0, writer);
|
||||
writer.WriteLine("---------------");
|
||||
}
|
||||
writer.WriteLine($"ROOT: {root}");
|
||||
_writeNode(root, 0, writer);
|
||||
writer.WriteLine("---------------");
|
||||
}
|
||||
|
||||
shell.WriteLine("Saved guidump");
|
||||
@@ -522,7 +520,7 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var window = new SS14Window { MinSize = (500, 400)};
|
||||
var window = new DefaultWindow { MinSize = (500, 400)};
|
||||
var tabContainer = new TabContainer();
|
||||
window.Contents.AddChild(tabContainer);
|
||||
var scroll = new ScrollContainer();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#if !FULL_RELEASE
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -22,44 +20,38 @@ namespace Robust.Client.Console.Commands
|
||||
var wantName = args.Length > 0 ? args[0] : null;
|
||||
|
||||
var basePath = Path.GetDirectoryName(UserDataDir.GetUserDataDir())!;
|
||||
var cfgPath = Path.Combine(basePath, "launcher", "launcher_config.json");
|
||||
var dbPath = Path.Combine(basePath, "launcher", "settings.db");
|
||||
|
||||
var data = JsonSerializer.Deserialize<LauncherConfig>(File.ReadAllText(cfgPath))!;
|
||||
using var con = new SqliteConnection($"Data Source={dbPath};Mode=ReadOnly");
|
||||
con.Open();
|
||||
using var cmd = con.CreateCommand();
|
||||
cmd.CommandText = "SELECT UserId, UserName, Token FROM Login WHERE Expires > datetime('NOW')";
|
||||
|
||||
var login = wantName != null
|
||||
? data.Logins.FirstOrDefault(p => p.Username == wantName)
|
||||
: data.Logins.FirstOrDefault();
|
||||
if (wantName != null)
|
||||
{
|
||||
cmd.CommandText += " AND UserName = @userName";
|
||||
cmd.Parameters.AddWithValue("@userName", wantName);
|
||||
}
|
||||
|
||||
if (login == null)
|
||||
cmd.CommandText += " LIMIT 1;";
|
||||
|
||||
using var reader = cmd.ExecuteReader();
|
||||
|
||||
if (!reader.Read())
|
||||
{
|
||||
shell.WriteLine("Unable to find a matching login");
|
||||
return;
|
||||
}
|
||||
|
||||
var token = login.Token.Token;
|
||||
var userId = login.UserId;
|
||||
var userId = Guid.Parse(reader.GetString(0));
|
||||
var userName = reader.GetString(1);
|
||||
var token = reader.GetString(2);
|
||||
|
||||
var cfg = IoCManager.Resolve<IAuthManager>();
|
||||
cfg.Token = token;
|
||||
cfg.UserId = new NetUserId(Guid.Parse(userId));
|
||||
}
|
||||
cfg.UserId = new NetUserId(userId);
|
||||
|
||||
private sealed class LauncherConfig
|
||||
{
|
||||
[JsonInclude] [JsonPropertyName("logins")]
|
||||
public LauncherLogin[] Logins = default!;
|
||||
}
|
||||
|
||||
private sealed class LauncherLogin
|
||||
{
|
||||
[JsonInclude] public string Username = default!;
|
||||
[JsonInclude] public string UserId = default!;
|
||||
[JsonInclude] public LauncherToken Token = default!;
|
||||
}
|
||||
|
||||
private sealed class LauncherToken
|
||||
{
|
||||
[JsonInclude] public string Token = default!;
|
||||
shell.WriteLine($"Logged into account {userName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using static Robust.Shared.Network.Messages.MsgScriptCompletionResponse;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public class Completions : SS14Window
|
||||
public class Completions : DefaultWindow
|
||||
{
|
||||
private HistoryLineEdit _textBar;
|
||||
private ScrollContainer _suggestPanel = new()
|
||||
|
||||
@@ -210,6 +210,23 @@ namespace Robust.Client.Console
|
||||
vvm.OpenVV(a);
|
||||
}
|
||||
|
||||
protected override void WriteSyntax(object toString)
|
||||
{
|
||||
var code = toString.ToString();
|
||||
|
||||
if (code == null)
|
||||
return;
|
||||
|
||||
var options = ScriptInstanceShared.GetScriptOptions(_owner._reflectionManager).AddReferences(typeof(Image).Assembly);
|
||||
var script = CSharpScript.Create(code, options, typeof(ScriptGlobals));
|
||||
script.Compile();
|
||||
|
||||
var syntax = new FormattedMessage();
|
||||
ScriptInstanceShared.AddWithSyntaxHighlighting(script, syntax, code, _owner._highlightWorkspace);
|
||||
|
||||
_owner.OutputPanel.AddMessage(syntax);
|
||||
}
|
||||
|
||||
public override void write(object toString)
|
||||
{
|
||||
_owner.OutputPanel.AddText(toString?.ToString() ?? "");
|
||||
|
||||
@@ -15,7 +15,7 @@ using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public class WatchWindow : SS14Window
|
||||
public class WatchWindow : DefaultWindow
|
||||
{
|
||||
private readonly IReflectionManager _reflectionManager;
|
||||
|
||||
@@ -155,6 +155,11 @@ namespace Robust.Client.Console
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void WriteSyntax(object toString)
|
||||
{
|
||||
// No-op: nothing to write to.
|
||||
}
|
||||
|
||||
public override void write(object toString)
|
||||
{
|
||||
// No-op: nothing to write to.
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
const float AlphaModifier = 0.2f;
|
||||
|
||||
foreach (var fixture in physBody.Fixtures)
|
||||
foreach (var fixture in _entityManager.GetComponent<FixturesComponent>(physBody.Owner).Fixtures.Values)
|
||||
{
|
||||
// Invalid shape - Box2D doesn't check for IsSensor
|
||||
if (physBody.BodyType == BodyType.Dynamic && fixture.Mass == 0f)
|
||||
@@ -274,7 +274,7 @@ namespace Robust.Client.Debugging
|
||||
const float AlphaModifier = 0.2f;
|
||||
Box2? aabb = null;
|
||||
|
||||
foreach (var fixture in physBody.Fixtures)
|
||||
foreach (var fixture in _entityManager.GetComponent<FixturesComponent>(physBody.Owner).Fixtures.Values)
|
||||
{
|
||||
for (var i = 0; i < fixture.Shape.ChildCount; i++)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Robust.Client.WebViewHook;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -8,12 +10,8 @@ namespace Robust.Client
|
||||
{
|
||||
internal sealed partial class GameController
|
||||
{
|
||||
private void LoadOptionalRobustModules(GameController.DisplayMode mode)
|
||||
private void LoadOptionalRobustModules(DisplayMode mode, ResourceManifestData manifest)
|
||||
{
|
||||
// In the future, this manifest should be loaded somewhere else and used for more parts of init.
|
||||
// For now, this is fine.
|
||||
var manifest = LoadResourceManifest();
|
||||
|
||||
foreach (var module in manifest.Modules)
|
||||
{
|
||||
switch (module)
|
||||
@@ -32,7 +30,8 @@ namespace Robust.Client
|
||||
{
|
||||
Logger.Debug("Loading Robust.Client.WebView");
|
||||
|
||||
var assembly = LoadRobustModuleAssembly("Robust.Client.WebView");
|
||||
var alc = CreateModuleLoadContext("Robust.Client.WebView");
|
||||
var assembly = alc.LoadFromAssemblyName(new AssemblyName("Robust.Client.WebView"));
|
||||
var attribute = assembly.GetCustomAttribute<WebViewManagerImplAttribute>()!;
|
||||
DebugTools.AssertNotNull(attribute);
|
||||
|
||||
@@ -43,10 +42,52 @@ namespace Robust.Client
|
||||
Logger.Debug("Done initializing Robust.Client.WebView");
|
||||
}
|
||||
|
||||
private Assembly LoadRobustModuleAssembly(string assemblyName)
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AssemblyLoadContext"/> that loads from an engine module directory.
|
||||
/// </summary>
|
||||
private AssemblyLoadContext CreateModuleLoadContext(string moduleName)
|
||||
{
|
||||
// TODO: Launcher distribution and all that stuff.
|
||||
return Assembly.Load(assemblyName);
|
||||
var sawmill = _logManager.GetSawmill("robust.mod");
|
||||
|
||||
var alc = new AssemblyLoadContext(moduleName);
|
||||
var envVarName = $"ROBUST_MODULE_{moduleName.ToUpperInvariant().Replace('.', '_')}";
|
||||
var envVar = Environment.GetEnvironmentVariable(envVarName);
|
||||
if (string.IsNullOrEmpty(envVar))
|
||||
{
|
||||
sawmill.Debug("Module {ModuleName} has no path override specified", moduleName);
|
||||
return alc;
|
||||
}
|
||||
|
||||
sawmill.Debug("Path for module {ModuleName} is {ModulePath}", moduleName, envVar);
|
||||
|
||||
alc.Resolving += (_, name) =>
|
||||
{
|
||||
sawmill.Debug("Loading {AssemblyName} from module {ModuleName}", name.ToString(), moduleName);
|
||||
var assemblyPath = Path.Combine(envVar, $"{name.Name}.dll");
|
||||
if (!File.Exists(assemblyPath))
|
||||
return null;
|
||||
|
||||
return alc.LoadFromAssemblyPath(assemblyPath);
|
||||
};
|
||||
|
||||
_modLoader.ExtraModuleLoaders += name =>
|
||||
{
|
||||
foreach (var assembly in alc.Assemblies)
|
||||
{
|
||||
var assemblyName = assembly.GetName();
|
||||
if (assemblyName.Name == name.Name)
|
||||
{
|
||||
sawmill.Debug("Resolved {ResolvingAssembly} as assembly {ResolvedAssembly} from {ModuleName}", name.ToString(), assemblyName.ToString(), moduleName);
|
||||
return assembly;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
_modLoader.AddEngineModuleDirectory(envVar);
|
||||
|
||||
return alc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace Robust.Client
|
||||
public GameControllerOptions Options { get; private set; } = new();
|
||||
public InitialLaunchState LaunchState { get; private set; } = default!;
|
||||
|
||||
private ResourceManifestData? _resourceManifest;
|
||||
|
||||
public void SetCommandLineArgs(CommandLineArgs args)
|
||||
{
|
||||
_commandLineArgs = args;
|
||||
@@ -86,19 +88,25 @@ namespace Robust.Client
|
||||
|
||||
internal bool StartupContinue(DisplayMode displayMode)
|
||||
{
|
||||
DebugTools.AssertNotNull(_resourceManifest);
|
||||
|
||||
_clyde.InitializePostWindowing();
|
||||
_clydeAudio.InitializePostWindowing();
|
||||
_clyde.SetWindowTitle(Options.DefaultWindowTitle);
|
||||
_clyde.SetWindowTitle(Options.DefaultWindowTitle ?? _resourceManifest!.DefaultWindowTitle ?? "RobustToolbox");
|
||||
|
||||
_taskManager.Initialize();
|
||||
_fontManager.SetFontDpi((uint)_configurationManager.GetCVar(CVars.DisplayFontDpi));
|
||||
|
||||
// Load optional Robust modules.
|
||||
LoadOptionalRobustModules(displayMode, _resourceManifest!);
|
||||
|
||||
// Disable load context usage on content start.
|
||||
// This prevents Content.Client being loaded twice and things like csi blowing up because of it.
|
||||
_modLoader.SetUseLoadContext(!ContentStart);
|
||||
_modLoader.SetEnableSandboxing(Options.Sandboxing);
|
||||
|
||||
if (!_modLoader.TryLoadModulesFrom(Options.AssemblyDirectory, Options.ContentModulePrefix))
|
||||
var assemblyPrefix = Options.ContentModulePrefix ?? _resourceManifest!.AssemblyPrefix ?? "Content.";
|
||||
if (!_modLoader.TryLoadModulesFrom(Options.AssemblyDirectory, assemblyPrefix))
|
||||
{
|
||||
Logger.Fatal("Errors while loading content assemblies.");
|
||||
return false;
|
||||
@@ -111,9 +119,6 @@ namespace Robust.Client
|
||||
|
||||
IoCManager.Resolve<ISerializationManager>().Initialize();
|
||||
|
||||
// Load optional Robust modules.
|
||||
LoadOptionalRobustModules(displayMode);
|
||||
|
||||
// Call Init in game assemblies.
|
||||
_modLoader.BroadcastRunLevel(ModRunLevel.PreInit);
|
||||
_modLoader.BroadcastRunLevel(ModRunLevel.Init);
|
||||
@@ -129,8 +134,8 @@ namespace Robust.Client
|
||||
_prototypeManager.Initialize();
|
||||
_prototypeManager.LoadDirectory(Options.PrototypeDirectory);
|
||||
_prototypeManager.Resync();
|
||||
_mapManager.Initialize();
|
||||
_entityManager.Initialize();
|
||||
_mapManager.Initialize();
|
||||
_gameStateManager.Initialize();
|
||||
_placementManager.Initialize();
|
||||
_viewVariablesManager.Initialize();
|
||||
@@ -209,7 +214,7 @@ namespace Robust.Client
|
||||
{
|
||||
// Parses /manifest.yml for game-specific settings that cannot be exclusively set up by content code.
|
||||
if (!_resourceCache.TryContentFileRead("/manifest.yml", out var stream))
|
||||
return new ResourceManifestData(Array.Empty<string>());
|
||||
return new ResourceManifestData(Array.Empty<string>(), null, null, null, null);
|
||||
|
||||
var yamlStream = new YamlStream();
|
||||
using (stream)
|
||||
@@ -218,6 +223,9 @@ namespace Robust.Client
|
||||
yamlStream.Load(streamReader);
|
||||
}
|
||||
|
||||
if (yamlStream.Documents.Count == 0)
|
||||
return new ResourceManifestData(Array.Empty<string>(), null, null, null, null);
|
||||
|
||||
if (yamlStream.Documents.Count != 1 || yamlStream.Documents[0].RootNode is not YamlMappingNode mapping)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
@@ -235,7 +243,23 @@ namespace Robust.Client
|
||||
}
|
||||
}
|
||||
|
||||
return new ResourceManifestData(modules);
|
||||
string? assemblyPrefix = null;
|
||||
if (mapping.TryGetNode("assemblyPrefix", out var prefixNode))
|
||||
assemblyPrefix = prefixNode.AsString();
|
||||
|
||||
string? defaultWindowTitle = null;
|
||||
if (mapping.TryGetNode("defaultWindowTitle", out var winTitleNode))
|
||||
defaultWindowTitle = winTitleNode.AsString();
|
||||
|
||||
string? windowIconSet = null;
|
||||
if (mapping.TryGetNode("windowIconSet", out var iconSetNode))
|
||||
windowIconSet = iconSetNode.AsString();
|
||||
|
||||
string? splashLogo = null;
|
||||
if (mapping.TryGetNode("splashLogo", out var splashNode))
|
||||
splashLogo = splashNode.AsString();
|
||||
|
||||
return new ResourceManifestData(modules, assemblyPrefix, defaultWindowTitle, windowIconSet, splashLogo);
|
||||
}
|
||||
|
||||
internal bool StartupSystemSplash(GameControllerOptions options, Func<ILogHandler>? logHandlerFactory)
|
||||
@@ -301,15 +325,6 @@ namespace Robust.Client
|
||||
_configurationManager.OverrideConVars(_commandLineArgs.CVars);
|
||||
}
|
||||
|
||||
{
|
||||
// Handle GameControllerOptions implicit CVar overrides.
|
||||
_configurationManager.OverrideConVars(new[]
|
||||
{
|
||||
(CVars.DisplayWindowIconSet.Name, options.WindowIconSet.ToString()),
|
||||
(CVars.DisplaySplashLogo.Name, options.SplashLogo.ToString())
|
||||
});
|
||||
}
|
||||
|
||||
ProfileOptSetup.Setup(_configurationManager);
|
||||
|
||||
_resourceCache.Initialize(Options.LoadConfigAndUserData ? userDataDir : null);
|
||||
@@ -324,11 +339,32 @@ namespace Robust.Client
|
||||
|
||||
if (_loaderArgs != null)
|
||||
{
|
||||
if (_loaderArgs.ApiMounts is { } mounts)
|
||||
{
|
||||
foreach (var (api, prefix) in mounts)
|
||||
{
|
||||
_resourceCache.MountLoaderApi(api, "", new ResourcePath(prefix));
|
||||
}
|
||||
}
|
||||
|
||||
_stringSerializer.EnableCaching = false;
|
||||
_resourceCache.MountLoaderApi(_loaderArgs.FileApi, "Resources/");
|
||||
_modLoader.VerifierExtraLoadHandler = VerifierExtraLoadHandler;
|
||||
}
|
||||
|
||||
_resourceManifest = LoadResourceManifest();
|
||||
|
||||
{
|
||||
// Handle GameControllerOptions implicit CVar overrides.
|
||||
_configurationManager.OverrideConVars(new[]
|
||||
{
|
||||
(CVars.DisplayWindowIconSet.Name,
|
||||
options.WindowIconSet?.ToString() ?? _resourceManifest.WindowIconSet ?? ""),
|
||||
(CVars.DisplaySplashLogo.Name,
|
||||
options.SplashLogo?.ToString() ?? _resourceManifest.SplashLogo ?? "")
|
||||
});
|
||||
}
|
||||
|
||||
_clyde.TextEntered += TextEntered;
|
||||
_clyde.MouseMove += MouseMove;
|
||||
_clyde.KeyUp += KeyUp;
|
||||
@@ -431,7 +467,9 @@ namespace Robust.Client
|
||||
// In singleplayer, however, we're in full control instead.
|
||||
else if (_client.RunLevel == ClientRunLevel.SinglePlayerGame)
|
||||
{
|
||||
_entityManager.TickUpdate(frameEventArgs.DeltaSeconds);
|
||||
// The last real tick is the current tick! This way we won't be in "prediction" mode.
|
||||
_gameTiming.LastRealTick = _gameTiming.CurTick;
|
||||
_entityManager.TickUpdate(frameEventArgs.DeltaSeconds, noPredictions: false);
|
||||
_lookup.Update();
|
||||
}
|
||||
|
||||
@@ -543,6 +581,12 @@ namespace Robust.Client
|
||||
_clydeAudio.Shutdown();
|
||||
}
|
||||
|
||||
private sealed record ResourceManifestData(string[] Modules);
|
||||
private sealed record ResourceManifestData(
|
||||
string[] Modules,
|
||||
string? AssemblyPrefix,
|
||||
string? DefaultWindowTitle,
|
||||
string? WindowIconSet,
|
||||
string? SplashLogo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,18 @@ namespace Robust.Client
|
||||
/// <summary>
|
||||
/// Default window title.
|
||||
/// </summary>
|
||||
public string DefaultWindowTitle { get; init; } = "Space Station 14";
|
||||
/// <remarks>
|
||||
/// Defaults to <c>RobustToolbox</c> if unset.
|
||||
/// </remarks>
|
||||
public string? DefaultWindowTitle { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Assemblies with this prefix will be loaded.
|
||||
/// </summary>
|
||||
public string ContentModulePrefix { get; init; } = "Content.";
|
||||
/// <remarks>
|
||||
/// Defaults to <c>Content.</c> if unset.
|
||||
/// </remarks>
|
||||
public string? ContentModulePrefix { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the content build directory, for game pack mounting purposes.
|
||||
@@ -55,12 +61,12 @@ namespace Robust.Client
|
||||
/// <summary>
|
||||
/// Directory resource path containing window icons to load.
|
||||
/// </summary>
|
||||
public ResourcePath WindowIconSet { get; init; } = new("/Textures/Logo/icon");
|
||||
public ResourcePath? WindowIconSet { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Resource path for splash image to show when the game starts up.
|
||||
/// </summary>
|
||||
public ResourcePath SplashLogo { get; init; } = new("/Textures/Logo/logo.png");
|
||||
public ResourcePath? SplashLogo { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to disable mounting the "Resources/" folder on FULL_RELEASE.
|
||||
|
||||
@@ -29,13 +29,9 @@ namespace Robust.Client.GameObjects
|
||||
RegisterClass<EyeComponent>();
|
||||
RegisterClass<AnimationPlayerComponent>();
|
||||
RegisterClass<TimerComponent>();
|
||||
|
||||
#if DEBUG
|
||||
RegisterClass<DebugExceptionOnAddComponent>();
|
||||
RegisterClass<DebugExceptionInitializeComponent>();
|
||||
RegisterClass<DebugExceptionStartupComponent>();
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Robust.Client.GameObjects
|
||||
_networkManager.RegisterNetMessage<MsgEntity>(HandleEntityNetworkMessage);
|
||||
}
|
||||
|
||||
public override void TickUpdate(float frameTime, Histogram? histogram)
|
||||
public override void TickUpdate(float frameTime, bool noPredictions, Histogram? histogram)
|
||||
{
|
||||
using (histogram?.WithLabels("EntityNet").NewTimer())
|
||||
{
|
||||
@@ -79,7 +79,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
base.TickUpdate(frameTime, histogram);
|
||||
base.TickUpdate(frameTime, noPredictions, histogram);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -109,10 +109,11 @@ namespace Robust.Client.GameObjects
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public void SendComponentNetworkMessage(INetChannel? channel, EntityUid entity, IComponent component, ComponentMessage message)
|
||||
{
|
||||
var netId = ComponentFactory.GetRegistration(component.GetType()).NetID;
|
||||
var componentType = component.GetType();
|
||||
var netId = ComponentFactory.GetRegistration(componentType).NetID;
|
||||
|
||||
if (!netId.HasValue)
|
||||
throw new ArgumentException($"Component {component.Name} does not have a NetID.", nameof(component));
|
||||
throw new ArgumentException($"Component {componentType} does not have a NetID.", nameof(component));
|
||||
|
||||
var msg = _networkManager.CreateNetMessage<MsgEntity>();
|
||||
msg.Type = EntityMessageType.ComponentMessage;
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
// TODO: Give this component a friend someday. Way too much content shit to change atm ._.
|
||||
|
||||
public override string Name => "AnimationPlayer";
|
||||
|
||||
public int PlayingAnimationCount => PlayingAnimations.Count;
|
||||
|
||||
internal readonly Dictionary<string, AnimationPlayback> PlayingAnimations
|
||||
|
||||
@@ -14,9 +14,6 @@ namespace Robust.Client.GameObjects
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Eye";
|
||||
|
||||
[ViewVariables]
|
||||
private Eye? _eye = default!;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -14,7 +14,6 @@ namespace Robust.Client.GameObjects
|
||||
[RegisterComponent]
|
||||
public class IconComponent : Component, ISerializationHooks
|
||||
{
|
||||
public override string Name => "Icon";
|
||||
public IDirectionalTextureProvider? Icon { get; private set; }
|
||||
|
||||
[DataField("sprite")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -10,9 +10,6 @@ namespace Robust.Client.GameObjects
|
||||
/// </summary>
|
||||
public class InputComponent : Component
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Input";
|
||||
|
||||
/// <summary>
|
||||
/// The context that will be made active for a client that attaches to this entity.
|
||||
/// </summary>
|
||||
|
||||
@@ -96,26 +96,6 @@ namespace Robust.Client.GameObjects
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public Texture? Mask { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[Animatable]
|
||||
public float Energy
|
||||
{
|
||||
get => _energy;
|
||||
set => _energy = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Soft shadow strength multiplier.
|
||||
/// Has no effect if soft shadows are not enabled.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[Animatable]
|
||||
public float Softness
|
||||
{
|
||||
get => _softness;
|
||||
set => _softness = value;
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool VisibleNested
|
||||
{
|
||||
@@ -134,10 +114,7 @@ namespace Robust.Client.GameObjects
|
||||
[DataField("autoRot")]
|
||||
private bool _maskAutoRotate;
|
||||
private Angle _rotation;
|
||||
[DataField("energy")]
|
||||
private float _energy = 1f;
|
||||
[DataField("softness")]
|
||||
private float _softness = 1f;
|
||||
|
||||
[DataField("mask")]
|
||||
internal string? _maskPath;
|
||||
|
||||
|
||||
@@ -1257,7 +1257,10 @@ namespace Robust.Client.GameObjects
|
||||
if (worldRotation.Theta < 0)
|
||||
worldRotation = new Angle(worldRotation.Theta + Math.Tau);
|
||||
|
||||
var spriteMatrix = GetLocalMatrix();
|
||||
// sprite matrix, WITHOUT offset.
|
||||
// offset is applied after sprite numDirs snapping/rotation correction
|
||||
// --> apply at same time as layer offset
|
||||
var spriteMatrix = Matrix3.CreateTransform(Vector2.Zero, rotation, scale);
|
||||
|
||||
foreach (var layer in Layers)
|
||||
{
|
||||
@@ -1268,7 +1271,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
var numDirs = GetLayerDirectionCount(layer);
|
||||
var layerRotation = worldRotation + layer.Rotation;
|
||||
var layerPosition = worldPosition + layerRotation.RotateVec(layer._offset);
|
||||
var layerPosition = worldPosition + layerRotation.RotateVec(layer._offset + offset);
|
||||
|
||||
CalcModelMatrix(numDirs, eyeRotation, layerRotation, layerPosition, out var modelMatrix);
|
||||
Matrix3.Multiply(ref spriteMatrix, ref modelMatrix, out var transformMatrix);
|
||||
@@ -1474,30 +1477,6 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
private RSI.State.Direction GetDir(RSI.State.DirectionType rsiDirectionType, Angle worldRotation)
|
||||
{
|
||||
var dir = rsiDirectionType switch
|
||||
{
|
||||
RSI.State.DirectionType.Dir1 => Direction.South,
|
||||
RSI.State.DirectionType.Dir4 => worldRotation.GetCardinalDir(),
|
||||
RSI.State.DirectionType.Dir8 => worldRotation.GetDir(),
|
||||
_ => throw new ArgumentException($"Unknown RSI DirectionType: {rsiDirectionType}.", nameof(rsiDirectionType))
|
||||
};
|
||||
|
||||
return dir switch
|
||||
{
|
||||
Direction.North => RSI.State.Direction.North,
|
||||
Direction.South => RSI.State.Direction.South,
|
||||
Direction.East => RSI.State.Direction.East,
|
||||
Direction.West => RSI.State.Direction.West,
|
||||
Direction.SouthEast => RSI.State.Direction.SouthEast,
|
||||
Direction.SouthWest => RSI.State.Direction.SouthWest,
|
||||
Direction.NorthEast => RSI.State.Direction.NorthEast,
|
||||
Direction.NorthWest => RSI.State.Direction.NorthWest,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(dir), dir, null)
|
||||
};
|
||||
}
|
||||
|
||||
private void QueueUpdateIsInert()
|
||||
{
|
||||
// Look this was an easy way to get bounds checks for layer updates.
|
||||
@@ -1547,58 +1526,13 @@ namespace Robust.Client.GameObjects
|
||||
return rsi["error"];
|
||||
}
|
||||
|
||||
private static RSI.State.Direction OffsetRsiDir(RSI.State.Direction dir, DirectionOffset offset)
|
||||
{
|
||||
// There is probably a better way to do this.
|
||||
// Eh.
|
||||
switch (offset)
|
||||
{
|
||||
case DirectionOffset.None:
|
||||
return dir;
|
||||
case DirectionOffset.Clockwise:
|
||||
return dir switch
|
||||
{
|
||||
RSI.State.Direction.North => RSI.State.Direction.East,
|
||||
RSI.State.Direction.East => RSI.State.Direction.South,
|
||||
RSI.State.Direction.South => RSI.State.Direction.West,
|
||||
RSI.State.Direction.West => RSI.State.Direction.North,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
case DirectionOffset.CounterClockwise:
|
||||
return dir switch
|
||||
{
|
||||
RSI.State.Direction.North => RSI.State.Direction.West,
|
||||
RSI.State.Direction.East => RSI.State.Direction.North,
|
||||
RSI.State.Direction.South => RSI.State.Direction.East,
|
||||
RSI.State.Direction.West => RSI.State.Direction.South,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
case DirectionOffset.Flip:
|
||||
switch (dir)
|
||||
{
|
||||
case RSI.State.Direction.North:
|
||||
return RSI.State.Direction.South;
|
||||
case RSI.State.Direction.East:
|
||||
return RSI.State.Direction.West;
|
||||
case RSI.State.Direction.South:
|
||||
return RSI.State.Direction.North;
|
||||
case RSI.State.Direction.West:
|
||||
return RSI.State.Direction.East;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDebugString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendFormat(
|
||||
"vis/depth/scl/rot/ofs/col/norot/override/dir: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{8}/{7}\n",
|
||||
Visible, DrawDepth, Scale, Rotation, Offset,
|
||||
Color, NoRotation, GetDir(RSI.State.DirectionType.Dir8, entities.GetComponent<TransformComponent>(Owner).WorldRotation),
|
||||
Color, NoRotation, entities.GetComponent<TransformComponent>(Owner).WorldRotation.ToRsiDirection(RSI.State.DirectionType.Dir8),
|
||||
DirectionOverride
|
||||
);
|
||||
|
||||
@@ -1839,10 +1773,10 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = _parent.GetDir(state.Directions, worldRotation);
|
||||
dir = worldRotation.ToRsiDirection(state.Directions);
|
||||
}
|
||||
|
||||
return OffsetRsiDir(dir, DirOffset);
|
||||
return dir.OffsetRsiDir(DirOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2073,6 +2007,7 @@ namespace Robust.Client.GameObjects
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var dummy = entityManager.SpawnEntity(prototype.ID, MapCoordinates.Nullspace);
|
||||
var spriteComponent = entityManager.EnsureComponent<SpriteComponent>(dummy);
|
||||
EntitySystem.Get<AppearanceSystem>().OnChangeData(dummy);
|
||||
|
||||
var anyTexture = false;
|
||||
foreach (var layer in spriteComponent.AllLayers)
|
||||
|
||||
@@ -6,8 +6,6 @@ namespace Robust.Client.GameObjects
|
||||
[RegisterComponent]
|
||||
public sealed class RenderingTreeComponent : Component
|
||||
{
|
||||
public override string Name => "RenderingTree";
|
||||
|
||||
internal DynamicTree<SpriteComponent> SpriteTree { get; set; } = default!;
|
||||
internal DynamicTree<PointLightComponent> LightTree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -19,15 +19,21 @@ namespace Robust.Client.GameObjects
|
||||
while (_queuedUpdates.TryDequeue(out var appearance))
|
||||
{
|
||||
if (appearance.Deleted)
|
||||
return;
|
||||
|
||||
foreach (var visualizer in appearance.Visualizers)
|
||||
{
|
||||
visualizer.OnChangeData(appearance);
|
||||
}
|
||||
continue;
|
||||
|
||||
OnChangeData(appearance.Owner, appearance);
|
||||
appearance.UnmarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnChangeData(EntityUid uid, ClientAppearanceComponent? appearanceComponent = null)
|
||||
{
|
||||
if (!Resolve(uid, ref appearanceComponent, false)) return;
|
||||
|
||||
foreach (var visualizer in appearanceComponent.Visualizers)
|
||||
{
|
||||
visualizer.OnChangeData(appearanceComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,9 +253,15 @@ namespace Robust.Client.GameObjects
|
||||
/// </summary>
|
||||
/// <param name="stream">The audio stream to play.</param>
|
||||
/// <param name="audioParams"></param>
|
||||
private IPlayingAudioStream Play(AudioStream stream, AudioParams? audioParams = null)
|
||||
private IPlayingAudioStream? Play(AudioStream stream, AudioParams? audioParams = null)
|
||||
{
|
||||
var source = _clyde.CreateAudioSource(stream);
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ApplyAudioParams(audioParams, source);
|
||||
|
||||
source.SetGlobal();
|
||||
@@ -303,6 +309,12 @@ namespace Robust.Client.GameObjects
|
||||
AudioParams? audioParams = null)
|
||||
{
|
||||
var source = _clyde.CreateAudioSource(stream);
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!source.SetPosition(EntityManager.GetComponent<TransformComponent>(entity).WorldPosition))
|
||||
{
|
||||
return Play(stream, fallbackCoordinates, fallbackCoordinates, audioParams);
|
||||
@@ -356,6 +368,12 @@ namespace Robust.Client.GameObjects
|
||||
EntityCoordinates fallbackCoordinates, AudioParams? audioParams = null)
|
||||
{
|
||||
var source = _clyde.CreateAudioSource(stream);
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!source.SetPosition(fallbackCoordinates.Position))
|
||||
{
|
||||
source.Dispose();
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Robust.Client.GameObjects
|
||||
var sender = ev.Sender;
|
||||
if (EntityManager.EntityExists(sender) &&
|
||||
EntityManager.TryGetComponent(sender, out ClientOccluderComponent? iconSmooth)
|
||||
&& iconSmooth.Running)
|
||||
&& iconSmooth.Initialized)
|
||||
{
|
||||
var grid1 = _mapManager.GetGrid(EntityManager.GetComponent<TransformComponent>(sender).GridID);
|
||||
var coords = EntityManager.GetComponent<TransformComponent>(sender).Coordinates;
|
||||
@@ -85,7 +85,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
// Entity is no longer valid, update around the last position it was at.
|
||||
if (ev.LastPosition.HasValue && _mapManager.TryGetGrid(ev.LastPosition.Value.grid, out var grid))
|
||||
else if (ev.LastPosition.HasValue && _mapManager.TryGetGrid(ev.LastPosition.Value.grid, out var grid))
|
||||
{
|
||||
var pos = ev.LastPosition.Value.pos;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (!cast.ContainerSet.Any(data => data.Id == id))
|
||||
{
|
||||
container.EmptyContainer(true);
|
||||
container.EmptyContainer(true, entMan: EntityManager);
|
||||
container.Shutdown();
|
||||
toDelete ??= new List<string>();
|
||||
toDelete.Add(id);
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
#if DEBUG
|
||||
using System;
|
||||
using System.Text;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
internal sealed class DebugGridTileLookupSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
if (_enabled == value) return;
|
||||
_enabled = value;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
_label.Visible = true;
|
||||
LastTile = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
_label.Text = null;
|
||||
_label.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enabled;
|
||||
|
||||
private (GridId Grid, Vector2i Indices) LastTile;
|
||||
|
||||
// Label and shit that follows cursor
|
||||
private Label _label = new()
|
||||
{
|
||||
Visible = false,
|
||||
};
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<SendGridTileLookupMessage>(HandleSentEntities);
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.AddChild(_label);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.RemoveChild(_label);
|
||||
}
|
||||
|
||||
private void RequestEntities(GridId gridId, Vector2i indices)
|
||||
{
|
||||
if (gridId == GridId.Invalid) return;
|
||||
RaiseNetworkEvent(new RequestGridTileLookupMessage(gridId, indices));
|
||||
}
|
||||
|
||||
private void HandleSentEntities(SendGridTileLookupMessage message)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
var text = new StringBuilder();
|
||||
text.AppendLine($"GridId: {LastTile.Grid}, Tile: {LastTile.Indices}");
|
||||
|
||||
for (var i = 0; i < message.Entities.Count; i++)
|
||||
{
|
||||
var entity = message.Entities[i];
|
||||
|
||||
if (!EntityManager.EntityExists(entity)) continue;
|
||||
|
||||
text.AppendLine((string) EntityManager.ToPrettyString(entity));
|
||||
}
|
||||
|
||||
_label.Text = text.ToString();
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
if (!Enabled) return;
|
||||
|
||||
var mousePos = _inputManager.MouseScreenPosition;
|
||||
var worldPos = _eyeManager.ScreenToMap(mousePos);
|
||||
|
||||
GridId gridId;
|
||||
Vector2i tile;
|
||||
|
||||
if (_mapManager.TryFindGridAt(worldPos, out var grid))
|
||||
{
|
||||
gridId = grid.Index;
|
||||
tile = grid.WorldToTile(worldPos.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
gridId = GridId.Invalid;
|
||||
tile = new Vector2i((int) MathF.Floor(worldPos.Position.X), (int) MathF.Floor(worldPos.Position.Y));
|
||||
}
|
||||
|
||||
LayoutContainer.SetPosition(_label, mousePos.Position);
|
||||
|
||||
if ((gridId, tile).Equals(LastTile)) return;
|
||||
|
||||
_label.Text = null;
|
||||
LastTile = (gridId, tile);
|
||||
RequestEntities(gridId, tile);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RequestTileEntities : IConsoleCommand
|
||||
{
|
||||
public string Command => "tilelookup";
|
||||
public string Description => "Used for debugging GridTileLookupSystem";
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<DebugGridTileLookupSystem>().Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -347,11 +347,17 @@ namespace Robust.Client.GameObjects
|
||||
if (_playerManager.LocalPlayer?.ControlledEntity is not {} playerEnt)
|
||||
return;
|
||||
|
||||
var playerXform = _entityManager.GetComponent<TransformComponent>(playerEnt);
|
||||
|
||||
foreach (var effect in _owner._Effects)
|
||||
{
|
||||
if(effect.AttachedEntityUid is {} attached
|
||||
&& _entityManager.GetComponent<TransformComponent>(attached).MapID != _entityManager.GetComponent<TransformComponent>(playerEnt).MapID
|
||||
&& effect.Coordinates.GetMapId(_entityManager) != map)
|
||||
TransformComponent? attachedXform = null;
|
||||
|
||||
if ((effect.AttachedEntityUid is {} attached &&
|
||||
_entityManager.TryGetComponent(attached, out attachedXform) &&
|
||||
attachedXform.MapID != playerXform.MapID) ||
|
||||
(effect.AttachedEntityUid == null &&
|
||||
effect.Coordinates.GetMapId(_entityManager) != map))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -367,16 +373,17 @@ namespace Robust.Client.GameObjects
|
||||
// TODO: Should be doing matrix transformations
|
||||
var effectSprite = effect.EffectSprite;
|
||||
|
||||
var tempQualifier1 = effect.AttachedEntityUid;
|
||||
var coordinates =
|
||||
(tempQualifier1 != null ? _entityManager.GetComponent<TransformComponent>(tempQualifier1.Value).Coordinates : effect.Coordinates)
|
||||
(attachedXform?.Coordinates ?? effect.Coordinates)
|
||||
.Offset(effect.AttachedOffset);
|
||||
|
||||
var rotation = _entityManager.GetComponent<TransformComponent>(coordinates.EntityId).WorldRotation;
|
||||
// ???
|
||||
var rotation = attachedXform?.WorldRotation ?? _entityManager.GetComponent<TransformComponent>(coordinates.EntityId).WorldRotation;
|
||||
|
||||
var effectOrigin = coordinates.ToMapPos(_entityManager);
|
||||
|
||||
var effectArea = Box2.CenteredAround(effectOrigin, effect.Size);
|
||||
var rotatedBox = new Box2Rotated(effectArea, effect.Rotation - rotation, effectOrigin);
|
||||
var rotatedBox = new Box2Rotated(effectArea, effect.Rotation + rotation, effectOrigin);
|
||||
|
||||
worldHandle.DrawTextureRect(effectSprite, rotatedBox, ToColor(effect.Color));
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
#nullable enable
|
||||
|
||||
@@ -18,26 +20,8 @@ namespace Robust.Client.GameObjects
|
||||
/// Updates the position of every Eye every frame, so that the camera follows the player around.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
internal class EyeUpdateSystem : EntitySystem
|
||||
public class EyeUpdateSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
|
||||
private TransformComponent? _lastParent;
|
||||
private TransformComponent? _lerpTo;
|
||||
private Angle LerpStartRotation;
|
||||
private float _accumulator;
|
||||
|
||||
public bool IsLerping { get => _lerpTo != null; }
|
||||
|
||||
// How fast the camera rotates in radians / s
|
||||
private const float CameraRotateSpeed = MathF.PI;
|
||||
// PER THIS AMOUNT OF TIME MILLISECONDS
|
||||
private const float CameraRotateTimeUnit = 1.2f;
|
||||
// Safety override
|
||||
private const float _lerpTimeMax = CameraRotateTimeUnit + 0.4f;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -65,77 +49,6 @@ namespace Robust.Client.GameObjects
|
||||
/// <inheritdoc />
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
var currentEye = _eyeManager.CurrentEye;
|
||||
|
||||
// TODO: Content should have its own way of handling this. We should have a default behavior that they can overwrite.
|
||||
|
||||
EntityUid tempQualifier = _playerManager.LocalPlayer?.ControlledEntity ?? EntityUid.Invalid;
|
||||
var playerTransform = (tempQualifier != EntityUid.Invalid ? EntityManager.GetComponent<TransformComponent>(tempQualifier) : null);
|
||||
|
||||
if (playerTransform == null) return;
|
||||
|
||||
var gridId = playerTransform.GridID;
|
||||
|
||||
TransformComponent parent;
|
||||
if (gridId != GridId.Invalid &&
|
||||
_mapManager.GetGrid(gridId).GridEntityId is var gridEnt &&
|
||||
EntityManager.EntityExists(gridEnt))
|
||||
parent = EntityManager.GetComponent<TransformComponent>(gridEnt);
|
||||
else
|
||||
{
|
||||
parent = EntityManager.GetComponent<TransformComponent>(
|
||||
_mapManager.GetMapEntityId(playerTransform.MapID));
|
||||
}
|
||||
|
||||
// Make sure that we don't fire the vomit carousel when we spawn in
|
||||
if (_lastParent is null)
|
||||
_lastParent = parent;
|
||||
|
||||
// Set a default for target rotation
|
||||
var parentRotation = -parent.WorldRotation;
|
||||
// Reuse current rotation when stepping into space
|
||||
if (parent.GridID == GridId.Invalid)
|
||||
parentRotation = currentEye.Rotation;
|
||||
|
||||
// Handle grid change in general
|
||||
if (_lastParent != parent)
|
||||
_lerpTo = parent;
|
||||
|
||||
// And we are up and running!
|
||||
if (_lerpTo is not null)
|
||||
{
|
||||
// Handle a case where we have beeing spinning around, but suddenly got off onto a different grid
|
||||
if (parent != _lerpTo) {
|
||||
LerpStartRotation = currentEye.Rotation;
|
||||
_lerpTo = parent;
|
||||
_accumulator = 0f;
|
||||
}
|
||||
|
||||
_accumulator += frameTime;
|
||||
|
||||
var changeNeeded = (float) (LerpStartRotation - parentRotation).Theta;
|
||||
|
||||
var changeLerp = _accumulator / (Math.Abs(changeNeeded % MathF.PI) / CameraRotateSpeed * CameraRotateTimeUnit);
|
||||
|
||||
currentEye.Rotation = Angle.Lerp(LerpStartRotation, parentRotation, changeLerp);
|
||||
|
||||
// Either we have overshot, or we have taken way too long on this, emergency reset time
|
||||
if (changeLerp > 1.0f || _accumulator >= _lerpTimeMax)
|
||||
{
|
||||
_lastParent = parent;
|
||||
_lerpTo = null;
|
||||
_accumulator = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
// We are just fine, or we finished a lerp (and probably overshot)
|
||||
if (_lerpTo is null)
|
||||
{
|
||||
currentEye.Rotation = parentRotation;
|
||||
LerpStartRotation = parentRotation;
|
||||
}
|
||||
|
||||
|
||||
foreach (var eyeComponent in EntityManager.EntityQuery<EyeComponent>(true))
|
||||
{
|
||||
eyeComponent.UpdateEyePosition();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -13,6 +12,10 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class GridChunkBoundsDebugSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||
|
||||
private GridChunkBoundsOverlay? _overlay;
|
||||
|
||||
public bool Enabled
|
||||
@@ -29,14 +32,14 @@ namespace Robust.Client.GameObjects
|
||||
DebugTools.Assert(_overlay == null);
|
||||
_overlay = new GridChunkBoundsOverlay(
|
||||
EntityManager,
|
||||
IoCManager.Resolve<IEyeManager>(),
|
||||
IoCManager.Resolve<IMapManager>());
|
||||
_eyeManager,
|
||||
_mapManager);
|
||||
|
||||
IoCManager.Resolve<IOverlayManager>().AddOverlay(_overlay);
|
||||
_overlayManager.AddOverlay(_overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(_overlay!);
|
||||
_overlayManager.RemoveOverlay(_overlay!);
|
||||
_overlay = null;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +66,7 @@ namespace Robust.Client.GameObjects
|
||||
protected internal override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
var currentMap = _eyeManager.CurrentMap;
|
||||
var viewport = _eyeManager.GetWorldViewport();
|
||||
var viewport = args.WorldBounds;
|
||||
var worldHandle = args.WorldHandle;
|
||||
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(currentMap, viewport))
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -62,6 +64,9 @@ namespace Robust.Client.GameObjects
|
||||
// handle local binds before sending off
|
||||
foreach (var handler in BindRegistry.GetHandlers(function))
|
||||
{
|
||||
if (!_stateManager.IsPredictionEnabled && !handler.FireOutsidePrediction)
|
||||
continue;
|
||||
|
||||
// local handlers can block sending over the network.
|
||||
if (handler.HandleCmdMessage(session, message))
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Robust.Client.GameObjects
|
||||
public sealed class PointLightSystem : SharedPointLightSystem
|
||||
{
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly RenderingTreeSystem _renderingTreeSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -19,16 +20,14 @@ namespace Robust.Client.GameObjects
|
||||
private void HandleInit(EntityUid uid, PointLightComponent component, ComponentInit args)
|
||||
{
|
||||
UpdateMask(component);
|
||||
RaiseLocalEvent(uid, new PointLightUpdateEvent());
|
||||
}
|
||||
|
||||
private void HandleRemove(EntityUid uid, PointLightComponent component, ComponentRemove args)
|
||||
{
|
||||
var map = EntityManager.GetComponent<TransformComponent>(uid).MapID;
|
||||
// TODO: Just make this update the tree directly and not allocate
|
||||
if (map != MapId.Nullspace)
|
||||
if (Transform(uid).MapID != MapId.Nullspace)
|
||||
{
|
||||
EntityManager.EventBus.RaiseEvent(EventSource.Local,
|
||||
new RenderTreeRemoveLightEvent(component, map));
|
||||
_renderingTreeSystem.ClearLight(component);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ namespace Robust.Client.GameObjects
|
||||
SubscribeLocalEvent<PointLightComponent, EntMapIdChangedMessage>(LightMapChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, EntParentChangedMessage>(LightParentChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, PointLightRadiusChangedEvent>(PointLightRadiusChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, RenderTreeRemoveLightEvent>(RemoveLight);
|
||||
SubscribeLocalEvent<PointLightComponent, PointLightUpdateEvent>(HandleLightUpdate);
|
||||
|
||||
SubscribeLocalEvent<RenderingTreeComponent, ComponentInit>(OnTreeInit);
|
||||
@@ -114,28 +113,31 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
private void AnythingMoved(ref MoveEvent args)
|
||||
{
|
||||
AnythingMovedSubHandler(EntityManager.GetComponent<TransformComponent>(args.Sender));
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
AnythingMovedSubHandler(args.Sender, xforms);
|
||||
}
|
||||
|
||||
private void AnythingMovedSubHandler(TransformComponent sender)
|
||||
private void AnythingMovedSubHandler(EntityUid uid, EntityQuery<TransformComponent> xforms)
|
||||
{
|
||||
// To avoid doing redundant updates (and we don't need to update a grid's children ever)
|
||||
if (!_checkedChildren.Add(sender.Owner) ||
|
||||
EntityManager.HasComponent<RenderingTreeComponent>(sender.Owner)) return;
|
||||
if (!_checkedChildren.Add(uid) || EntityManager.HasComponent<RenderingTreeComponent>(uid)) return;
|
||||
|
||||
// This recursive search is needed, as MoveEvent is defined to not care about indirect events like children.
|
||||
// WHATEVER YOU DO, DON'T REPLACE THIS WITH SPAMMING EVENTS UNLESS YOU HAVE A GUARANTEE IT WON'T LAG THE GC.
|
||||
// (Struct-based events ok though)
|
||||
// Ironically this was lagging the GC lolz
|
||||
if (EntityManager.TryGetComponent(sender.Owner, out SpriteComponent? sprite))
|
||||
if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite))
|
||||
QueueSpriteUpdate(sprite);
|
||||
|
||||
if (EntityManager.TryGetComponent(sender.Owner, out PointLightComponent? light))
|
||||
if (EntityManager.TryGetComponent(uid, out PointLightComponent? light))
|
||||
QueueLightUpdate(light);
|
||||
|
||||
foreach (TransformComponent child in sender.Children)
|
||||
if (!xforms.TryGetComponent(uid, out var xform)) return;
|
||||
|
||||
foreach (var child in xform.ChildEntities)
|
||||
{
|
||||
AnythingMovedSubHandler(child);
|
||||
AnythingMovedSubHandler(child, xforms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,12 +195,7 @@ namespace Robust.Client.GameObjects
|
||||
QueueLightUpdate(component);
|
||||
}
|
||||
|
||||
private void RemoveLight(EntityUid uid, PointLightComponent component, RenderTreeRemoveLightEvent args)
|
||||
{
|
||||
ClearLight(component);
|
||||
}
|
||||
|
||||
private void ClearLight(PointLightComponent component)
|
||||
public void ClearLight(PointLightComponent component)
|
||||
{
|
||||
if (component.RenderTree == null) return;
|
||||
|
||||
@@ -253,23 +250,21 @@ namespace Robust.Client.GameObjects
|
||||
EntityManager.EnsureComponent<RenderingTreeComponent>(_mapManager.GetGrid(gridId).GridEntityId);
|
||||
}
|
||||
|
||||
// TODO: Pass in TransformComponent directly: mainly interested in getting this shit working atm.
|
||||
private RenderingTreeComponent? GetRenderTree(EntityUid entity)
|
||||
private RenderingTreeComponent? GetRenderTree(EntityUid entity, EntityQuery<TransformComponent> xforms)
|
||||
{
|
||||
var lookups = EntityManager.GetEntityQuery<RenderingTreeComponent>();
|
||||
|
||||
if (!EntityManager.EntityExists(entity) ||
|
||||
!EntityManager.TryGetComponent(entity, out TransformComponent? xform) ||
|
||||
!xforms.TryGetComponent(entity, out var xform) ||
|
||||
xform.MapID == MapId.Nullspace ||
|
||||
EntityManager.HasComponent<RenderingTreeComponent>(entity)) return null;
|
||||
lookups.HasComponent(entity)) return null;
|
||||
|
||||
var parent = xform.ParentUid;
|
||||
|
||||
while (true)
|
||||
while (parent.IsValid())
|
||||
{
|
||||
if (!parent.IsValid())
|
||||
break;
|
||||
|
||||
if (EntityManager.TryGetComponent(parent, out RenderingTreeComponent? comp)) return comp;
|
||||
parent = EntityManager.GetComponent<TransformComponent>(parent).ParentUid;
|
||||
if (lookups.TryGetComponent(parent, out var comp)) return comp;
|
||||
parent = xforms.GetComponent(parent).ParentUid;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -284,6 +279,8 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
_checkedChildren.Clear();
|
||||
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var sprite in _spriteQueue)
|
||||
{
|
||||
sprite.TreeUpdateQueued = false;
|
||||
@@ -294,9 +291,9 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var oldMapTree = sprite.RenderTree;
|
||||
var newMapTree = GetRenderTree(sprite.Owner);
|
||||
var newMapTree = GetRenderTree(sprite.Owner, xforms);
|
||||
// TODO: Temp PVS guard
|
||||
var xform = EntityManager.GetComponent<TransformComponent>(sprite.Owner);
|
||||
var xform = xforms.GetComponent(sprite.Owner);
|
||||
var (worldPos, worldRot) = xform.GetWorldPositionRotation();
|
||||
|
||||
if (float.IsNaN(worldPos.X) || float.IsNaN(worldPos.Y))
|
||||
@@ -305,7 +302,7 @@ namespace Robust.Client.GameObjects
|
||||
continue;
|
||||
}
|
||||
|
||||
var aabb = SpriteAabbFunc(sprite, worldPos, worldRot);
|
||||
var aabb = SpriteAabbFunc(sprite, worldPos, worldRot, xforms);
|
||||
|
||||
// If we're on a new map then clear the old one.
|
||||
if (oldMapTree != newMapTree)
|
||||
@@ -332,9 +329,9 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var oldMapTree = light.RenderTree;
|
||||
var newMapTree = GetRenderTree(light.Owner);
|
||||
var newMapTree = GetRenderTree(light.Owner, xforms);
|
||||
// TODO: Temp PVS guard
|
||||
var worldPos = EntityManager.GetComponent<TransformComponent>(light.Owner).WorldPosition;
|
||||
var worldPos = xforms.GetComponent(light.Owner).WorldPosition;
|
||||
|
||||
if (float.IsNaN(worldPos.X) || float.IsNaN(worldPos.Y))
|
||||
{
|
||||
@@ -349,7 +346,7 @@ namespace Robust.Client.GameObjects
|
||||
Logger.WarningS(LoggerSawmill, $"Light radius for {light.Owner} set above max radius of {MaxLightRadius}. This may lead to pop-in.");
|
||||
}
|
||||
|
||||
var aabb = LightAabbFunc(light, worldPos);
|
||||
var aabb = LightAabbFunc(light, worldPos, xforms);
|
||||
|
||||
// If we're on a new map then clear the old one.
|
||||
if (oldMapTree != newMapTree)
|
||||
@@ -371,82 +368,44 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
private Box2 SpriteAabbFunc(in SpriteComponent value)
|
||||
{
|
||||
var xform = EntityManager.GetComponent<TransformComponent>(value.Owner);
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
var xform = xforms.GetComponent(value.Owner);
|
||||
var (worldPos, worldRot) = xform.GetWorldPositionRotation();
|
||||
var bounds = new Box2Rotated(value.CalculateBoundingBox(worldPos), worldRot, worldPos);
|
||||
var tree = GetRenderTree(value.Owner);
|
||||
var tree = GetRenderTree(value.Owner, xforms);
|
||||
|
||||
if (tree == null)
|
||||
{
|
||||
return bounds.CalcBoundingBox();
|
||||
}
|
||||
else
|
||||
{
|
||||
return EntityManager.GetComponent<TransformComponent>(tree.Owner).InvWorldMatrix.TransformBox(bounds);
|
||||
}
|
||||
return tree == null ? bounds.CalcBoundingBox() : xforms.GetComponent(tree.Owner).InvWorldMatrix.TransformBox(bounds);
|
||||
}
|
||||
|
||||
private Box2 LightAabbFunc(in PointLightComponent value)
|
||||
{
|
||||
var worldPos = EntityManager.GetComponent<TransformComponent>(value.Owner).WorldPosition;
|
||||
var tree = GetRenderTree(value.Owner);
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
var worldPos = xforms.GetComponent(value.Owner).WorldPosition;
|
||||
var tree = GetRenderTree(value.Owner, xforms);
|
||||
var boxSize = value.Radius * 2;
|
||||
|
||||
Vector2 localPos;
|
||||
if (tree == null)
|
||||
{
|
||||
localPos = worldPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Need a way to just cache this InvWorldMatrix
|
||||
localPos = EntityManager.GetComponent<TransformComponent>(tree.Owner).InvWorldMatrix.Transform(worldPos);
|
||||
}
|
||||
var localPos = tree == null ? worldPos : xforms.GetComponent(tree.Owner).InvWorldMatrix.Transform(worldPos);
|
||||
return Box2.CenteredAround(localPos, (boxSize, boxSize));
|
||||
}
|
||||
|
||||
private Box2 SpriteAabbFunc(SpriteComponent value, Vector2 worldPos, Angle worldRot)
|
||||
private Box2 SpriteAabbFunc(SpriteComponent value, Vector2 worldPos, Angle worldRot, EntityQuery<TransformComponent> xforms)
|
||||
{
|
||||
var bounds = new Box2Rotated(value.CalculateBoundingBox(worldPos), worldRot, worldPos);
|
||||
var tree = GetRenderTree(value.Owner);
|
||||
var tree = GetRenderTree(value.Owner, xforms);
|
||||
|
||||
if (tree == null)
|
||||
{
|
||||
return bounds.CalcBoundingBox();
|
||||
}
|
||||
else
|
||||
{
|
||||
return EntityManager.GetComponent<TransformComponent>(tree.Owner).InvWorldMatrix.TransformBox(bounds);
|
||||
}
|
||||
return tree == null ? bounds.CalcBoundingBox() : xforms.GetComponent(tree.Owner).InvWorldMatrix.TransformBox(bounds);
|
||||
}
|
||||
|
||||
private Box2 LightAabbFunc(PointLightComponent value, Vector2 worldPos)
|
||||
private Box2 LightAabbFunc(PointLightComponent value, Vector2 worldPos, EntityQuery<TransformComponent> xforms)
|
||||
{
|
||||
// Lights are circles so don't need entity's rotation
|
||||
var tree = GetRenderTree(value.Owner);
|
||||
var tree = GetRenderTree(value.Owner, xforms);
|
||||
var boxSize = value.Radius * 2;
|
||||
|
||||
Vector2 localPos;
|
||||
if (tree == null)
|
||||
{
|
||||
localPos = worldPos;
|
||||
} else
|
||||
{
|
||||
localPos = EntityManager.GetComponent<TransformComponent>(tree.Owner).InvWorldMatrix.Transform(worldPos);
|
||||
}
|
||||
var localPos = tree == null ? worldPos : xforms.GetComponent(tree.Owner).InvWorldMatrix.Transform(worldPos);
|
||||
return Box2.CenteredAround(localPos, (boxSize, boxSize));
|
||||
}
|
||||
}
|
||||
|
||||
internal class RenderTreeRemoveLightEvent : EntityEventArgs
|
||||
{
|
||||
public RenderTreeRemoveLightEvent(PointLightComponent light, MapId map)
|
||||
{
|
||||
Light = light;
|
||||
Map = map;
|
||||
}
|
||||
|
||||
public PointLightComponent Light { get; }
|
||||
public MapId Map { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,11 @@ namespace Robust.Client.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var comp in _treeSystem.GetRenderTrees(currentMap, pvsBounds))
|
||||
{
|
||||
var bounds = EntityManager.GetComponent<TransformComponent>(comp.Owner).InvWorldMatrix.TransformBox(pvsBounds);
|
||||
var bounds = xforms.GetComponent(comp.Owner).InvWorldMatrix.TransformBox(pvsBounds);
|
||||
|
||||
comp.SpriteTree.QueryAabb(ref frameTime, (ref float state, in SpriteComponent value) =>
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Robust.Client.GameObjects
|
||||
/// Handles interpolation of transform positions.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
internal sealed class TransformSystem : SharedTransformSystem
|
||||
public sealed class TransformSystem : SharedTransformSystem
|
||||
{
|
||||
// Max distance per tick how far an entity can move before it is considered teleporting.
|
||||
// TODO: Make these values somehow dependent on server TPS.
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.Timing;
|
||||
using Robust.Shared;
|
||||
@@ -50,7 +49,7 @@ namespace Robust.Client.GameStates
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
[Dependency] private readonly IClientNetManager _network = default!;
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly IClientMapManager _mapManager = default!;
|
||||
[Dependency] private readonly INetworkedMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IClientGameTiming _timing = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
@@ -60,6 +59,8 @@ namespace Robust.Client.GameStates
|
||||
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
|
||||
#endif
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int MinBufferSize => _processor.MinBufferSize;
|
||||
|
||||
@@ -69,7 +70,7 @@ namespace Robust.Client.GameStates
|
||||
/// <inheritdoc />
|
||||
public int CurrentBufferSize => _processor.CalculateBufferSize(CurServerTick);
|
||||
|
||||
public bool Predicting { get; private set; }
|
||||
public bool IsPredictionEnabled { get; private set; }
|
||||
|
||||
public int PredictTickBias { get; private set; }
|
||||
public float PredictLagBias { get; private set; }
|
||||
@@ -87,6 +88,7 @@ namespace Robust.Client.GameStates
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_sawmill = Logger.GetSawmill(CVars.NetPredict.Name);
|
||||
_processor = new GameStateProcessor(_timing);
|
||||
|
||||
_network.RegisterNetMessage<MsgState>(HandleStateMessage);
|
||||
@@ -96,7 +98,7 @@ namespace Robust.Client.GameStates
|
||||
_config.OnValueChanged(CVars.NetInterp, b => _processor.Interpolation = b, true);
|
||||
_config.OnValueChanged(CVars.NetInterpRatio, i => _processor.InterpRatio = i, true);
|
||||
_config.OnValueChanged(CVars.NetLogging, b => _processor.Logging = b, true);
|
||||
_config.OnValueChanged(CVars.NetPredict, b => Predicting = b, true);
|
||||
_config.OnValueChanged(CVars.NetPredict, b => IsPredictionEnabled = b, true);
|
||||
_config.OnValueChanged(CVars.NetPredictTickBias, i => PredictTickBias = i, true);
|
||||
_config.OnValueChanged(CVars.NetPredictLagBias, i => PredictLagBias = i, true);
|
||||
_config.OnValueChanged(CVars.NetStateBufMergeThreshold, i => StateBufferMergeThreshold = i, true);
|
||||
@@ -104,7 +106,7 @@ namespace Robust.Client.GameStates
|
||||
_processor.Interpolation = _config.GetCVar(CVars.NetInterp);
|
||||
_processor.InterpRatio = _config.GetCVar(CVars.NetInterpRatio);
|
||||
_processor.Logging = _config.GetCVar(CVars.NetLogging);
|
||||
Predicting = _config.GetCVar(CVars.NetPredict);
|
||||
IsPredictionEnabled = _config.GetCVar(CVars.NetPredict);
|
||||
PredictTickBias = _config.GetCVar(CVars.NetPredictTickBias);
|
||||
PredictLagBias = _config.GetCVar(CVars.NetPredictLagBias);
|
||||
|
||||
@@ -135,7 +137,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
public void InputCommandDispatched(FullInputCmdMessage message)
|
||||
{
|
||||
if (!Predicting)
|
||||
if (!IsPredictionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -144,14 +146,14 @@ namespace Robust.Client.GameStates
|
||||
_pendingInputs.Enqueue(message);
|
||||
|
||||
_inputManager.NetworkBindMap.TryGetKeyFunction(message.InputFunctionId, out var boundFunc);
|
||||
Logger.DebugS(CVars.NetPredict.Name,
|
||||
_sawmill.Debug(
|
||||
$"CL> SENT tick={_timing.CurTick}, sub={_timing.TickFraction}, seq={_nextInputCmdSeq}, func={boundFunc.FunctionName}, state={message.State}");
|
||||
_nextInputCmdSeq++;
|
||||
}
|
||||
|
||||
public uint SystemMessageDispatched<T>(T message) where T : EntityEventArgs
|
||||
{
|
||||
if (!Predicting)
|
||||
if (!IsPredictionEnabled)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -214,7 +216,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
// TODO: If Predicting gets disabled *while* the world state is dirty from a prediction,
|
||||
// this won't run meaning it could potentially get stuck dirty.
|
||||
if (Predicting && i == 0)
|
||||
if (IsPredictionEnabled && i == 0)
|
||||
{
|
||||
// Disable IsFirstTimePredicted while re-running HandleComponentState here.
|
||||
// Helps with debugging.
|
||||
@@ -238,7 +240,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
if (_lastProcessedSeq < curState.LastProcessedInput)
|
||||
{
|
||||
Logger.DebugS(CVars.NetPredict.Name, $"SV> RCV tick={_timing.CurTick}, seq={_lastProcessedSeq}");
|
||||
_sawmill.Debug($"SV> RCV tick={_timing.CurTick}, seq={_lastProcessedSeq}");
|
||||
_lastProcessedSeq = curState.LastProcessedInput;
|
||||
}
|
||||
}
|
||||
@@ -257,8 +259,7 @@ namespace Robust.Client.GameStates
|
||||
var inCmd = _pendingInputs.Dequeue();
|
||||
|
||||
_inputManager.NetworkBindMap.TryGetKeyFunction(inCmd.InputFunctionId, out var boundFunc);
|
||||
Logger.DebugS(CVars.NetPredict.Name,
|
||||
$"SV> seq={inCmd.InputSequence}, func={boundFunc.FunctionName}, state={inCmd.State}");
|
||||
_sawmill.Debug($"SV> seq={inCmd.InputSequence}, func={boundFunc.FunctionName}, state={inCmd.State}");
|
||||
}
|
||||
|
||||
while (_pendingSystemMessages.Count > 0 && _pendingSystemMessages.Peek().sequence <= _lastProcessedSeq)
|
||||
@@ -268,13 +269,13 @@ namespace Robust.Client.GameStates
|
||||
|
||||
DebugTools.Assert(_timing.InSimulation);
|
||||
|
||||
if (Predicting)
|
||||
if (IsPredictionEnabled)
|
||||
{
|
||||
using var _ = _timing.StartPastPredictionArea();
|
||||
|
||||
if (_pendingInputs.Count > 0)
|
||||
{
|
||||
Logger.DebugS(CVars.NetPredict.Name, "CL> Predicted:");
|
||||
_sawmill.Debug("CL> Predicted:");
|
||||
}
|
||||
|
||||
var pendingInputEnumerator = _pendingInputs.GetEnumerator();
|
||||
@@ -299,7 +300,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
_inputManager.NetworkBindMap.TryGetKeyFunction(inputCmd.InputFunctionId, out var boundFunc);
|
||||
|
||||
Logger.DebugS(CVars.NetPredict.Name,
|
||||
_sawmill.Debug(
|
||||
$" seq={inputCmd.InputSequence}, sub={inputCmd.SubTick}, dTick={tick}, func={boundFunc.FunctionName}, " +
|
||||
$"state={inputCmd.State}");
|
||||
|
||||
@@ -324,28 +325,34 @@ namespace Robust.Client.GameStates
|
||||
// Don't run EntitySystemManager.TickUpdate if this is the target tick,
|
||||
// because the rest of the main loop will call into it with the target tick later,
|
||||
// and it won't be a past prediction.
|
||||
_entitySystemManager.TickUpdate((float) _timing.TickPeriod.TotalSeconds);
|
||||
_entitySystemManager.TickUpdate((float) _timing.TickPeriod.TotalSeconds, noPredictions: false);
|
||||
((IBroadcastEventBusInternal) _entities.EventBus).ProcessEventQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_entities.TickUpdate((float) _timing.TickPeriod.TotalSeconds);
|
||||
_entities.TickUpdate((float) _timing.TickPeriod.TotalSeconds, noPredictions: !IsPredictionEnabled);
|
||||
|
||||
_lookup.Update();
|
||||
}
|
||||
|
||||
private void ResetPredictedEntities(GameTick curTick)
|
||||
{
|
||||
foreach (var entity in _entities.GetEntities())
|
||||
foreach (var meta in _entityManager.EntityQuery<MetaDataComponent>(true))
|
||||
{
|
||||
var entity = meta.Owner;
|
||||
|
||||
// TODO: 99% there's an off-by-one here.
|
||||
if (entity.IsClientSide() || _entityManager.GetComponent<MetaDataComponent>(entity).EntityLastModifiedTick < curTick)
|
||||
if (entity.IsClientSide() || meta.EntityLastModifiedTick < curTick)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.DebugS(CVars.NetPredict.Name, $"Entity {entity} was made dirty.");
|
||||
// Check log level first to avoid the string alloc.
|
||||
if (_sawmill.Level <= LogLevel.Debug)
|
||||
{
|
||||
_sawmill.Debug($"Entity {entity} was made dirty.");
|
||||
}
|
||||
|
||||
if (!_processor.TryGetLastServerStates(entity, out var last))
|
||||
{
|
||||
@@ -363,7 +370,7 @@ namespace Robust.Client.GameStates
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.DebugS(CVars.NetPredict.Name, $" And also its component {comp.Name}");
|
||||
_sawmill.Debug($" And also its component {comp.GetType()}");
|
||||
// TODO: Handle interpolation.
|
||||
var handleState = new ComponentHandleState(compState, null);
|
||||
_entities.EventBus.RaiseComponentEvent(comp, ref handleState);
|
||||
@@ -429,8 +436,6 @@ namespace Robust.Client.GameStates
|
||||
var toApply = new Dictionary<EntityUid, (EntityState?, EntityState?)>();
|
||||
var toInitialize = new List<EntityUid>();
|
||||
var created = new List<EntityUid>();
|
||||
var toHide = new List<EntityUid>();
|
||||
var toShow = new List<EntityUid>();
|
||||
|
||||
foreach (var es in curEntStates)
|
||||
{
|
||||
@@ -440,9 +445,6 @@ namespace Robust.Client.GameStates
|
||||
{
|
||||
// Logger.Debug($"[{IGameTiming.TickStampStatic}] MOD {es.Uid}");
|
||||
toApply.Add(uid, (es, null));
|
||||
if(_hiddenEntities.ContainsKey(uid))
|
||||
toShow.Add(uid);
|
||||
uid = es.Uid;
|
||||
}
|
||||
else //Unknown entities
|
||||
{
|
||||
@@ -456,10 +458,7 @@ namespace Robust.Client.GameStates
|
||||
toApply.Add(newEntity, (es, null));
|
||||
toInitialize.Add(newEntity);
|
||||
created.Add(newEntity);
|
||||
uid = newEntity;
|
||||
}
|
||||
if(es.Hide)
|
||||
toHide.Add(uid);
|
||||
}
|
||||
|
||||
foreach (var es in nextEntStates)
|
||||
@@ -542,21 +541,6 @@ namespace Robust.Client.GameStates
|
||||
}
|
||||
#endif
|
||||
|
||||
foreach (var entityUid in toHide)
|
||||
{
|
||||
if(_entityManager.HasComponent<MapGridComponent>(entityUid)) continue;
|
||||
|
||||
var xform = _entityManager.GetComponent<TransformComponent>(entityUid);
|
||||
_hiddenEntities.Add(entityUid, xform.MapID);
|
||||
xform.ChangeMapId(MapId.Nullspace);
|
||||
}
|
||||
|
||||
foreach (var entityUid in toShow)
|
||||
{
|
||||
_entityManager.GetComponent<TransformComponent>(entityUid).ChangeMapId(_hiddenEntities[entityUid]);
|
||||
_hiddenEntities.Remove(entityUid);
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
@@ -626,7 +610,7 @@ namespace Robust.Client.GameStates
|
||||
catch (Exception e)
|
||||
{
|
||||
var wrapper = new ComponentStateApplyException(
|
||||
$"Failed to apply comp state: entity={component.Owner}, comp={component.Name}", e);
|
||||
$"Failed to apply comp state: entity={component.Owner}, comp={component.GetType()}", e);
|
||||
#if EXCEPTION_TOLERANCE
|
||||
_runtimeLog.LogException(wrapper, "Component state apply");
|
||||
#else
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -44,6 +45,13 @@ namespace Robust.Client.GameStates
|
||||
/// </summary>
|
||||
int StateBufferMergeThreshold { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether prediction is currently enabled on the client entirely.
|
||||
/// This is NOT equal to <see cref="IGameTiming.InPrediction"/> or <see cref="IGameTiming.IsFirstTimePredicted"/>.
|
||||
/// </summary>
|
||||
/// <remarks>This is effectively an alias of <see cref="CVars.NetPredict"/>.</remarks>
|
||||
bool IsPredictionEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This is called after the game state has been applied for the current tick.
|
||||
/// </summary>
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Robust.Client.GameStates
|
||||
var transform = _entityManager.GetComponent<TransformComponent>(boundingBox.Owner);
|
||||
|
||||
// if not on the same map, continue
|
||||
if (transform.MapID != _eyeManager.CurrentMap || boundingBox.Owner.IsInContainer())
|
||||
if (transform.MapID != _eyeManager.CurrentMap || boundingBox.Owner.IsInContainer(_entityManager))
|
||||
continue;
|
||||
|
||||
// This entity isn't lerping, no need to draw debug info for it
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using JetBrains.Annotations;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -31,5 +31,14 @@ namespace Robust.Client.Graphics
|
||||
/// Our sub region within our source, in pixel coordinates.
|
||||
/// </summary>
|
||||
public UIBox2 SubRegion { get; }
|
||||
|
||||
public override Color GetPixel(int x, int y)
|
||||
{
|
||||
DebugTools.Assert(x < SubRegion.Right);
|
||||
DebugTools.Assert(y < SubRegion.Top);
|
||||
int xTranslated = x + (int) SubRegion.Left;
|
||||
int yTranslated = y + (int) SubRegion.Top;
|
||||
return this.SourceTexture[xTranslated, yTranslated];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,9 +215,16 @@ namespace Robust.Client.Graphics.Audio
|
||||
_openALSawmill.Info($"Set audio attenuation to {attToString.ToString()}");
|
||||
}
|
||||
|
||||
public IClydeAudioSource CreateAudioSource(AudioStream stream)
|
||||
public IClydeAudioSource? CreateAudioSource(AudioStream stream)
|
||||
{
|
||||
var source = AL.GenSource();
|
||||
|
||||
if (!AL.IsSource(source))
|
||||
{
|
||||
_openALSawmill.Error("Failed to generate source. Too many simultaneous audio streams?");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
// TODO: This really shouldn't be indexing based on the ClydeHandle...
|
||||
AL.Source(source, ALSourcei.Buffer, _audioSampleBuffers[(int) stream.ClydeHandle!.Value.Value].BufferHandle);
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Robust.Client.Graphics.Audio
|
||||
return ActualImplementation.LoadAudioRaw(samples, channels, sampleRate, name);
|
||||
}
|
||||
|
||||
public IClydeAudioSource CreateAudioSource(AudioStream stream)
|
||||
public IClydeAudioSource? CreateAudioSource(AudioStream stream)
|
||||
{
|
||||
return ActualImplementation.CreateAudioSource(stream);
|
||||
}
|
||||
|
||||
@@ -32,14 +32,20 @@ namespace Robust.Client.Graphics
|
||||
public IEye CurrentEye
|
||||
{
|
||||
get => _currentEye ?? _defaultEye;
|
||||
set => _currentEye = value;
|
||||
set
|
||||
{
|
||||
var old = _currentEye;
|
||||
_currentEye = value;
|
||||
|
||||
_entityManager.EventBus.RaiseEvent(EventSource.Local, new CurrentEyeChangedEvent(old, _currentEye));
|
||||
}
|
||||
}
|
||||
|
||||
public IViewportControl MainViewport { get; set; } = default!;
|
||||
|
||||
public void ClearCurrentEye()
|
||||
{
|
||||
_currentEye = _defaultEye;
|
||||
CurrentEye = _defaultEye;
|
||||
}
|
||||
|
||||
void IEyeManager.Initialize()
|
||||
@@ -146,4 +152,16 @@ namespace Robust.Client.Graphics
|
||||
return MainViewport.ScreenToMap(point);
|
||||
}
|
||||
}
|
||||
|
||||
public class CurrentEyeChangedEvent : EntityEventArgs
|
||||
{
|
||||
public IEye? Old { get; }
|
||||
public IEye New { get; }
|
||||
|
||||
public CurrentEyeChangedEvent(IEye? oldEye, IEye newEye)
|
||||
{
|
||||
Old = oldEye;
|
||||
New = newEye;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (_cfg.GetCVar(CVars.DisplayEgl))
|
||||
{
|
||||
_sawmillOgl.Debug("Trying EGL");
|
||||
@@ -40,7 +39,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_glContext = ctxEgl;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// These are set from Clyde.Windowing.
|
||||
private bool _isGLES;
|
||||
private bool _isGLES2;
|
||||
private bool _isCore;
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -372,22 +372,24 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private void ProcessSpriteEntities(MapId map, Matrix3 eyeMatrix, Box2Rotated worldBounds,
|
||||
RefList<(SpriteComponent sprite, Matrix3 matrix, Angle worldRot, float yWorldPos)> list)
|
||||
{
|
||||
var xforms = _entityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var comp in _entitySystemManager.GetEntitySystem<RenderingTreeSystem>().GetRenderTrees(map, worldBounds))
|
||||
{
|
||||
var bounds = _entityManager.GetComponent<TransformComponent>(comp.Owner).InvWorldMatrix.TransformBox(worldBounds);
|
||||
var bounds = xforms.GetComponent(comp.Owner).InvWorldMatrix.TransformBox(worldBounds);
|
||||
|
||||
comp.SpriteTree.QueryAabb(ref list, (
|
||||
ref RefList<(SpriteComponent sprite, Matrix3 matrix, Angle worldRot, float yWorldPos)> state,
|
||||
in SpriteComponent value) =>
|
||||
{
|
||||
var entity = value.Owner;
|
||||
var transform = _entityManager.GetComponent<TransformComponent>(entity);
|
||||
var transform = xforms.GetComponent(entity);
|
||||
|
||||
ref var entry = ref state.AllocAdd();
|
||||
entry.sprite = value;
|
||||
entry.worldRot = transform.WorldRotation;
|
||||
entry.matrix = transform.WorldMatrix;
|
||||
var eyePos = eyeMatrix.Transform(new Vector2(entry.matrix.R0C2, entry.matrix.R1C2));
|
||||
Vector2 worldPos;
|
||||
(worldPos, entry.worldRot, entry.matrix) = transform.GetWorldPositionRotationMatrix();
|
||||
var eyePos = eyeMatrix.Transform(worldPos);
|
||||
// Didn't use the bounds from the query as that has to be re-calculated (and is probably more expensive than this).
|
||||
var bounds = value.CalculateBoundingBox(eyePos);
|
||||
entry.yWorldPos = eyePos.Y - bounds.Extents.Y;
|
||||
@@ -403,12 +405,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
ClearFramebuffer(Color.Black);
|
||||
|
||||
var splashTex = _cfg.GetCVar(CVars.DisplaySplashLogo);
|
||||
if (string.IsNullOrEmpty(splashTex))
|
||||
return;
|
||||
|
||||
var texture = _resourceCache.GetResource<TextureResource>(splashTex).Texture;
|
||||
|
||||
handle.DrawingHandleScreen.DrawTexture(texture, (ScreenSize - texture.Size) / 2);
|
||||
}
|
||||
|
||||
private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color clearColor=default)
|
||||
private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearColor=default)
|
||||
{
|
||||
// TODO: for the love of god all this state pushing/popping needs to be cleaned up.
|
||||
|
||||
@@ -422,7 +427,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
{
|
||||
BindRenderTargetFull(RtToLoaded(rt));
|
||||
ClearFramebuffer(clearColor);
|
||||
if (clearColor is not null)
|
||||
ClearFramebuffer(clearColor.Value);
|
||||
SetViewportImmediate(Box2i.FromDimensions(Vector2i.Zero, rt.Size));
|
||||
_updateUniformConstants(rt.Size);
|
||||
CalcScreenMatrices(rt.Size, out var proj, out var view);
|
||||
@@ -524,7 +530,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
RenderOverlays(viewport, OverlaySpace.WorldSpace, worldAABB, worldBounds);
|
||||
|
||||
_currentViewport = oldVp;
|
||||
});
|
||||
}, viewport.ClearColor);
|
||||
}
|
||||
|
||||
private static Box2 CalcWorldAABB(Viewport viewport)
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
PixelInternalFormat.Srgb8Alpha8 => 4,
|
||||
PixelInternalFormat.R11fG11fB10f => 4,
|
||||
PixelInternalFormat.R32f => 4,
|
||||
PixelInternalFormat.Rg32f => 4,
|
||||
PixelInternalFormat.Rg32f => 8,
|
||||
PixelInternalFormat.R8 => 1,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
@@ -515,10 +515,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Use worldbounds for this one as we only care if the light intersects our actual bounds
|
||||
var state = (this, worldAABB, count: 0);
|
||||
var xforms = _entityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var comp in renderingTreeSystem.GetRenderTrees(map, enlargedBounds))
|
||||
{
|
||||
var bounds = _entityManager.GetComponent<TransformComponent>(comp.Owner).InvWorldMatrix.TransformBox(worldBounds);
|
||||
var bounds = xforms.GetComponent(comp.Owner).InvWorldMatrix.TransformBox(worldBounds);
|
||||
|
||||
comp.LightTree.QueryAabb(ref state, (ref (Clyde clyde, Box2 worldAABB, int count) state, in PointLightComponent light) =>
|
||||
{
|
||||
@@ -528,7 +529,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return false;
|
||||
}
|
||||
|
||||
var transform = _entityManager.GetComponent<TransformComponent>(light.Owner);
|
||||
var transform = xforms.GetComponent(light.Owner);
|
||||
|
||||
if (float.IsNaN(transform.LocalPosition.X) || float.IsNaN(transform.LocalPosition.Y)) return true;
|
||||
|
||||
@@ -871,21 +872,24 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var ii = 0;
|
||||
var imi = 0;
|
||||
|
||||
var xforms = _entityManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var comp in occluderSystem.GetOccluderTrees(map, expandedBounds))
|
||||
{
|
||||
var treeBounds = _entityManager.GetComponent<TransformComponent>(comp.Owner).InvWorldMatrix.TransformBox(expandedBounds);
|
||||
var treeBounds = xforms.GetComponent(comp.Owner).InvWorldMatrix.TransformBox(expandedBounds);
|
||||
|
||||
comp.Tree.QueryAabb((in OccluderComponent sOccluder) =>
|
||||
{
|
||||
var occluder = (ClientOccluderComponent)sOccluder;
|
||||
var transform = _entityManager.GetComponent<TransformComponent>(occluder.Owner);
|
||||
if (!occluder.Enabled)
|
||||
var transform = xforms.GetComponent(sOccluder.Owner);
|
||||
if (!sOccluder.Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var occluder = (ClientOccluderComponent)sOccluder;
|
||||
|
||||
var worldTransform = transform.WorldMatrix;
|
||||
var box = occluder.BoundingBox;
|
||||
var box = sOccluder.BoundingBox;
|
||||
|
||||
var tl = worldTransform.Transform(box.TopLeft);
|
||||
var tr = worldTransform.Transform(box.TopRight);
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Cache currently bound framebuffers
|
||||
// so if somebody creates a framebuffer while drawing it won't ruin everything.
|
||||
// Note that this means _currentBoundRenderTarget goes temporarily out of sync here
|
||||
var boundDrawBuffer = GL.GetInteger(GetPName.DrawFramebufferBinding);
|
||||
var boundDrawBuffer = GL.GetInteger(
|
||||
_isGLES2 ? GetPName.FramebufferBinding : GetPName.DrawFramebufferBinding);
|
||||
var boundReadBuffer = 0;
|
||||
if (_hasGLReadFramebuffer)
|
||||
{
|
||||
@@ -102,18 +103,29 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Make sure to specify the correct pixel type and formats even if we're not uploading any data.
|
||||
// Not doing this (just sending red/byte) is fine on desktop GL but illegal on ES.
|
||||
// @formatter:off
|
||||
var (internalFormat, pixFormat, pixType) = colorFormat switch
|
||||
{
|
||||
// using block comments to force formatters to not fuck this up.
|
||||
RTCF.Rgba8 => /* */(PIF.Rgba8, /* */PF.Rgba, /**/PT.UnsignedByte),
|
||||
RTCF.Rgba16F => /* */(PIF.Rgba16f, /* */PF.Rgba, /**/PT.Float),
|
||||
RTCF.Rgba8Srgb => /* */(PIF.Srgb8Alpha8, /* */PF.Rgba, /**/PT.UnsignedByte),
|
||||
RTCF.R11FG11FB10F => /**/(PIF.R11fG11fB10f, /**/PF.Rgb, /* */PT.Float),
|
||||
RTCF.R32F => /* */(PIF.R32f, /* */PF.Red, /* */PT.Float),
|
||||
RTCF.RG32F => /* */(PIF.Rg32f, /* */PF.Rg, /* */PT.Float),
|
||||
RTCF.R8 => /* */(PIF.R8, /* */PF.Red, /* */PT.UnsignedByte),
|
||||
RTCF.Rgba8 => (PIF.Rgba8, PF.Rgba, PT.UnsignedByte),
|
||||
RTCF.Rgba16F => (PIF.Rgba16f, PF.Rgba, PT.Float),
|
||||
RTCF.Rgba8Srgb => (PIF.Srgb8Alpha8, PF.Rgba, PT.UnsignedByte),
|
||||
RTCF.R11FG11FB10F => (PIF.R11fG11fB10f, PF.Rgb, PT.Float),
|
||||
RTCF.R32F => (PIF.R32f, PF.Red, PT.Float),
|
||||
RTCF.RG32F => (PIF.Rg32f, PF.Rg, PT.Float),
|
||||
RTCF.R8 => (PIF.R8, PF.Red, PT.UnsignedByte),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(format.ColorFormat), format.ColorFormat, null)
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
if (_isGLES2)
|
||||
{
|
||||
(internalFormat, pixFormat, pixType) = colorFormat switch
|
||||
{
|
||||
RTCF.Rgba8 => (PIF.Rgba, PF.Rgba, PT.UnsignedByte),
|
||||
RTCF.R8 => (PIF.Rgba, PF.Rgba, PT.UnsignedByte),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(format.ColorFormat), format.ColorFormat, null)
|
||||
};
|
||||
}
|
||||
|
||||
estPixSize += EstPixelSize(internalFormat);
|
||||
|
||||
@@ -169,7 +181,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
$"new framebuffer has bad status {status}");
|
||||
|
||||
// Re-bind previous framebuffers (thus _currentBoundRenderTarget is back in sync)
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, boundDrawBuffer);
|
||||
GL.BindFramebuffer(
|
||||
_isGLES2 ? FramebufferTarget.Framebuffer : FramebufferTarget.DrawFramebuffer,
|
||||
boundDrawBuffer);
|
||||
CheckGlError();
|
||||
if (_hasGLReadFramebuffer)
|
||||
{
|
||||
@@ -273,11 +287,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public Vector2i Size;
|
||||
public bool IsSrgb;
|
||||
|
||||
#pragma warning disable 649
|
||||
// Gets assigned by (currently commented out) GLContextAngle.
|
||||
// It's fine don't worry about it.
|
||||
public bool FlipY;
|
||||
#pragma warning restore 649
|
||||
|
||||
public RTCF ColorFormat;
|
||||
|
||||
|
||||
@@ -52,11 +52,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public StencilParameters Stencil = StencilParameters.Default;
|
||||
}
|
||||
|
||||
public ClydeHandle LoadShader(ParsedShader shader, string? name = null)
|
||||
public ClydeHandle LoadShader(ParsedShader shader, string? name = null, Dictionary<string,string>? defines = null)
|
||||
{
|
||||
var (vertBody, fragBody) = GetShaderCode(shader);
|
||||
|
||||
var program = _compileProgram(vertBody, fragBody, BaseShaderAttribLocations, name);
|
||||
var program = _compileProgram(vertBody, fragBody, BaseShaderAttribLocations, name, defines: defines);
|
||||
|
||||
if (_hasGLUniformBuffers)
|
||||
{
|
||||
@@ -141,7 +141,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
private GLShaderProgram _compileProgram(string vertexSource, string fragmentSource,
|
||||
(string, uint)[] attribLocations, string? name = null, bool includeLib=true)
|
||||
(string, uint)[] attribLocations, string? name = null, bool includeLib=true, Dictionary<string,string>? defines=null)
|
||||
{
|
||||
GLShader? vertexShader = null;
|
||||
GLShader? fragmentShader = null;
|
||||
@@ -186,6 +186,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
versionHeader += "#define HAS_UNIFORM_BUFFERS\n";
|
||||
}
|
||||
|
||||
if (defines is not null)
|
||||
{
|
||||
foreach (var k in defines.Keys)
|
||||
{
|
||||
versionHeader += $"#define {k} {defines[k]}\n";
|
||||
}
|
||||
}
|
||||
|
||||
var lib = includeLib ? _shaderLibrary : "";
|
||||
vertexSource = versionHeader + "#define VERTEX_SHADER\n" + lib + vertexSource;
|
||||
fragmentSource = versionHeader + "#define FRAGMENT_SHADER\n" + lib + fragmentSource;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
@@ -11,6 +12,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Color = Robust.Shared.Maths.Color;
|
||||
using OGLTextureWrapMode = OpenToolkit.Graphics.OpenGL.TextureWrapMode;
|
||||
using PIF = OpenToolkit.Graphics.OpenGL4.PixelInternalFormat;
|
||||
using PF = OpenToolkit.Graphics.OpenGL4.PixelFormat;
|
||||
@@ -146,7 +148,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
CheckGlError();
|
||||
ApplySampleParameters(loadParams.SampleParameters);
|
||||
|
||||
var (pif, _, _) = PixelEnums<T>(loadParams.Srgb);
|
||||
var (pif, pf, pt) = PixelEnums<T>(loadParams.Srgb);
|
||||
var pixelType = typeof(T);
|
||||
var texPixType = GetTexturePixelType<T>();
|
||||
var isActuallySrgb = false;
|
||||
@@ -255,6 +257,16 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private (PIF pif, PF pf, PT pt) PixelEnums<T>(bool srgb)
|
||||
where T : unmanaged, IPixel<T>
|
||||
{
|
||||
if (_isGLES2)
|
||||
{
|
||||
return default(T) switch
|
||||
{
|
||||
Rgba32 => (PIF.Rgba, PF.Rgba, PT.UnsignedByte),
|
||||
L8 => (PIF.Luminance, PF.Red, PT.UnsignedByte),
|
||||
_ => throw new NotSupportedException("Unsupported pixel type."),
|
||||
};
|
||||
}
|
||||
|
||||
return default(T) switch
|
||||
{
|
||||
// Note that if _hasGLSrgb is off, we import an sRGB texture as non-sRGB.
|
||||
@@ -633,6 +645,25 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
return $"ClydeTexture: ({TextureId})";
|
||||
}
|
||||
|
||||
public override Color GetPixel(int x, int y)
|
||||
{
|
||||
if (!_clyde._loadedTextures.TryGetValue(TextureId, out var loaded))
|
||||
{
|
||||
throw new DataException("Texture not found");
|
||||
}
|
||||
|
||||
Span<byte> rgba = stackalloc byte[4];
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* p = rgba)
|
||||
{
|
||||
GL.GetTextureImage(loaded.OpenGLObject.Handle, 0, PF.Rgba, PT.UnsignedByte, 4, (IntPtr) p);
|
||||
}
|
||||
}
|
||||
|
||||
return new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public Texture GetStockTexture(ClydeStockTexture stockTexture)
|
||||
|
||||
@@ -112,6 +112,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
public Vector2i Size { get; set; }
|
||||
public Color? ClearColor { get; set; } = Color.Black;
|
||||
public Vector2 RenderScale { get; set; } = Vector2.One;
|
||||
public bool AutomaticRender { get; set; }
|
||||
|
||||
@@ -143,7 +144,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
if (Eye == null)
|
||||
return default;
|
||||
|
||||
var eye = (IEye) Eye;
|
||||
var eye = Eye;
|
||||
var newPoint = point;
|
||||
|
||||
eye.GetViewMatrix(out var viewMatrix, RenderScale);
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared;
|
||||
@@ -13,8 +12,9 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using static Robust.Client.Utility.Win32;
|
||||
using TerraFX.Interop.Windows;
|
||||
using FrameEventArgs = Robust.Shared.Timing.FrameEventArgs;
|
||||
using GL = OpenToolkit.Graphics.OpenGL4.GL;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
@@ -204,10 +204,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
"or enable compatibility mode in the launcher if that fails.\n" +
|
||||
$"The exact error is: {lastError}";
|
||||
|
||||
MessageBoxW(null,
|
||||
msgBoxContent,
|
||||
"Space Station 14: Failed to create window",
|
||||
MB_OK | MB_ICONERROR);
|
||||
fixed (char* pText = msgBoxContent)
|
||||
fixed (char* pCaption = "RobustToolbox: Failed to create window")
|
||||
{
|
||||
Windows.MessageBoxW(HWND.NULL,
|
||||
(ushort*) pText,
|
||||
(ushort*) pCaption,
|
||||
MB.MB_OK | MB.MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.FatalS("clyde.win",
|
||||
|
||||
@@ -159,6 +159,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private void InitOpenGL()
|
||||
{
|
||||
_isGLES = _openGLVersion is RendererOpenGLVersion.GLES2 or RendererOpenGLVersion.GLES3;
|
||||
_isGLES2 = _openGLVersion is RendererOpenGLVersion.GLES2;
|
||||
_isCore = _openGLVersion is RendererOpenGLVersion.GL33;
|
||||
|
||||
GLInitBindings(_isGLES);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
@@ -221,7 +221,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return window;
|
||||
}
|
||||
|
||||
public ClydeHandle LoadShader(ParsedShader shader, string? name = null)
|
||||
public ClydeHandle LoadShader(ParsedShader shader, string? name = null, Dictionary<string,string>? defines = null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -383,6 +383,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
// Just do nothing on mutate.
|
||||
}
|
||||
|
||||
public override Color GetPixel(int x, int y)
|
||||
{
|
||||
return Color.Black;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DummyShaderInstance : ShaderInstance
|
||||
@@ -540,6 +545,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
public IEye? Eye { get; set; }
|
||||
public Vector2i Size { get; }
|
||||
public Color? ClearColor { get; set; } = Color.Black;
|
||||
public Vector2 RenderScale { get; set; }
|
||||
public bool AutomaticRender { get; set; }
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private IDXGIFactory1* _factory;
|
||||
private IDXGIAdapter1* _adapter;
|
||||
private ID3D11Device* _device;
|
||||
private ID3D11DeviceContext* _deviceContext;
|
||||
private D3D_FEATURE_LEVEL _deviceFl;
|
||||
private void* _eglDevice;
|
||||
private void* _eglDisplay;
|
||||
@@ -320,6 +319,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
#pragma warning disable CS0162
|
||||
IDXGIFactory6* factory6;
|
||||
if (_adapter == null && _factory->QueryInterface(__uuidof<IDXGIFactory6>(), (void**) &factory6) == 0)
|
||||
{
|
||||
@@ -349,6 +349,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
factory6->Release();
|
||||
}
|
||||
#pragma warning restore CS0162
|
||||
#pragma warning restore CA1416
|
||||
|
||||
Span<D3D_FEATURE_LEVEL> featureLevels = stackalloc D3D_FEATURE_LEVEL[]
|
||||
@@ -363,6 +364,16 @@ namespace Robust.Client.Graphics.Clyde
|
||||
D3D_FEATURE_LEVEL_9_1
|
||||
};
|
||||
|
||||
if (Clyde._cfg.GetCVar(CVars.DisplayAngleForceEs2))
|
||||
{
|
||||
featureLevels = stackalloc D3D_FEATURE_LEVEL[]
|
||||
{
|
||||
// Don't allow FL 11_0 so ANGLE is forced to init GLES2.
|
||||
D3D_FEATURE_LEVEL_9_3,
|
||||
D3D_FEATURE_LEVEL_9_1
|
||||
};
|
||||
}
|
||||
|
||||
fixed (ID3D11Device** device = &_device)
|
||||
fixed (D3D_FEATURE_LEVEL* fl = &featureLevels[0])
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using OpenToolkit;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using TerraFX.Interop.Windows;
|
||||
using static Robust.Client.Graphics.Clyde.Egl;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
@@ -106,7 +106,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
// Setting up ANGLE without manually selecting a D3D11 device requires a windows DC.
|
||||
mainWindow.DC = GetDC(Clyde._windowing!.WindowGetWin32Window(mainWindow.Reg)!.Value);
|
||||
mainWindow.DC = Windows.GetDC((HWND)Clyde._windowing!.WindowGetWin32Window(mainWindow.Reg)!.Value);
|
||||
|
||||
_eglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, (void*) mainWindow.DC, null);
|
||||
if (_eglDisplay == null)
|
||||
@@ -272,25 +272,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
public void* EglSurface;
|
||||
}
|
||||
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern nint GetDC(nint hWnd);
|
||||
|
||||
private sealed class EglBindingsContext : IBindingsContext
|
||||
{
|
||||
public IntPtr GetProcAddress(string procName)
|
||||
{
|
||||
Span<byte> buf = stackalloc byte[128];
|
||||
buf.Clear();
|
||||
Encoding.UTF8.GetBytes(procName, buf);
|
||||
|
||||
fixed (byte* b = &buf.GetPinnableReference())
|
||||
{
|
||||
return (nint) eglGetProcAddress(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
adapter3->Release();
|
||||
}
|
||||
|
||||
dxgiFactory->Release();
|
||||
}
|
||||
|
||||
private static void ThrowIfFailed(string methodName, HRESULT hr)
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using TerraFX.Interop.Windows;
|
||||
using GlfwImage = OpenToolkit.GraphicsLibraryFramework.Image;
|
||||
using Monitor = OpenToolkit.GraphicsLibraryFramework.Monitor;
|
||||
|
||||
@@ -360,12 +361,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// On Windows, closing the child window causes the owner to be minimized, apparently.
|
||||
// Clear owner on close to avoid this.
|
||||
|
||||
var hWnd = (void*) GLFW.GetWin32Window(window);
|
||||
DebugTools.Assert(hWnd != null);
|
||||
var hWnd = (HWND) GLFW.GetWin32Window(window);
|
||||
DebugTools.Assert(hWnd != HWND.NULL);
|
||||
|
||||
Win32.SetWindowLongPtrW(
|
||||
Windows.SetWindowLongPtrW(
|
||||
hWnd,
|
||||
Win32.GWLP_HWNDPARENT,
|
||||
GWLP.GWLP_HWNDPARENT,
|
||||
0);
|
||||
}
|
||||
|
||||
@@ -378,8 +379,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
Window* contextShare,
|
||||
Window* ownerWindow)
|
||||
{
|
||||
GLFW.WindowHint(WindowHintString.X11ClassName, "SS14");
|
||||
GLFW.WindowHint(WindowHintString.X11InstanceName, "SS14");
|
||||
GLFW.WindowHint(WindowHintString.X11ClassName, "RobustToolbox");
|
||||
GLFW.WindowHint(WindowHintString.X11InstanceName, "RobustToolbox");
|
||||
GLFW.WindowHint(WindowHintBool.ScaleToMonitor, true);
|
||||
|
||||
if (spec == null)
|
||||
@@ -481,14 +482,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
var hWnd = (void*) GLFW.GetWin32Window(window);
|
||||
DebugTools.Assert(hWnd != null);
|
||||
var hWnd = (HWND) GLFW.GetWin32Window(window);
|
||||
DebugTools.Assert(hWnd != HWND.NULL);
|
||||
|
||||
Win32.SetWindowLongPtrW(
|
||||
Windows.SetWindowLongPtrW(
|
||||
hWnd,
|
||||
Win32.GWL_STYLE,
|
||||
GWL.GWL_STYLE,
|
||||
// Cast to long here to work around a bug in rider with nint bitwise operators.
|
||||
(nint)((long)Win32.GetWindowLongPtrW(hWnd, Win32.GWL_STYLE) & ~Win32.WS_SYSMENU));
|
||||
(nint)((long)Windows.GetWindowLongPtrW(hWnd, GWL.GWL_STYLE) & ~WS.WS_SYSMENU));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -500,13 +501,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
var hWnd = (void*) GLFW.GetWin32Window(window);
|
||||
var ownerHWnd = GLFW.GetWin32Window(ownerWindow);
|
||||
DebugTools.Assert(hWnd != null);
|
||||
var hWnd = (HWND) GLFW.GetWin32Window(window);
|
||||
var ownerHWnd = (HWND) GLFW.GetWin32Window(ownerWindow);
|
||||
DebugTools.Assert(hWnd != HWND.NULL);
|
||||
|
||||
Win32.SetWindowLongPtrW(
|
||||
Windows.SetWindowLongPtrW(
|
||||
hWnd,
|
||||
Win32.GWLP_HWNDPARENT,
|
||||
GWLP.GWLP_HWNDPARENT,
|
||||
ownerHWnd);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Robust.Client.Graphics
|
||||
|
||||
void SetMasterVolume(float newVolume);
|
||||
|
||||
IClydeAudioSource CreateAudioSource(AudioStream stream);
|
||||
IClydeAudioSource? CreateAudioSource(AudioStream stream);
|
||||
IClydeBufferedAudioSource CreateBufferedAudioSource(int buffers, bool floatAudio=false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Map;
|
||||
@@ -31,7 +32,7 @@ namespace Robust.Client.Graphics
|
||||
event Action<WindowRequestClosedEventArgs> CloseWindow;
|
||||
event Action<WindowDestroyedEventArgs> DestroyWindow;
|
||||
|
||||
ClydeHandle LoadShader(ParsedShader shader, string? name = null);
|
||||
ClydeHandle LoadShader(ParsedShader shader, string? name = null, Dictionary<string,string>? defines = null);
|
||||
|
||||
void ReloadShader(ClydeHandle handle, ParsedShader newShader);
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ namespace Robust.Client.Graphics
|
||||
IEye? Eye { get; set; }
|
||||
Vector2i Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Color to clear the render target to before rendering. If null, no clearing will happen.
|
||||
/// </summary>
|
||||
Color? ClearColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is, effectively, a multiplier to the eye's zoom.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Color = Robust.Shared.Maths.Color;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
@@ -31,6 +32,8 @@ namespace Robust.Client.Graphics
|
||||
/// </summary>
|
||||
public Vector2i Size { get; /*protected set;*/ }
|
||||
|
||||
public Color this[int x, int y] => this.GetPixel(x, y);
|
||||
|
||||
protected Texture(Vector2i size)
|
||||
{
|
||||
Size = size;
|
||||
@@ -104,6 +107,8 @@ namespace Robust.Client.Graphics
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract Color GetPixel(int x, int y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Robust.Client.Input
|
||||
mapping.Add("leaveEmpty", serializationManager.WriteValue(leaveEmpty));
|
||||
|
||||
var path = new ResourcePath(KeybindsPath);
|
||||
using var writer = new StreamWriter(_resourceMan.UserData.Create(path));
|
||||
using var writer = _resourceMan.UserData.OpenWriteText(path);
|
||||
var stream = new YamlStream {new(mapping.ToYaml())};
|
||||
stream.Save(new YamlMappingFix(new Emitter(writer)), false);
|
||||
}
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Map
|
||||
{
|
||||
internal class ClientMapManager : MapManager, IClientMapManager
|
||||
{
|
||||
public void ApplyGameStatePre(GameStateMapData? data, ReadOnlySpan<EntityState> entityStates)
|
||||
{
|
||||
// There was no map data this tick, so nothing to do.
|
||||
if(data == null)
|
||||
return;
|
||||
|
||||
// First we need to figure out all the NEW MAPS.
|
||||
if(data.CreatedMaps != null)
|
||||
{
|
||||
DebugTools.Assert(!entityStates.IsEmpty, "Received new maps, but no entity state.");
|
||||
|
||||
foreach (var mapId in data.CreatedMaps)
|
||||
{
|
||||
// map already exists from a previous state.
|
||||
if (_maps.Contains(mapId))
|
||||
continue;
|
||||
|
||||
EntityUid mapEuid = default;
|
||||
|
||||
//get shared euid of map comp entity
|
||||
foreach (var entityState in entityStates!)
|
||||
{
|
||||
foreach (var compChange in entityState.ComponentChanges.Span)
|
||||
{
|
||||
if (compChange.State is not MapComponentState mapCompState || mapCompState.MapId != mapId)
|
||||
continue;
|
||||
|
||||
mapEuid = entityState.Uid;
|
||||
goto BreakMapEntSearch;
|
||||
}
|
||||
}
|
||||
BreakMapEntSearch:
|
||||
|
||||
DebugTools.Assert(mapEuid != default, $"Could not find corresponding entity state for new map {mapId}.");
|
||||
|
||||
CreateMap(mapId, mapEuid);
|
||||
}
|
||||
}
|
||||
|
||||
// Then make all the grids.
|
||||
if(data.CreatedGrids != null)
|
||||
{
|
||||
DebugTools.Assert(data.GridData is not null, "Received new grids, but GridData was null.");
|
||||
|
||||
foreach (var (gridId, creationDatum) in data.CreatedGrids)
|
||||
{
|
||||
if (_grids.ContainsKey(gridId))
|
||||
continue;
|
||||
|
||||
EntityUid gridEuid = default;
|
||||
|
||||
//get shared euid of map comp entity
|
||||
foreach (var entityState in entityStates!)
|
||||
{
|
||||
foreach (var compState in entityState.ComponentChanges.Span)
|
||||
{
|
||||
if (compState.State is not MapGridComponentState gridCompState || gridCompState.GridIndex != gridId)
|
||||
continue;
|
||||
|
||||
gridEuid = entityState.Uid;
|
||||
goto BreakGridEntSearch;
|
||||
}
|
||||
}
|
||||
BreakGridEntSearch:
|
||||
|
||||
DebugTools.Assert(gridEuid != default, $"Could not find corresponding entity state for new grid {gridId}.");
|
||||
|
||||
MapId gridMapId = default;
|
||||
foreach (var kvData in data.GridData!)
|
||||
{
|
||||
if (kvData.Key != gridId)
|
||||
continue;
|
||||
|
||||
gridMapId = kvData.Value.Coordinates.MapId;
|
||||
break;
|
||||
}
|
||||
|
||||
DebugTools.Assert(gridMapId != default, $"Could not find corresponding gridData for new grid {gridId}.");
|
||||
|
||||
CreateGrid(gridMapId, gridId, creationDatum.ChunkSize, gridEuid);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all grid updates.
|
||||
if(data.GridData != null)
|
||||
{
|
||||
SuppressOnTileChanged = true;
|
||||
// Ok good all the grids and maps exist now.
|
||||
foreach (var (gridId, gridDatum) in data.GridData)
|
||||
{
|
||||
var grid = _grids[gridId];
|
||||
if (grid.ParentMapId != gridDatum.Coordinates.MapId)
|
||||
{
|
||||
throw new NotImplementedException("Moving grids between maps is not yet implemented");
|
||||
}
|
||||
|
||||
grid.WorldPosition = gridDatum.Coordinates.Position;
|
||||
|
||||
var modified = new List<(Vector2i position, Tile tile)>();
|
||||
foreach (var chunkData in gridDatum.ChunkData)
|
||||
{
|
||||
var chunk = grid.GetChunk(chunkData.Index);
|
||||
chunk.SuppressCollisionRegeneration = true;
|
||||
DebugTools.Assert(chunkData.TileData.Length == grid.ChunkSize * grid.ChunkSize);
|
||||
|
||||
var counter = 0;
|
||||
for (ushort x = 0; x < grid.ChunkSize; x++)
|
||||
{
|
||||
for (ushort y = 0; y < grid.ChunkSize; y++)
|
||||
{
|
||||
var tile = chunkData.TileData[counter++];
|
||||
if (chunk.GetTileRef(x, y).Tile != tile)
|
||||
{
|
||||
chunk.SetTile(x, y, tile);
|
||||
modified.Add((new Vector2i(chunk.X * grid.ChunkSize + x, chunk.Y * grid.ChunkSize + y), tile));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modified.Count != 0)
|
||||
{
|
||||
InvokeGridChanged(this, new GridChangedEventArgs(grid, modified));
|
||||
}
|
||||
|
||||
foreach (var chunkData in gridDatum.ChunkData)
|
||||
{
|
||||
var chunk = grid.GetChunk(chunkData.Index);
|
||||
chunk.SuppressCollisionRegeneration = false;
|
||||
chunk.RegenerateCollision();
|
||||
}
|
||||
|
||||
foreach (var chunkData in gridDatum.DeletedChunkData)
|
||||
{
|
||||
grid.RemoveChunk(chunkData.Index);
|
||||
}
|
||||
}
|
||||
|
||||
SuppressOnTileChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyGameStatePost(GameStateMapData? data)
|
||||
{
|
||||
if(data == null) // if there is no data, there is nothing to do!
|
||||
return;
|
||||
|
||||
if(data.DeletedGrids != null)
|
||||
{
|
||||
foreach (var grid in data.DeletedGrids)
|
||||
{
|
||||
if (_grids.ContainsKey(grid))
|
||||
{
|
||||
DeleteGrid(grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(data.DeletedMaps != null)
|
||||
{
|
||||
foreach (var map in data.DeletedMaps)
|
||||
{
|
||||
if (_maps.Contains(map))
|
||||
{
|
||||
DeleteMap(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Robust.Client.Map
|
||||
{
|
||||
internal interface IClientMapManager : IMapManagerInternal
|
||||
{
|
||||
// Two methods here, so that new grids etc can be made BEFORE entities get states applied,
|
||||
// but old ones can be deleted after.
|
||||
void ApplyGameStatePre(GameStateMapData? data, ReadOnlySpan<EntityState> entityStates);
|
||||
void ApplyGameStatePost(GameStateMapData? data);
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,16 @@ namespace Robust.Client.Physics
|
||||
public sealed class PhysicsMapComponent : SharedPhysicsMapComponent
|
||||
{
|
||||
private float _timeToSleep;
|
||||
private float _linSleepTolerance;
|
||||
private float _angSleepTolerance;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
var configManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
configManager.OnValueChanged(CVars.TimeToSleep, SetTimeToSleep);
|
||||
configManager.OnValueChanged(CVars.TimeToSleep, SetTimeToSleep, true);
|
||||
configManager.OnValueChanged(CVars.LinearSleepTolerance, SetLinearSleepTolerance, true);
|
||||
configManager.OnValueChanged(CVars.AngularSleepTolerance, SetAngularSleepTolerance, true);
|
||||
}
|
||||
|
||||
protected override void OnRemove()
|
||||
@@ -25,10 +29,16 @@ namespace Robust.Client.Physics
|
||||
base.OnRemove();
|
||||
var configManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
configManager.UnsubValueChanged(CVars.TimeToSleep, SetTimeToSleep);
|
||||
configManager.UnsubValueChanged(CVars.LinearSleepTolerance, SetLinearSleepTolerance);
|
||||
configManager.UnsubValueChanged(CVars.AngularSleepTolerance, SetAngularSleepTolerance);
|
||||
}
|
||||
|
||||
private void SetTimeToSleep(float value) => _timeToSleep = value;
|
||||
|
||||
private void SetLinearSleepTolerance(float value) => _linSleepTolerance = value;
|
||||
|
||||
private void SetAngularSleepTolerance(float value) => _angSleepTolerance = value;
|
||||
|
||||
protected override void Cleanup(float frameTime)
|
||||
{
|
||||
var toRemove = new List<PhysicsComponent>();
|
||||
@@ -36,9 +46,10 @@ namespace Robust.Client.Physics
|
||||
// Because we're not predicting 99% of bodies its sleep timer never gets incremented so we'll just do it ourselves.
|
||||
// (and serializing it over the network isn't necessary?)
|
||||
// This is a client-only problem.
|
||||
// Also need to suss out having the client build the island anyway and just... not solving it?
|
||||
foreach (var body in AwakeBodies)
|
||||
{
|
||||
if (body.Island || body.LinearVelocity.Length > 0.0001f || body.AngularVelocity != 0f) continue;
|
||||
if (body.Island || body.LinearVelocity.Length > _linSleepTolerance / 2f || body.AngularVelocity > _angSleepTolerance / 2f) continue;
|
||||
body.SleepTime += frameTime;
|
||||
if (body.SleepTime > _timeToSleep)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
@@ -11,6 +12,7 @@ namespace Robust.Client.Physics
|
||||
public class PhysicsSystem : SharedPhysicsSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IClientGameStateManager _gameState = default!;
|
||||
|
||||
private TimeSpan _lastRem;
|
||||
|
||||
@@ -22,6 +24,9 @@ namespace Robust.Client.Physics
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
if (!_gameState.IsPredictionEnabled)
|
||||
return;
|
||||
|
||||
if (_lastRem > _gameTiming.TickRemainder)
|
||||
{
|
||||
_lastRem = TimeSpan.Zero;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -125,7 +126,7 @@ namespace Robust.Client.Placement
|
||||
|
||||
public IEnumerable<EntityCoordinates> LineCoordinates()
|
||||
{
|
||||
var (x, y) = MouseCoords.ToMapPos(pManager.EntityManager) - pManager.StartPoint.ToMapPos(pManager.EntityManager);
|
||||
var (_, (x, y)) = MouseCoords.WithEntityId(pManager.StartPoint.EntityId) - pManager.StartPoint;
|
||||
float iterations;
|
||||
Vector2 distance;
|
||||
if (Math.Abs(x) > Math.Abs(y))
|
||||
@@ -148,7 +149,7 @@ namespace Robust.Client.Placement
|
||||
// This name is a nice reminder of our origins. Never forget.
|
||||
public IEnumerable<EntityCoordinates> GridCoordinates()
|
||||
{
|
||||
var placementdiff = MouseCoords.ToMapPos(pManager.EntityManager) - pManager.StartPoint.ToMapPos(pManager.EntityManager);
|
||||
var placementdiff = MouseCoords.WithEntityId(pManager.StartPoint.EntityId) - pManager.StartPoint;
|
||||
var distanceX = new Vector2(placementdiff.X > 0 ? 1 : -1, 0) * GridDistancing;
|
||||
var distanceY = new Vector2(0, placementdiff.Y > 0 ? 1 : -1) * GridDistancing;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using Robust.LoaderApi;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.ResourceManagement
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.3" />
|
||||
<PackageReference Include="nfluidsynth" Version="0.3.1" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" />
|
||||
<PackageReference Include="OpenToolkit.OpenAL" Version="4.0.0-pre9.1" />
|
||||
@@ -50,6 +49,11 @@
|
||||
<RobustLinkAssemblies Include="TerraFX.Interop.Windows" />
|
||||
<RobustLinkAssemblies Include="OpenToolkit.Graphics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="UserInterface\CustomControls\DefaultWindow.xaml.cs">
|
||||
<DependentUpon>DefaultWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="..\MSBuild\Robust.Engine.targets" />
|
||||
<PropertyGroup>
|
||||
<RobustToolsPath>../Tools</RobustToolsPath>
|
||||
|
||||
@@ -186,6 +186,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
private void Select(int idx)
|
||||
{
|
||||
if(SelectMode != ItemListSelectMode.Multiple)
|
||||
ClearSelected(idx);
|
||||
OnItemSelected?.Invoke(new ItemListSelectedEventArgs(idx, this));
|
||||
}
|
||||
|
||||
@@ -208,18 +210,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
Deselect(idx);
|
||||
}
|
||||
|
||||
public void ClearSelected()
|
||||
public void ClearSelected(int? except = null)
|
||||
{
|
||||
foreach (var item in GetSelected())
|
||||
{
|
||||
if(IndexOf(item) == except) continue;
|
||||
item.Selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SortItemsByText()
|
||||
{
|
||||
_itemList.Sort((p, q) => string.Compare(p.Text, q.Text, StringComparison.Ordinal));
|
||||
}
|
||||
public void SortItemsByText() => Sort((p, q) => string.Compare(p.Text, q.Text, StringComparison.Ordinal));
|
||||
|
||||
public void Sort(Comparison<Item> comparison) => _itemList.Sort(comparison);
|
||||
|
||||
|
||||
public void EnsureCurrentIsVisible()
|
||||
{
|
||||
@@ -447,8 +450,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
if(SelectMode != ItemListSelectMode.Multiple)
|
||||
ClearSelected();
|
||||
item.Selected = true;
|
||||
if (SelectMode == ItemListSelectMode.Button)
|
||||
Timer.Spawn(ButtonDeselectDelay, () => { item.Selected = false; } );
|
||||
|
||||
@@ -33,6 +33,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
private bool Vertical => Orientation == SplitOrientation.Vertical;
|
||||
|
||||
public SplitState State
|
||||
{
|
||||
get => _splitState;
|
||||
set
|
||||
{
|
||||
_splitState = value;
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SplitOrientation Orientation
|
||||
{
|
||||
@@ -266,7 +276,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
/// <summary>
|
||||
/// Defines how the split position should be determined
|
||||
/// </summary>
|
||||
private enum SplitState : byte
|
||||
public enum SplitState : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically adjust the split based on the width of the children
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
if (!Visible)
|
||||
{
|
||||
Visible = true;
|
||||
Logger.WarningS("ui", $"Window {this} had visibility false. Do not use visibility on SS14Window.");
|
||||
Logger.WarningS("ui", $"Window {this} had visibility false. Do not use visibility on DefaultWindow.");
|
||||
}
|
||||
|
||||
if (!IsOpen)
|
||||
|
||||
@@ -313,13 +313,13 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
Stream? stream = null;
|
||||
StreamWriter? writer = null;
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream = _resourceManager.UserData.Create(HistoryPath);
|
||||
writer = _resourceManager.UserData.OpenWriteText(HistoryPath);
|
||||
break;
|
||||
}
|
||||
catch (IOException)
|
||||
@@ -329,16 +329,18 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
}
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
if (writer == null)
|
||||
{
|
||||
sawmill.Warning("Failed to save debug console history!");
|
||||
return;
|
||||
}
|
||||
|
||||
// ReSharper disable once UseAwaitUsing
|
||||
using var writer = new StreamWriter(stream, EncodingHelpers.UTF8);
|
||||
// ReSharper disable once MethodHasAsyncOverload
|
||||
writer.Write(newHistory);
|
||||
using (writer)
|
||||
{
|
||||
// ReSharper disable once MethodHasAsyncOverload
|
||||
writer.Write(newHistory);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<SS14Window xmlns="https://spacestation14.io" MinWidth="100" MinHeight="50">
|
||||
<DefaultWindow xmlns="https://spacestation14.io" MinWidth="100" MinHeight="50">
|
||||
<PanelContainer StyleClasses="windowPanel" />
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="0">
|
||||
<PanelContainer Name="WindowHeader" StyleClasses="windowHeader">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Margin="5 0 0 0" HorizontalExpand="true" Name="TitleLabel" StyleIdentifier="foo" ClipText="True"
|
||||
Text="{Loc 'ss14window-placeholder-title'}" VAlign="Center" StyleClasses="windowTitle" />
|
||||
Text="{Loc 'defaultwindow-placeholder-title'}" VAlign="Center" StyleClasses="windowTitle" />
|
||||
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" VerticalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<Control Name="ContentsContainer" Margin="10" RectClipContent="True" VerticalExpand="true" />
|
||||
</BoxContainer>
|
||||
</SS14Window>
|
||||
</DefaultWindow>
|
||||
@@ -9,9 +9,15 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple window implementation that can be resized and has a title bar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Warning: ugly.
|
||||
/// </remarks>
|
||||
[GenerateTypedNameReferences]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public partial class SS14Window : BaseWindow
|
||||
public partial class DefaultWindow : BaseWindow
|
||||
{
|
||||
public const string StyleClassWindowTitle = "windowTitle";
|
||||
public const string StyleClassWindowPanel = "windowPanel";
|
||||
@@ -21,7 +27,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
private string? _headerClass;
|
||||
private string? _titleClass;
|
||||
|
||||
public SS14Window()
|
||||
public DefaultWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
@@ -171,9 +177,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
public class SS14ContentCollection : ICollection<Control>, IReadOnlyCollection<Control>
|
||||
{
|
||||
private readonly SS14Window Owner;
|
||||
private readonly DefaultWindow Owner;
|
||||
|
||||
public SS14ContentCollection(SS14Window owner)
|
||||
public SS14ContentCollection(DefaultWindow owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
@@ -229,9 +235,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
private OrderedChildCollection.Enumerator _enumerator;
|
||||
|
||||
internal Enumerator(SS14Window ss14Window)
|
||||
internal Enumerator(DefaultWindow DefaultWindow)
|
||||
{
|
||||
_enumerator = ss14Window.Contents.Children.GetEnumerator();
|
||||
_enumerator = DefaultWindow.Contents.Children.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||