From c4f90e56161df940e845874e1980338f8c3851fc Mon Sep 17 00:00:00 2001 From: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Date: Wed, 15 May 2024 16:08:59 -0700 Subject: [PATCH 01/10] Add an Audio Automatic Label (#408) # Description Realized while going through issues that we don't have a label for audio file changes, I've added one. --- .github/labeler.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 694c83b6025..eb01eeecc4f 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,4 +1,7 @@ -"Changes: C#": +"Changes: Audio": + - "**/*.ogg" + +"Changes: C#": - "**/*.cs" "Changes: Config": From 25397147474d173cc8251fbef0c45c4ac75807e6 Mon Sep 17 00:00:00 2001 From: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Date: Wed, 15 May 2024 16:10:36 -0700 Subject: [PATCH 02/10] Update close-master-pr Workflow's Denial Message (#347) # Description Didn't intend for this branch to be made on this repo. Improves the "close PRs from master" workflow's denial message. --- .github/workflows/close-master-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close-master-pr.yml b/.github/workflows/close-master-pr.yml index 51ce874dd07..a74e8380995 100644 --- a/.github/workflows/close-master-pr.yml +++ b/.github/workflows/close-master-pr.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: superbrothers/close-pull-request@v3 with: - comment: "Thank you for contributing to the Space Station 14 repository. Unfortunately, it looks like you submitted your pull request from the master branch. We suggest you follow [our git usage documentation](https://docs.spacestation14.com/en/general-development/setup/git-for-the-ss14-developer.html) \n\n You can move your current work from the master branch to another branch by doing `git branch Date: Sat, 18 May 2024 15:37:54 -0700 Subject: [PATCH 03/10] Build/Run Scripts from Parkstation (#6) # Description Adds several scripts to make building and running the projects easier outside of an IDE. --- Scripts/bat/!README.txt | 25 +++++++++++++++++++++++++ Scripts/bat/buildAllDebug.bat | 8 ++++++++ Scripts/bat/buildAllRelease.bat | 8 ++++++++ Scripts/bat/buildAllTools.bat | 8 ++++++++ Scripts/bat/runQuickAll.bat | 6 ++++++ Scripts/bat/runQuickClient.bat | 6 ++++++ Scripts/bat/runQuickServer.bat | 6 ++++++ Scripts/bat/runTests.bat | 8 ++++++++ Scripts/bat/runTestsIntegration.bat | 8 ++++++++ Scripts/bat/runTestsYAML.bat | 8 ++++++++ Scripts/sh/!README.txt | 25 +++++++++++++++++++++++++ Scripts/sh/buildAllDebug.sh | 12 ++++++++++++ Scripts/sh/buildAllRelease.sh | 12 ++++++++++++ Scripts/sh/buildAllTools.sh | 12 ++++++++++++ Scripts/sh/runQuickAll.sh | 11 +++++++++++ Scripts/sh/runQuickClient.sh | 9 +++++++++ Scripts/sh/runQuickServer.sh | 9 +++++++++ Scripts/sh/runTests.sh | 9 +++++++++ Scripts/sh/runTestsIntegration.sh | 9 +++++++++ Scripts/sh/runTestsYAML.sh | 9 +++++++++ runclient.bat | 6 ------ runserver.bat | 7 ------- 22 files changed, 208 insertions(+), 13 deletions(-) create mode 100755 Scripts/bat/!README.txt create mode 100755 Scripts/bat/buildAllDebug.bat create mode 100755 Scripts/bat/buildAllRelease.bat create mode 100755 Scripts/bat/buildAllTools.bat create mode 100755 Scripts/bat/runQuickAll.bat create mode 100755 Scripts/bat/runQuickClient.bat create mode 100755 Scripts/bat/runQuickServer.bat create mode 100755 Scripts/bat/runTests.bat create mode 100755 Scripts/bat/runTestsIntegration.bat create mode 100755 Scripts/bat/runTestsYAML.bat create mode 100755 Scripts/sh/!README.txt create mode 100755 Scripts/sh/buildAllDebug.sh create mode 100755 Scripts/sh/buildAllRelease.sh create mode 100755 Scripts/sh/buildAllTools.sh create mode 100755 Scripts/sh/runQuickAll.sh create mode 100755 Scripts/sh/runQuickClient.sh create mode 100755 Scripts/sh/runQuickServer.sh create mode 100755 Scripts/sh/runTests.sh create mode 100755 Scripts/sh/runTestsIntegration.sh create mode 100755 Scripts/sh/runTestsYAML.sh delete mode 100644 runclient.bat delete mode 100644 runserver.bat diff --git a/Scripts/bat/!README.txt b/Scripts/bat/!README.txt new file mode 100755 index 00000000000..a8ba0d77ae3 --- /dev/null +++ b/Scripts/bat/!README.txt @@ -0,0 +1,25 @@ +buildAllDebug + Builds all projects with debug configuration +buildAllRelease + Builds all projects with release configuration +buildAllTools + Builds all projects with tools configuration + +The debug vs release build is simply what people develop in vs the actual server. +The release build contains various optimizations, while the debug build contains debugging tools. +If you're mapping, use the release or tools build as it will run smoother with less crashes. + + +runQuickAll + Runs the client and server without building +runQuickClient + Runs the client without building +runQuickServer + Runs the server without building + +runTests + Runs the unit tests, makes sure various C# systems work as intended +runTestsIntegration + Runs the integration tests, makes sure various C# systems work as intended +runTestsYAML + Runs the YAML linter and finds issues with the YAML files that you probably wouldn't otherwise diff --git a/Scripts/bat/buildAllDebug.bat b/Scripts/bat/buildAllDebug.bat new file mode 100755 index 00000000000..5cf49521753 --- /dev/null +++ b/Scripts/bat/buildAllDebug.bat @@ -0,0 +1,8 @@ +@echo off +cd ../../ + +call python RUN_THIS.py +call git submodule update --init --recursive +call dotnet build -c Debug + +pause diff --git a/Scripts/bat/buildAllRelease.bat b/Scripts/bat/buildAllRelease.bat new file mode 100755 index 00000000000..6a8cbac6648 --- /dev/null +++ b/Scripts/bat/buildAllRelease.bat @@ -0,0 +1,8 @@ +@echo off +cd ../../ + +call python RUN_THIS.py +call git submodule update --init --recursive +call dotnet build -c Release + +pause diff --git a/Scripts/bat/buildAllTools.bat b/Scripts/bat/buildAllTools.bat new file mode 100755 index 00000000000..7c878cbabb5 --- /dev/null +++ b/Scripts/bat/buildAllTools.bat @@ -0,0 +1,8 @@ +@echo off +cd ../../ + +call python RUN_THIS.py +call git submodule update --init --recursive +call dotnet build -c Tools + +pause diff --git a/Scripts/bat/runQuickAll.bat b/Scripts/bat/runQuickAll.bat new file mode 100755 index 00000000000..26884f1d0bf --- /dev/null +++ b/Scripts/bat/runQuickAll.bat @@ -0,0 +1,6 @@ +@echo off + +start runQuickServer.bat %* +start runQuickClient.bat %* + +exit diff --git a/Scripts/bat/runQuickClient.bat b/Scripts/bat/runQuickClient.bat new file mode 100755 index 00000000000..172fd1ce6e9 --- /dev/null +++ b/Scripts/bat/runQuickClient.bat @@ -0,0 +1,6 @@ +@echo off +cd ../../ + +call dotnet run --project Content.Client --no-build %* + +pause diff --git a/Scripts/bat/runQuickServer.bat b/Scripts/bat/runQuickServer.bat new file mode 100755 index 00000000000..ca61ef6b2c9 --- /dev/null +++ b/Scripts/bat/runQuickServer.bat @@ -0,0 +1,6 @@ +@echo off +cd ../../ + +call dotnet run --project Content.Server --no-build %* + +pause diff --git a/Scripts/bat/runTests.bat b/Scripts/bat/runTests.bat new file mode 100755 index 00000000000..4d46d728da7 --- /dev/null +++ b/Scripts/bat/runTests.bat @@ -0,0 +1,8 @@ +cd ..\..\ + +mkdir Scripts\logs + +del Scripts\logs\Content.Tests.log +dotnet test Content.Tests/Content.Tests.csproj -c DebugOpt -- NUnit.ConsoleOut=0 > Scripts\logs\Content.Tests.log + +pause diff --git a/Scripts/bat/runTestsIntegration.bat b/Scripts/bat/runTestsIntegration.bat new file mode 100755 index 00000000000..39aa4cac5cd --- /dev/null +++ b/Scripts/bat/runTestsIntegration.bat @@ -0,0 +1,8 @@ +cd ..\..\ + +mkdir Scripts\logs + +del Scripts\logs\Content.IntegrationTests.log +dotnet test Content.IntegrationTests/Content.IntegrationTests.csproj -c DebugOpt -- NUnit.ConsoleOut=0 NUnit.MapWarningTo=Failed > Scripts\logs\Content.IntegrationTests.log + +pause diff --git a/Scripts/bat/runTestsYAML.bat b/Scripts/bat/runTestsYAML.bat new file mode 100755 index 00000000000..8b41dd61b85 --- /dev/null +++ b/Scripts/bat/runTestsYAML.bat @@ -0,0 +1,8 @@ +cd ..\..\ + +mkdir Scripts\logs + +del Scripts\logs\Content.YAMLLinter.log +dotnet run --project Content.YAMLLinter/Content.YAMLLinter.csproj -c DebugOpt -- NUnit.ConsoleOut=0 > Scripts\logs\Content.YAMLLinter.log + +pause diff --git a/Scripts/sh/!README.txt b/Scripts/sh/!README.txt new file mode 100755 index 00000000000..a8ba0d77ae3 --- /dev/null +++ b/Scripts/sh/!README.txt @@ -0,0 +1,25 @@ +buildAllDebug + Builds all projects with debug configuration +buildAllRelease + Builds all projects with release configuration +buildAllTools + Builds all projects with tools configuration + +The debug vs release build is simply what people develop in vs the actual server. +The release build contains various optimizations, while the debug build contains debugging tools. +If you're mapping, use the release or tools build as it will run smoother with less crashes. + + +runQuickAll + Runs the client and server without building +runQuickClient + Runs the client without building +runQuickServer + Runs the server without building + +runTests + Runs the unit tests, makes sure various C# systems work as intended +runTestsIntegration + Runs the integration tests, makes sure various C# systems work as intended +runTestsYAML + Runs the YAML linter and finds issues with the YAML files that you probably wouldn't otherwise diff --git a/Scripts/sh/buildAllDebug.sh b/Scripts/sh/buildAllDebug.sh new file mode 100755 index 00000000000..1ee457ff2ae --- /dev/null +++ b/Scripts/sh/buildAllDebug.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +cd ../../ + +python RUN_THIS.py +git submodule update --init --recursive +dotnet build -c Debug diff --git a/Scripts/sh/buildAllRelease.sh b/Scripts/sh/buildAllRelease.sh new file mode 100755 index 00000000000..b3749ac28d8 --- /dev/null +++ b/Scripts/sh/buildAllRelease.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +cd ../../ + +python RUN_THIS.py +git submodule update --init --recursive +dotnet build -c Release diff --git a/Scripts/sh/buildAllTools.sh b/Scripts/sh/buildAllTools.sh new file mode 100755 index 00000000000..14a68487afe --- /dev/null +++ b/Scripts/sh/buildAllTools.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +cd ../../ + +python RUN_THIS.py +git submodule update --init --recursive +dotnet build -c Tools diff --git a/Scripts/sh/runQuickAll.sh b/Scripts/sh/runQuickAll.sh new file mode 100755 index 00000000000..49eb5ab8d22 --- /dev/null +++ b/Scripts/sh/runQuickAll.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +sh -e runQuickServer.sh & +sh -e runQuickClient.sh + +exit diff --git a/Scripts/sh/runQuickClient.sh b/Scripts/sh/runQuickClient.sh new file mode 100755 index 00000000000..080c78f27ca --- /dev/null +++ b/Scripts/sh/runQuickClient.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +cd ../../ +dotnet run --project Content.Client --no-build diff --git a/Scripts/sh/runQuickServer.sh b/Scripts/sh/runQuickServer.sh new file mode 100755 index 00000000000..b264ff6fc7b --- /dev/null +++ b/Scripts/sh/runQuickServer.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +# make sure to start from script dir +if [ "$(dirname $0)" != "." ]; then + cd "$(dirname $0)" +fi + +cd ../../ +dotnet run --project Content.Server --no-build diff --git a/Scripts/sh/runTests.sh b/Scripts/sh/runTests.sh new file mode 100755 index 00000000000..bf6fc0f5bba --- /dev/null +++ b/Scripts/sh/runTests.sh @@ -0,0 +1,9 @@ +cd ../../ + +mkdir Scripts/logs + +rm Scripts/logs/Content.Tests.log +dotnet test Content.Tests/Content.Tests.csproj -c DebugOpt -- NUnit.ConsoleOut=0 > Scripts/logs/Content.Tests.log + +echo "Tests complete. Press enter to continue." +read diff --git a/Scripts/sh/runTestsIntegration.sh b/Scripts/sh/runTestsIntegration.sh new file mode 100755 index 00000000000..c6db14c252a --- /dev/null +++ b/Scripts/sh/runTestsIntegration.sh @@ -0,0 +1,9 @@ +cd ../../ + +mkdir Scripts/logs + +rm Scripts/logs/Content.IntegrationTests.log +dotnet test Content.IntegrationTests/Content.IntegrationTests.csproj -c DebugOpt -- NUnit.ConsoleOut=0 NUnit.MapWarningTo=Failed > Scripts/logs/Content.IntegrationTests.log + +echo "Tests complete. Press enter to continue." +read diff --git a/Scripts/sh/runTestsYAML.sh b/Scripts/sh/runTestsYAML.sh new file mode 100755 index 00000000000..5a4b09bf4b4 --- /dev/null +++ b/Scripts/sh/runTestsYAML.sh @@ -0,0 +1,9 @@ +cd ../../ + +mkdir Scripts/logs + +rm Scripts/logs/Content.YAMLLinter.log +dotnet run --project Content.YAMLLinter/Content.YAMLLinter.csproj -c DebugOpt -- NUnit.ConsoleOut=0 > Scripts/logs/Content.YAMLLinter.log + +echo "Tests complete. Press enter to continue." +read diff --git a/runclient.bat b/runclient.bat deleted file mode 100644 index f580d41e9d6..00000000000 --- a/runclient.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -set PDIR=%~dp0 -cd %PDIR%Bin\Content.Client -start Content.Client.exe %* -cd %PDIR% -set PDIR= diff --git a/runserver.bat b/runserver.bat deleted file mode 100644 index 573de0a15d8..00000000000 --- a/runserver.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -set PDIR=%~dp0 -cd %PDIR%Bin\Content.Server -call Content.Server.exe %* -cd %PDIR% -set PDIR= -pause From a866a4872001f265731978629af50df2b655b99d Mon Sep 17 00:00:00 2001 From: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Date: Sat, 18 May 2024 15:38:06 -0700 Subject: [PATCH 04/10] Temporary CI/CD Fix (#411) # Description Ports https://github.com/DeltaV-Station/Delta-v/commit/7e3ba621d325db4d838c4d0fb675b5173f3111df until we get the real fix. Should allow tests to run, though it still fails most of the time according to Null. Co-authored-by: Null <56081759+NullWanderer@users.noreply.github.com> --- .github/workflows/build-map-renderer.yml | 2 +- .github/workflows/build-test-debug.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test-packaging.yml | 2 +- .github/workflows/yaml-linter.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-map-renderer.yml b/.github/workflows/build-map-renderer.yml index 45c807b3624..c1790feadb8 100644 --- a/.github/workflows/build-map-renderer.yml +++ b/.github/workflows/build-map-renderer.yml @@ -36,7 +36,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Install dependencies run: dotnet restore diff --git a/.github/workflows/build-test-debug.yml b/.github/workflows/build-test-debug.yml index c3b766f8de8..bb0624e3ba0 100644 --- a/.github/workflows/build-test-debug.yml +++ b/.github/workflows/build-test-debug.yml @@ -36,7 +36,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Install dependencies run: dotnet restore diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 74a975be5c6..177e6a0fe6d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Get Engine Tag run: | diff --git a/.github/workflows/test-packaging.yml b/.github/workflows/test-packaging.yml index b35a6092202..27cf5d2d7b1 100644 --- a/.github/workflows/test-packaging.yml +++ b/.github/workflows/test-packaging.yml @@ -51,7 +51,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Install dependencies run: dotnet restore diff --git a/.github/workflows/yaml-linter.yml b/.github/workflows/yaml-linter.yml index f60945ae7ce..8660ccc0407 100644 --- a/.github/workflows/yaml-linter.yml +++ b/.github/workflows/yaml-linter.yml @@ -26,7 +26,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Install dependencies run: dotnet restore - name: Build From c62f777aee0c5e28df70953f77de950009e42c13 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 19:19:09 -0700 Subject: [PATCH 05/10] Update Credits (#412) This is an automated Pull Request. This PR updates the GitHub contributors in the credits section. Co-authored-by: SimpleStation Changelogs --- Resources/Credits/GitHub.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index ce93c10d338..3aea674fd94 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem From 6e0ffe81bc2a1be3e9d0453b8597a8f92df41dc1 Mon Sep 17 00:00:00 2001 From: SimpleStation14 <130339894+SimpleStation14@users.noreply.github.com> Date: Sun, 19 May 2024 23:33:00 -0700 Subject: [PATCH 06/10] Mirror: Partial atmos refactor (#312) ## Mirror of PR #22521: [Partial atmos refactor](https://github.com/space-wizards/space-station-14/pull/22521) from space-wizards [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `18a35e7e83b2b71ee84b054d44d9ed5e595dd618` PR opened by ElectroJr at 2023-12-15 03:45:42 UTC --- PR changed 43 files with 891 additions and 635 deletions. The PR had the following labels: - Status: Needs Review ---

Original Body

> This PR reworks how some parts of atmos code work. Originally it was just meant to be a performance and bugfix PR, but it has ballooned in scope. I'm not sure about some of my changes largely because I'm not sure if some things were an oversight or an intentional decision for some reason. > > List of changes: > - The `MolesArchived float[]` field is now read-only > - It simply gets zeroed whenever the `GasMixture` is set to null instead of constantly reallocating > - Airtight query information is now cached in `TileAtmosphere` > - This means that it should only iterate over anchored entities once per update. > - Previously an invalidated atmos tile would cause `ProcessRevalidate()` to query airtight entities on the same tile six times by calling a combination of `GridIsTileAirBlocked()`, `NeedsVacuumFixing()`, and `GridIsTileAirBlocked()`. So this should help significantly reduce component lookups & entity enumeration. > - This does change some behaviour. In particular blocked directions are now only updated if the tile was invalidated prior to the current atmos-update, and will only ever be updated once per atmos-update. > - AFAIK this only has an effect if the invalid tile processing is deferred over multiple ticks, and I don't think it should cause any issues? > - Fixes a potential bug, where tiles might not dispose of their excited group if their direction flags changed. > - `MapAtmosphereComponent.Mixture` is now always immutable and no longer nullable > - I'm not sure why the mixture was nullable before? AFAICT the component is meaningless if its null? > - Space "gas" was always immutable, but there was nothing that required planet atmospheres to be immutable. Requiring that it be immutable gets rid of the constant gas mixture cloning. > - I don't know if there was a reason for why they weren't immutable to begin with. > - Fixes lungs removing too much air from a gas mixture, resulting in negative moles. > - `GasMixture.Moles` is now `[Access]` restricted to the atmosphere system. > - This is to prevent people from improperly modifying the gas mixtures (e.g., lungs), or accidentally modifying immutable mixtures. > - Fixes an issue where non-grid atmosphere tiles would fail to update their adjacent tiles, resulting in null reference exception spam > - Fixes #21732 > - Fixes #21210 (probably) > - Disconnected atmosphere tiles, i.e., tiles that aren't on or adjacent to a grid tile, will now get removed from the tile set. Previously the tile set would just always increase, with tiles never getting removed. > - Removes various redundant component and tile-definition queries. > - Removes some method events in favour of just using methods. > - Map-exposded tiles now get updated when a map's atmosphere changes (or the grid moves across maps). > - Adds a `setmapatmos` command for adding map-wide atmospheres. > - Fixed (non-planet) map atmospheres rendering over grids. > > ## Media > > This PR also includes changes to the atmos debug overlay, though I've also split that off into a separate PR to make reviewing easier (#22520). > > Below is a video showing that atmos still seems to work, and that trimming of disconnected tiles works: > > https://github.com/space-wizards/space-station-14/assets/60421075/4da46992-19e6-4354-8ecd-3cd67be4d0ed > > For comparison, here is a video showing how current master works (disconnected tiles never get removed): > > https://github.com/space-wizards/space-station-14/assets/60421075/54590777-e11c-41dc-b49d-fd7e53bfeed7 > > :cl: > - fix: Fixed a bug where partially airtight entities (e.g., thin windows or doors) could let air leak out into space. >
Co-authored-by: SimpleStation14 --- .../Atmos/Overlays/GasTileOverlay.cs | 70 ++-- Content.Client/Mapping/MappingSystem.cs | 2 +- .../Tests/Body/LungTest.cs | 2 +- .../Interaction/InteractionTest.Helpers.cs | 7 +- .../Atmos/Commands/SetMapAtmosCommand.cs | 94 +++++ .../Atmos/Components/AirtightComponent.cs | 4 +- .../Components/GridAtmosphereComponent.cs | 8 +- .../Components/MapAtmosphereComponent.cs | 8 +- .../Atmos/EntitySystems/AirtightSystem.cs | 18 +- .../EntitySystems/AtmosDebugOverlaySystem.cs | 11 +- .../AtmosObstructionEnumerator.cs | 37 -- .../EntitySystems/AtmosphereSystem.API.cs | 45 +-- .../AtmosphereSystem.ExcitedGroup.cs | 28 +- .../AtmosphereSystem.GridAtmosphere.cs | 247 +++++--------- .../AtmosphereSystem.HighPressureDelta.cs | 2 - .../EntitySystems/AtmosphereSystem.LINDA.cs | 18 +- .../EntitySystems/AtmosphereSystem.Map.cs | 108 +++++- .../AtmosphereSystem.Monstermos.cs | 110 +++--- .../AtmosphereSystem.Processing.cs | 323 ++++++++++++------ .../AtmosphereSystem.Superconductivity.cs | 8 +- .../EntitySystems/AtmosphereSystem.Utils.cs | 62 ++-- .../Atmos/EntitySystems/AtmosphereSystem.cs | 7 + .../EntitySystems/AutomaticAtmosSystem.cs | 8 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 4 +- .../EntitySystems/GasTileOverlaySystem.cs | 6 +- Content.Server/Atmos/GasMixture.cs | 57 +++- .../Unary/EntitySystems/GasCanisterSystem.cs | 2 +- .../Unary/EntitySystems/GasCondenserSystem.cs | 2 +- .../TileAtmosCollectionSerializer.cs | 8 +- Content.Server/Atmos/TileAtmosphere.cs | 53 ++- Content.Server/Body/Systems/LungSystem.cs | 2 +- .../Chemistry/ReagentEffects/ModifyLungGas.cs | 13 +- .../Conditions/ComponentInTile.cs | 11 +- .../ExplosionSystem.Processing.cs | 4 +- Content.Server/Parallax/BiomeSystem.cs | 11 +- .../Power/Generator/GasPowerReceiverSystem.cs | 2 +- .../Salvage/SpawnSalvageMissionJob.cs | 6 +- Content.Server/Spreader/SpreaderSystem.cs | 69 ++-- Content.Shared/Atmos/Atmospherics.cs | 7 +- .../SharedGasTileOverlaySystem.cs | 3 + Content.Shared/Maps/ContentTileDefinition.cs | 6 +- Content.Shared/Maps/TurfHelpers.cs | 27 +- Resources/Locale/en-US/atmos/commands.ftl | 8 + 43 files changed, 892 insertions(+), 636 deletions(-) create mode 100644 Content.Server/Atmos/Commands/SetMapAtmosCommand.cs delete mode 100644 Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs create mode 100644 Resources/Locale/en-US/atmos/commands.ftl diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs index ef65d43fe85..f4dc274a4e5 100644 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs @@ -8,7 +8,6 @@ using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; -using Robust.Shared.Graphics; using Robust.Shared.Graphics.RSI; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -23,7 +22,7 @@ public sealed class GasTileOverlay : Overlay private readonly IEntityManager _entManager; private readonly IMapManager _mapManager; - public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities; + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; private readonly ShaderInstance _shader; // Gas overlays @@ -79,7 +78,8 @@ public GasTileOverlay(GasTileOverlaySystem system, IEntityManager entManager, IR var rsi = resourceCache.GetResource(animated.RsiPath).RSI; var stateId = animated.RsiState; - if (!rsi.TryGetState(stateId, out var state)) continue; + if (!rsi.TryGetState(stateId, out var state)) + continue; _frames[i] = state.GetFrames(RsiDirection.South); _frameDelays[i] = state.GetDelays(); @@ -111,7 +111,8 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < _gasCount; i++) { var delays = _frameDelays[i]; - if (delays.Length == 0) continue; + if (delays.Length == 0) + continue; var frameCount = _frameCounter[i]; _timer[i] += args.DeltaSeconds; @@ -127,7 +128,8 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < FireStates; i++) { var delays = _fireFrameDelays[i]; - if (delays.Length == 0) continue; + if (delays.Length == 0) + continue; var frameCount = _fireFrameCounter[i]; _fireTimer[i] += args.DeltaSeconds; @@ -161,26 +163,10 @@ protected override void Draw(in OverlayDrawArgs args) var mapUid = _mapManager.GetMapEntityId(args.MapId); if (_entManager.TryGetComponent(mapUid, out var atmos)) - { - var bottomLeft = args.WorldAABB.BottomLeft.Floored(); - var topRight = args.WorldAABB.TopRight.Ceiled(); - - for (var x = bottomLeft.X; x <= topRight.X; x++) - { - for (var y = bottomLeft.Y; y <= topRight.Y; y++) - { - var tilePosition = new Vector2(x, y); - - for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) - { - var opacity = atmos.OverlayData.Opacity[i]; + DrawMapOverlay(drawHandle, args, mapUid, atmos); - if (opacity > 0) - args.WorldHandle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); - } - } - } - } + if (args.Space != OverlaySpace.WorldSpaceEntities) + return; // TODO: WorldBounds callback. _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, @@ -265,5 +251,41 @@ protected override void Draw(in OverlayDrawArgs args) drawHandle.UseShader(null); drawHandle.SetTransform(Matrix3.Identity); } + + private void DrawMapOverlay( + DrawingHandleWorld handle, + OverlayDrawArgs args, + EntityUid map, + MapAtmosphereComponent atmos) + { + var mapGrid = _entManager.HasComponent(map); + + // map-grid atmospheres get drawn above grids + if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities) + return; + + // Normal map atmospheres get drawn below grids + if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld) + return; + + var bottomLeft = args.WorldAABB.BottomLeft.Floored(); + var topRight = args.WorldAABB.TopRight.Ceiled(); + + for (var x = bottomLeft.X; x <= topRight.X; x++) + { + for (var y = bottomLeft.Y; y <= topRight.Y; y++) + { + var tilePosition = new Vector2(x, y); + + for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) + { + var opacity = atmos.OverlayData.Opacity[i]; + + if (opacity > 0) + handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); + } + } + } + } } } diff --git a/Content.Client/Mapping/MappingSystem.cs b/Content.Client/Mapping/MappingSystem.cs index 4456be36a65..8daf193dfeb 100644 --- a/Content.Client/Mapping/MappingSystem.cs +++ b/Content.Client/Mapping/MappingSystem.cs @@ -83,7 +83,7 @@ private void OnFillActionSlot(FillActionSlotEvent ev) if (tileDef is not ContentTileDefinition contentTileDef) return; - var tileIcon = contentTileDef.IsSpace + var tileIcon = contentTileDef.MapAtmosphere ? _spaceIcon : new Texture(contentTileDef.Sprite!.Value); diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index d0325480acd..f2e19849b00 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -128,7 +128,7 @@ await server.WaitAssertion(() => metaSys.Update(1.0f); metaSys.Update(1.0f); respSys.Update(2.0f); - Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0001)); + Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002)); }); } diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 84e1afaf45c..88448e7b800 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -1006,15 +1006,10 @@ protected async Task AddAtmosphere(EntityUid? uid = null) await Server.WaitPost(() => { var atmosSystem = SEntMan.System(); - var atmos = SEntMan.EnsureComponent(target); var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - atmosSystem.SetMapAtmosphere(target, false, new GasMixture(2500) - { - Temperature = 293.15f, - Moles = moles, - }, atmos); + atmosSystem.SetMapAtmosphere(target, false, new GasMixture(moles, Atmospherics.T20C)); }); } diff --git a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs new file mode 100644 index 00000000000..6f04cfb2da6 --- /dev/null +++ b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs @@ -0,0 +1,94 @@ +using Content.Server.Administration; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Administration; +using Content.Shared.Atmos; +using Robust.Shared.Console; +using Robust.Shared.Map; + +namespace Content.Server.Atmos.Commands; + +[AdminCommand(AdminFlags.Admin)] +public sealed class AddMapAtmosCommand : LocalizedCommands +{ + [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IMapManager _map = default!; + + private const string _cmd = "cmd-set-map-atmos"; + public override string Command => "setmapatmos"; + public override string Description => Loc.GetString($"{_cmd}-desc"); + public override string Help => Loc.GetString($"{_cmd}-help"); + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length < 2) + { + shell.WriteLine(Help); + return; + } + + int.TryParse(args[0], out var id); + var map = _map.GetMapEntityId(new MapId(id)); + if (!map.IsValid()) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", args[0]))); + return; + } + + if (!bool.TryParse(args[1], out var space)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-bool", ("arg", args[1]))); + return; + } + + if (space || args.Length < 4) + { + _entities.RemoveComponent(map); + shell.WriteLine(Loc.GetString($"{_cmd}-removed", ("map", id))); + return; + } + + if (!float.TryParse(args[2], out var temp)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2]))); + return; + } + + var mix = new GasMixture(Atmospherics.CellVolume) {Temperature = Math.Min(temp, Atmospherics.TCMB)}; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + if (args.Length == 3 + i) + break; + + if (!float.TryParse(args[3+i], out var moles)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3+i]))); + return; + } + + mix.AdjustMoles(i, moles); + } + + var atmos = _entities.EntitySysManager.GetEntitySystem(); + atmos.SetMapAtmosphere(map, space, mix); + shell.WriteLine(Loc.GetString($"{_cmd}-updated", ("map", id))); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + if (args.Length == 1) + return CompletionResult.FromHintOptions(CompletionHelper.MapIds(_entities), Loc.GetString($"{_cmd}-hint-map")); + + if (args.Length == 2) + return CompletionResult.FromHintOptions(new[]{ "false", "true"}, Loc.GetString($"{_cmd}-hint-space")); + + if (!bool.TryParse(args[1], out var space) || space) + return CompletionResult.Empty; + + if (args.Length == 3) + return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-temp")); + + var gas = (Gas) args.Length - 4; + return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-gas" , ("gas", gas.ToString()))); + } +} diff --git a/Content.Server/Atmos/Components/AirtightComponent.cs b/Content.Server/Atmos/Components/AirtightComponent.cs index 897981724c9..ca107eafbe8 100644 --- a/Content.Server/Atmos/Components/AirtightComponent.cs +++ b/Content.Server/Atmos/Components/AirtightComponent.cs @@ -1,9 +1,10 @@ +using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Atmos.Components { - [RegisterComponent] + [RegisterComponent, Access(typeof(AirtightSystem))] public sealed partial class AirtightComponent : Component { public (EntityUid Grid, Vector2i Tile) LastPosition { get; set; } @@ -29,6 +30,7 @@ public sealed partial class AirtightComponent : Component [DataField("noAirWhenFullyAirBlocked")] public bool NoAirWhenFullyAirBlocked { get; set; } = true; + [Access(Other = AccessPermissions.ReadWriteExecute)] public AtmosDirection AirBlockedDirection => (AtmosDirection)CurrentAirBlockedDirection; } } diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index 7fcd63bc5d8..e682fd09644 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -28,6 +28,9 @@ public sealed partial class GridAtmosphereComponent : Component [IncludeDataField(customTypeSerializer:typeof(TileAtmosCollectionSerializer))] public Dictionary Tiles = new(1000); + [ViewVariables] + public HashSet MapTiles = new(1000); + [ViewVariables] public readonly HashSet ActiveTiles = new(1000); @@ -80,7 +83,10 @@ public sealed partial class GridAtmosphereComponent : Component public readonly HashSet InvalidatedCoords = new(1000); [ViewVariables] - public readonly Queue CurrentRunInvalidatedCoordinates = new(); + public readonly Queue CurrentRunInvalidatedTiles = new(); + + [ViewVariables] + public readonly List PossiblyDisconnectedTiles = new(100); [ViewVariables] public int InvalidatedCoordsCount => InvalidatedCoords.Count; diff --git a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs index bbf5ea6403e..6bdef901d44 100644 --- a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs @@ -12,12 +12,14 @@ public sealed partial class MapAtmosphereComponent : SharedMapAtmosphereComponen /// /// The default GasMixture a map will have. Space mixture by default. /// - [DataField("mixture"), ViewVariables(VVAccess.ReadWrite)] - public GasMixture? Mixture = GasMixture.SpaceGas; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public GasMixture Mixture = GasMixture.SpaceGas; /// /// Whether empty tiles will be considered space or not. /// - [DataField("space"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool Space = true; + + public SharedGasTileOverlaySystem.GasOverlayData Overlay; } diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index 97dccbaabb7..548d6a36926 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Explosion.EntitySystems; using Content.Shared.Atmos; using JetBrains.Annotations; -using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems @@ -10,7 +9,7 @@ namespace Content.Server.Atmos.EntitySystems [UsedImplicitly] public sealed class AirtightSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ExplosionSystem _explosionSystem = default!; @@ -121,19 +120,16 @@ public void UpdatePosition(Entity ent, TransformComponent? xf if (!xform.Anchored || !TryComp(xform.GridUid, out MapGridComponent? grid)) return; - airtight.LastPosition = (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)); - InvalidatePosition(airtight.LastPosition.Item1, airtight.LastPosition.Item2, airtight.FixVacuum && !airtight.AirBlocked); + var indices = _transform.GetGridTilePositionOrDefault((ent, xform), grid); + airtight.LastPosition = (xform.GridUid.Value, indices); + InvalidatePosition((xform.GridUid.Value, grid), indices); } - public void InvalidatePosition(EntityUid gridId, Vector2i pos, bool fixVacuum = false) + public void InvalidatePosition(Entity grid, Vector2i pos) { - if (!TryComp(gridId, out MapGridComponent? grid)) - return; - var query = EntityManager.GetEntityQuery(); - _explosionSystem.UpdateAirtightMap(gridId, pos, grid, query); - // TODO make atmos system use query - _atmosphereSystem.InvalidateTile(gridId, pos); + _explosionSystem.UpdateAirtightMap(grid, pos, grid, query); + _atmosphereSystem.InvalidateTile(grid.Owner, pos); } private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle) diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index 4af32fce58f..c0284f26c90 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -97,22 +97,19 @@ private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) } } - private AtmosDebugOverlayData ConvertTileToData(TileAtmosphere? tile) + private AtmosDebugOverlayData? ConvertTileToData(TileAtmosphere tile) { - if (tile == null) - return default; - return new AtmosDebugOverlayData( tile.GridIndices, tile.Air?.Temperature ?? default, tile.Air?.Moles, tile.PressureDirection, tile.LastPressureDirection, - tile.BlockedAirflow, + tile.AirtightData.BlockedDirections, tile.ExcitedGroup?.GetHashCode(), tile.Space, - false, - false); + tile.MapAtmosphere, + tile.NoGridTile); } public override void Update(float frameTime) diff --git a/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs b/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs deleted file mode 100644 index aed009e9a12..00000000000 --- a/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Atmos.Components; -using Robust.Shared.Map; -using Robust.Shared.Map.Enumerators; - -namespace Content.Server.Atmos.EntitySystems; - -public struct AtmosObstructionEnumerator -{ - private AnchoredEntitiesEnumerator _enumerator; - private EntityQuery _query; - - public AtmosObstructionEnumerator(AnchoredEntitiesEnumerator enumerator, EntityQuery query) - { - _enumerator = enumerator; - _query = query; - } - - public bool MoveNext([NotNullWhen(true)] out AirtightComponent? airtight) - { - if (!_enumerator.MoveNext(out var uid)) - { - airtight = null; - return false; - } - - // No rider, it makes it uglier. - // ReSharper disable once ConvertIfStatementToReturnStatement - if (!_query.TryGetComponent(uid.Value, out airtight)) - { - // ReSharper disable once TailRecursiveCall - return MoveNext(out airtight); - } - - return true; - } -} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 310e602336a..cece99cacf6 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -85,10 +85,10 @@ public IEnumerable GetAllMixtures(EntityUid gridUid, bool excite = f return ev.Mixtures!; } - public void InvalidateTile(EntityUid gridUid, Vector2i tile) + public void InvalidateTile(Entity entity, Vector2i tile) { - var ev = new InvalidateTileMethodEvent(gridUid, tile); - RaiseLocalEvent(gridUid, ref ev); + if (_atmosQuery.Resolve(entity.Owner, ref entity.Comp, false)) + entity.Comp.InvalidatedCoords.Add(tile); } public GasMixture?[]? GetTileMixtures(EntityUid? gridUid, EntityUid? mapUid, List tiles, bool excite = false) @@ -176,11 +176,11 @@ public ReactionResult ReactTile(EntityUid gridId, Vector2i tile) public bool IsTileAirBlocked(EntityUid gridUid, Vector2i tile, AtmosDirection directions = AtmosDirection.All, MapGridComponent? mapGridComp = null) { - var ev = new IsTileAirBlockedMethodEvent(gridUid, tile, directions, mapGridComp); - RaiseLocalEvent(gridUid, ref ev); + if (!Resolve(gridUid, ref mapGridComp)) + return false; - // If nothing handled the event, it'll default to true. - return ev.Result; + var data = GetAirtightData(gridUid, mapGridComp, tile); + return data.BlockedDirections.IsFlagSet(directions); } public bool IsTileSpace(EntityUid? gridUid, EntityUid? mapUid, Vector2i tile, MapGridComponent? mapGridComp = null) @@ -231,12 +231,6 @@ public IEnumerable GetAdjacentTileMixtures(EntityUid gridUid, Vector return ev.Result ?? Enumerable.Empty(); } - public void UpdateAdjacent(EntityUid gridUid, Vector2i tile, MapGridComponent? mapGridComp = null) - { - var ev = new UpdateAdjacentMethodEvent(gridUid, tile, mapGridComp); - RaiseLocalEvent(gridUid, ref ev); - } - public void HotspotExpose(EntityUid gridUid, Vector2i tile, float exposedTemperature, float exposedVolume, EntityUid? sparkSourceUid = null, bool soh = false) { @@ -259,12 +253,6 @@ public bool IsHotspotActive(EntityUid gridUid, Vector2i tile) return ev.Result; } - public void FixTileVacuum(EntityUid gridUid, Vector2i tile) - { - var ev = new FixTileVacuumMethodEvent(gridUid, tile); - RaiseLocalEvent(gridUid, ref ev); - } - public void AddPipeNet(EntityUid gridUid, PipeNet pipeNet) { var ev = new AddPipeNetMethodEvent(gridUid, pipeNet); @@ -307,9 +295,6 @@ [ByRefEvent] private record struct IsSimulatedGridMethodEvent [ByRefEvent] private record struct GetAllMixturesMethodEvent (EntityUid Grid, bool Excite = false, IEnumerable? Mixtures = null, bool Handled = false); - [ByRefEvent] private record struct InvalidateTileMethodEvent - (EntityUid Grid, Vector2i Tile, bool Handled = false); - [ByRefEvent] private record struct GetTileMixturesMethodEvent (EntityUid? GridUid, EntityUid? MapUid, List Tiles, bool Excite = false, GasMixture?[]? Mixtures = null, bool Handled = false); @@ -319,16 +304,6 @@ [ByRefEvent] private record struct GetTileMixtureMethodEvent [ByRefEvent] private record struct ReactTileMethodEvent (EntityUid GridId, Vector2i Tile, ReactionResult Result = default, bool Handled = false); - [ByRefEvent] private record struct IsTileAirBlockedMethodEvent - (EntityUid Grid, Vector2i Tile, AtmosDirection Direction = AtmosDirection.All, MapGridComponent? MapGridComponent = null, bool Result = false, bool Handled = false) - { - /// - /// True if one of the enabled blockers has . Note - /// that this does not actually check if all directions are blocked. - /// - public bool NoAir = false; - } - [ByRefEvent] private record struct IsTileSpaceMethodEvent (EntityUid? Grid, EntityUid? Map, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Result = true, bool Handled = false); @@ -339,9 +314,6 @@ [ByRefEvent] private record struct GetAdjacentTileMixturesMethodEvent (EntityUid Grid, Vector2i Tile, bool IncludeBlocked, bool Excite, IEnumerable? Result = null, bool Handled = false); - [ByRefEvent] private record struct UpdateAdjacentMethodEvent - (EntityUid Grid, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Handled = false); - [ByRefEvent] private record struct HotspotExposeMethodEvent (EntityUid Grid, EntityUid? SparkSourceUid, Vector2i Tile, float ExposedTemperature, float ExposedVolume, bool soh, bool Handled = false); @@ -351,9 +323,6 @@ [ByRefEvent] private record struct HotspotExtinguishMethodEvent [ByRefEvent] private record struct IsHotspotActiveMethodEvent (EntityUid Grid, Vector2i Tile, bool Result = false, bool Handled = false); - [ByRefEvent] private record struct FixTileVacuumMethodEvent - (EntityUid Grid, Vector2i Tile, bool Handled = false); - [ByRefEvent] private record struct AddPipeNetMethodEvent (EntityUid Grid, PipeNet PipeNet, bool Handled = false); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs index 1d809dcd032..de4c9199cf7 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs @@ -72,7 +72,8 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E var tileSize = excitedGroup.Tiles.Count; - if (excitedGroup.Disposed) return; + if (excitedGroup.Disposed) + return; if (tileSize == 0) { @@ -98,7 +99,9 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E foreach (var tile in excitedGroup.Tiles) { - if (tile?.Air == null) continue; + if (tile?.Air == null) + continue; + tile.Air.CopyFromMutable(combined); InvalidateVisuals(tile.GridIndex, tile.GridIndices); } @@ -106,21 +109,23 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E excitedGroup.BreakdownCooldown = 0; } - private void ExcitedGroupDismantle(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup, bool unexcite = true) + /// + /// This de-activates and removes all tiles in an excited group. + /// + private void DeactivateGroupTiles(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) { foreach (var tile in excitedGroup.Tiles) { tile.ExcitedGroup = null; - - if (!unexcite) - continue; - RemoveActiveTile(gridAtmosphere, tile); } excitedGroup.Tiles.Clear(); } + /// + /// This removes an excited group without de-activating its tiles. + /// private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) { if (excitedGroup.Disposed) @@ -129,9 +134,14 @@ private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, Excited DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!"); excitedGroup.Disposed = true; - gridAtmosphere.ExcitedGroups.Remove(excitedGroup); - ExcitedGroupDismantle(gridAtmosphere, excitedGroup, false); + + foreach (var tile in excitedGroup.Tiles) + { + tile.ExcitedGroup = null; + } + + excitedGroup.Tiles.Clear(); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs index 1f1a208b24b..d43cc81b0f8 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs @@ -14,6 +14,7 @@ public sealed partial class AtmosphereSystem private void InitializeGridAtmosphere() { SubscribeLocalEvent(OnGridAtmosphereInit); + SubscribeLocalEvent(OnGridAtmosphereStartup); SubscribeLocalEvent(OnAtmosphereRemove); SubscribeLocalEvent(OnGridSplit); @@ -22,19 +23,15 @@ private void InitializeGridAtmosphere() SubscribeLocalEvent(GridHasAtmosphere); SubscribeLocalEvent(GridIsSimulated); SubscribeLocalEvent(GridGetAllMixtures); - SubscribeLocalEvent(GridInvalidateTile); SubscribeLocalEvent(GridGetTileMixture); SubscribeLocalEvent(GridGetTileMixtures); SubscribeLocalEvent(GridReactTile); - SubscribeLocalEvent(GridIsTileAirBlocked); SubscribeLocalEvent(GridIsTileSpace); SubscribeLocalEvent(GridGetAdjacentTiles); SubscribeLocalEvent(GridGetAdjacentTileMixtures); - SubscribeLocalEvent(GridUpdateAdjacent); SubscribeLocalEvent(GridHotspotExpose); SubscribeLocalEvent(GridHotspotExtinguish); SubscribeLocalEvent(GridIsHotspotActive); - SubscribeLocalEvent(GridFixTileVacuum); SubscribeLocalEvent(GridAddPipeNet); SubscribeLocalEvent(GridRemovePipeNet); SubscribeLocalEvent(GridAddAtmosDevice); @@ -56,22 +53,23 @@ private void OnAtmosphereRemove(EntityUid uid, GridAtmosphereComponent component } } - private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent gridAtmosphere, ComponentInit args) + private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent component, ComponentInit args) { base.Initialize(); - if (!TryComp(uid, out MapGridComponent? mapGrid)) - return; - EnsureComp(uid); - - foreach (var (indices, tile) in gridAtmosphere.Tiles) + foreach (var tile in component.Tiles.Values) { - gridAtmosphere.InvalidatedCoords.Add(indices); tile.GridIndex = uid; } + } + + private void OnGridAtmosphereStartup(EntityUid uid, GridAtmosphereComponent component, ComponentStartup args) + { + if (!TryComp(uid, out MapGridComponent? mapGrid)) + return; - GridRepopulateTiles((uid, mapGrid, gridAtmosphere)); + InvalidateAllTiles((uid, mapGrid, component)); } private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmos, ref GridSplitEvent args) @@ -104,8 +102,7 @@ private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmo continue; // Copy a bunch of data over... Not great, maybe put this in TileAtmosphere? - newTileAtmosphere.Air = tileAtmosphere.Air?.Clone() ?? null; - newTileAtmosphere.MolesArchived = newTileAtmosphere.Air == null ? null : new float[Atmospherics.AdjustedNumberOfGases]; + newTileAtmosphere.Air = tileAtmosphere.Air?.Clone(); newTileAtmosphere.Hotspot = tileAtmosphere.Hotspot; newTileAtmosphere.HeatCapacity = tileAtmosphere.HeatCapacity; newTileAtmosphere.Temperature = tileAtmosphere.Temperature; @@ -170,15 +167,6 @@ IEnumerable EnumerateMixtures(EntityUid gridUid, GridAtmosphereCompo args.Handled = true; } - private void GridInvalidateTile(EntityUid uid, GridAtmosphereComponent component, ref InvalidateTileMethodEvent args) - { - if (args.Handled) - return; - - component.InvalidatedCoords.Add(args.Tile); - args.Handled = true; - } - private void GridGetTileMixture(EntityUid uid, GridAtmosphereComponent component, ref GetTileMixtureMethodEvent args) { @@ -233,43 +221,6 @@ private void GridReactTile(EntityUid uid, GridAtmosphereComponent component, ref args.Handled = true; } - private void GridIsTileAirBlocked(EntityUid uid, GridAtmosphereComponent component, - ref IsTileAirBlockedMethodEvent args) - { - if (args.Handled) - return; - - var mapGridComp = args.MapGridComponent; - - if (!Resolve(uid, ref mapGridComp)) - return; - - var directions = AtmosDirection.Invalid; - - var enumerator = GetObstructingComponentsEnumerator(mapGridComp, args.Tile); - - while (enumerator.MoveNext(out var obstructingComponent)) - { - if (!obstructingComponent.AirBlocked) - continue; - - // We set the directions that are air-blocked so far, - // as you could have a full obstruction with only 4 directional air blockers. - directions |= obstructingComponent.AirBlockedDirection; - args.NoAir |= obstructingComponent.NoAirWhenFullyAirBlocked; - - if (directions.IsFlagSet(args.Direction)) - { - args.Result = true; - args.Handled = true; - return; - } - } - - args.Result = false; - args.Handled = true; - } - private void GridIsTileSpace(EntityUid uid, GridAtmosphereComponent component, ref IsTileSpaceMethodEvent args) { if (args.Handled) @@ -331,71 +282,58 @@ IEnumerable EnumerateAdjacent(GridAtmosphereComponent grid, TileAtmo args.Handled = true; } - private void GridUpdateAdjacent(EntityUid uid, GridAtmosphereComponent component, - ref UpdateAdjacentMethodEvent args) + /// + /// Update array of adjacent tiles and the adjacency flags. Optionally activates all tiles with modified adjacencies. + /// + private void UpdateAdjacentTiles( + Entity ent, + TileAtmosphere tile, + bool activate = false) { - if (args.Handled) - return; - - var mapGridComp = args.MapGridComponent; - - if (!Resolve(uid, ref mapGridComp)) - return; - - var xform = Transform(uid); - EntityUid? mapUid = _mapManager.MapExists(xform.MapID) ? _mapManager.GetMapEntityId(xform.MapID) : null; - - if (!component.Tiles.TryGetValue(args.Tile, out var tile)) - return; + var uid = ent.Owner; + var atmos = ent.Comp1; + var blockedDirs = tile.AirtightData.BlockedDirections; + if (activate) + AddActiveTile(atmos, tile); tile.AdjacentBits = AtmosDirection.Invalid; - tile.BlockedAirflow = GetBlockedDirections(mapGridComp, tile.GridIndices); - for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); + var adjacentIndices = tile.GridIndices.Offset(direction); - var otherIndices = tile.GridIndices.Offset(direction); - - if (!component.Tiles.TryGetValue(otherIndices, out var adjacent)) + TileAtmosphere? adjacent; + if (!tile.NoGridTile) { - adjacent = new TileAtmosphere(tile.GridIndex, otherIndices, - GetTileMixture(null, mapUid, otherIndices), - space: IsTileSpace(null, mapUid, otherIndices, mapGridComp)); + adjacent = GetOrNewTile(uid, atmos, adjacentIndices); } - - var oppositeDirection = direction.GetOpposite(); - - adjacent.BlockedAirflow = GetBlockedDirections(mapGridComp, adjacent.GridIndices); - - // Pass in MapGridComponent so we don't have to resolve it for every adjacent direction. - var tileBlockedEv = new IsTileAirBlockedMethodEvent(uid, tile.GridIndices, direction, mapGridComp); - GridIsTileAirBlocked(uid, component, ref tileBlockedEv); - - var adjacentBlockedEv = - new IsTileAirBlockedMethodEvent(uid, adjacent.GridIndices, oppositeDirection, mapGridComp); - GridIsTileAirBlocked(uid, component, ref adjacentBlockedEv); - - if (!adjacent.BlockedAirflow.IsFlagSet(oppositeDirection) && !tileBlockedEv.Result) + else if (!atmos.Tiles.TryGetValue(adjacentIndices, out adjacent)) { - adjacent.AdjacentBits |= oppositeDirection; - adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; + tile.AdjacentBits &= ~direction; + tile.AdjacentTiles[i] = null; + continue; } - else + + var adjBlockDirs = adjacent.AirtightData.BlockedDirections; + if (activate) + AddActiveTile(atmos, adjacent); + + var oppositeDirection = direction.GetOpposite(); + if (adjBlockDirs.IsFlagSet(oppositeDirection) || blockedDirs.IsFlagSet(direction)) { + // Adjacency is blocked by some airtight entity. + tile.AdjacentBits &= ~direction; adjacent.AdjacentBits &= ~oppositeDirection; + tile.AdjacentTiles[i] = null; adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = null; } - - if (!tile.BlockedAirflow.IsFlagSet(direction) && !adjacentBlockedEv.Result) - { - tile.AdjacentBits |= direction; - tile.AdjacentTiles[direction.ToIndex()] = adjacent; - } else { - tile.AdjacentBits &= ~direction; - tile.AdjacentTiles[direction.ToIndex()] = null; + // No airtight entity in the way. + tile.AdjacentBits |= direction; + adjacent.AdjacentBits |= oppositeDirection; + tile.AdjacentTiles[i] = adjacent; + adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; } DebugTools.Assert(!(tile.AdjacentBits.IsFlagSet(direction) ^ @@ -409,6 +347,16 @@ private void GridUpdateAdjacent(EntityUid uid, GridAtmosphereComponent component tile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid; } + private (GasMixture Air, bool IsSpace) GetDefaultMapAtmosphere(MapAtmosphereComponent? map) + { + if (map == null) + return (GasMixture.SpaceGas, true); + + var air = map.Mixture; + DebugTools.Assert(air.Immutable); + return (air, map.Space); + } + private void GridHotspotExpose(EntityUid uid, GridAtmosphereComponent component, ref HotspotExposeMethodEvent args) { if (args.Handled) @@ -451,54 +399,50 @@ private void GridIsHotspotActive(EntityUid uid, GridAtmosphereComponent componen args.Handled = true; } - private void GridFixTileVacuum(EntityUid uid, GridAtmosphereComponent component, ref FixTileVacuumMethodEvent args) + private void GridFixTileVacuum( + Entity ent, + TileAtmosphere tile, + float volume) { - if (args.Handled) - return; - - var adjEv = new GetAdjacentTileMixturesMethodEvent(uid, args.Tile, false, true); - GridGetAdjacentTileMixtures(uid, component, ref adjEv); - - if (!adjEv.Handled || !component.Tiles.TryGetValue(args.Tile, out var tile)) - return; - - if (!TryComp(uid, out var mapGridComp)) - return; - - var adjacent = adjEv.Result!.ToArray(); - - // Return early, let's not cause any funny NaNs or needless vacuums. - if (adjacent.Length == 0) - return; + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable == false ); + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; - tile.Air = new GasMixture + var count = 0; + foreach (var adj in tile.AdjacentTiles) { - Volume = GetVolumeForTiles(mapGridComp, 1), - Temperature = Atmospherics.T20C - }; - - tile.MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; - tile.ArchivedCycle = 0; + if (adj?.Air != null) + count++; + } - var ratio = 1f / adjacent.Length; + var ratio = 1f / count; var totalTemperature = 0f; - foreach (var adj in adjacent) + foreach (var adj in tile.AdjacentTiles) { + if (adj?.Air == null) + continue; + totalTemperature += adj.Temperature; + // TODO ATMOS. Why is this removing and then re-adding air to the neighbouring tiles? + // Is it some rounding issue to do with Atmospherics.GasMinMoles? because otherwise this is just unnecessary. + // if we get rid of this, then this could also just add moles and then multiply by ratio at the end, rather + // than having to iterate over adjacent tiles twice. + // Remove a bit of gas from the adjacent ratio... - var mix = adj.RemoveRatio(ratio); + var mix = adj.Air.RemoveRatio(ratio); // And merge it to the new tile air. Merge(tile.Air, mix); // Return removed gas to its original mixture. - Merge(adj, mix); + Merge(adj.Air, mix); } // New temperature is the arithmetic mean of the sum of the adjacent temperatures... - tile.Air.Temperature = totalTemperature / adjacent.Length; + tile.Air.Temperature = totalTemperature / count; } private void GridAddPipeNet(EntityUid uid, GridAtmosphereComponent component, ref AddPipeNetMethodEvent args) @@ -547,30 +491,21 @@ private void GridRemoveAtmosDevice(EntityUid uid, GridAtmosphereComponent compon /// /// Repopulates all tiles on a grid atmosphere. /// - /// The grid where to get all valid tiles from. - /// The grid atmosphere where the tiles will be repopulated. - private void GridRepopulateTiles(Entity grid) + public void InvalidateAllTiles(Entity entity) { - var (uid, mapGrid, gridAtmosphere) = grid; - var volume = GetVolumeForTiles(mapGrid, 1); + var (uid, grid, atmos) = entity; + if (!Resolve(uid, ref grid, ref atmos)) + return; - foreach (var tile in mapGrid.GetAllTiles()) + foreach (var indices in atmos.Tiles.Keys) { - if (!gridAtmosphere.Tiles.ContainsKey(tile.GridIndices)) - gridAtmosphere.Tiles[tile.GridIndices] = new TileAtmosphere(tile.GridUid, tile.GridIndices, - new GasMixture(volume) { Temperature = Atmospherics.T20C }); - - gridAtmosphere.InvalidatedCoords.Add(tile.GridIndices); + atmos.InvalidatedCoords.Add(indices); } - TryComp(uid, out GasTileOverlayComponent? overlay); - - // Gotta do this afterwards so we can properly update adjacent tiles. - foreach (var (position, _) in gridAtmosphere.Tiles.ToArray()) + var enumerator = _map.GetAllTilesEnumerator(uid, grid); + while (enumerator.MoveNext(out var tile)) { - var ev = new UpdateAdjacentMethodEvent(uid, position); - GridUpdateAdjacent(uid, gridAtmosphere, ref ev); - InvalidateVisuals(uid, position, overlay); + atmos.InvalidatedCoords.Add(tile.Value.GridIndices); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index 53035e1ed3c..b0c823426d6 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -1,13 +1,11 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; -using Content.Shared.Audio; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; -using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index 795c6e0547e..c27e18b55b0 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -1,12 +1,13 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem { - private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent? visuals) + private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent visuals) { // Can't process a tile without air if (tile.Air == null) @@ -116,15 +117,9 @@ private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere private void Archive(TileAtmosphere tile, int fireCount) { if (tile.Air != null) - { tile.Air.Moles.AsSpan().CopyTo(tile.MolesArchived.AsSpan()); - tile.TemperatureArchived = tile.Air.Temperature; - } - else - { - tile.TemperatureArchived = tile.Temperature; - } + tile.TemperatureArchived = tile.Temperature; tile.ArchivedCycle = fireCount; } @@ -166,6 +161,12 @@ private void AddActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmospher /// Whether to dispose of the tile's private void RemoveActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool disposeExcitedGroup = true) { + DebugTools.Assert(tile.Excited == gridAtmosphere.ActiveTiles.Contains(tile)); + DebugTools.Assert(tile.Excited || tile.ExcitedGroup == null); + + if (!tile.Excited) + return; + tile.Excited = false; gridAtmosphere.ActiveTiles.Remove(tile); @@ -186,7 +187,6 @@ public float GetHeatCapacityArchived(TileAtmosphere tile) if (tile.Air == null) return tile.HeatCapacity; - // Moles archived is not null if air is not null. return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs index 916191cb050..ed105c8d33f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs @@ -1,6 +1,8 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos.Components; using Robust.Shared.GameStates; +using Robust.Shared.Map.Components; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems; @@ -8,10 +10,25 @@ public partial class AtmosphereSystem { private void InitializeMap() { + SubscribeLocalEvent(OnMapStartup); + SubscribeLocalEvent(OnMapRemove); SubscribeLocalEvent(MapIsTileSpace); SubscribeLocalEvent(MapGetTileMixture); SubscribeLocalEvent(MapGetTileMixtures); SubscribeLocalEvent(OnMapGetState); + SubscribeLocalEvent(OnGridParentChanged); + } + + private void OnMapStartup(EntityUid uid, MapAtmosphereComponent component, ComponentInit args) + { + component.Mixture.MarkImmutable(); + component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); + } + + private void OnMapRemove(EntityUid uid, MapAtmosphereComponent component, ComponentRemove args) + { + if (!TerminatingOrDeleted(uid)) + RefreshAllGridMapAtmospheres(uid); } private void MapIsTileSpace(EntityUid uid, MapAtmosphereComponent component, ref IsTileSpaceMethodEvent args) @@ -28,54 +45,115 @@ private void MapGetTileMixture(EntityUid uid, MapAtmosphereComponent component, if (args.Handled) return; - // Clone the mixture, if possible. - args.Mixture = component.Mixture?.Clone(); + args.Mixture = component.Mixture; args.Handled = true; } private void MapGetTileMixtures(EntityUid uid, MapAtmosphereComponent component, ref GetTileMixturesMethodEvent args) { - if (args.Handled || component.Mixture == null) + if (args.Handled) return; args.Handled = true; args.Mixtures ??= new GasMixture?[args.Tiles.Count]; for (var i = 0; i < args.Tiles.Count; i++) { - args.Mixtures[i] ??= component.Mixture.Clone(); + args.Mixtures[i] ??= component.Mixture; } } private void OnMapGetState(EntityUid uid, MapAtmosphereComponent component, ref ComponentGetState args) { - args.State = new MapAtmosphereComponentState(_gasTileOverlaySystem.GetOverlayData(component.Mixture)); + args.State = new MapAtmosphereComponentState(component.Overlay); + } + + public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture) + { + DebugTools.Assert(HasComp(uid)); + var component = EnsureComp(uid); + SetMapGasMixture(uid, mixture, component, false); + SetMapSpace(uid, space, component, false); + RefreshAllGridMapAtmospheres(uid); } - public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture, MapAtmosphereComponent? component = null) + public void SetMapGasMixture(EntityUid uid, GasMixture mixture, MapAtmosphereComponent? component = null, bool updateTiles = true) { if (!Resolve(uid, ref component)) return; - component.Space = space; + if (!mixture.Immutable) + { + mixture = mixture.Clone(); + mixture.MarkImmutable(); + } + component.Mixture = mixture; - Dirty(component); + component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); + Dirty(uid, component); + if (updateTiles) + RefreshAllGridMapAtmospheres(uid); } - public void SetMapGasMixture(EntityUid uid, GasMixture? mixture, MapAtmosphereComponent? component = null) + public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null, bool updateTiles = true) { if (!Resolve(uid, ref component)) return; - component.Mixture = mixture; - Dirty(component); + if (component.Space == space) + return; + + component.Space = space; + + if (updateTiles) + RefreshAllGridMapAtmospheres(uid); } - public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null) + /// + /// Forces a refresh of all MapAtmosphere tiles on every grid on a map. + /// + public void RefreshAllGridMapAtmospheres(EntityUid map) { - if (!Resolve(uid, ref component)) + DebugTools.Assert(HasComp(map)); + var enumerator = AllEntityQuery(); + while (enumerator.MoveNext(out var grid, out var atmos, out var xform)) + { + if (xform.MapUid == map) + RefreshMapAtmosphereTiles((grid, atmos)); + } + } + + /// + /// Forces a refresh of all MapAtmosphere tiles on a given grid. + /// + private void RefreshMapAtmosphereTiles(Entity grid) + { + if (!Resolve(grid.Owner, ref grid.Comp)) return; - component.Space = space; - Dirty(component); + var atmos = grid.Comp; + foreach (var tile in atmos.MapTiles) + { + RemoveMapAtmos(atmos, tile); + atmos.InvalidatedCoords.Add(tile.GridIndices); + } + atmos.MapTiles.Clear(); + } + + /// + /// Handles updating map-atmospheres when grids move across maps. + /// + private void OnGridParentChanged(Entity grid, ref EntParentChangedMessage args) + { + // Do nothing if detaching to nullspace + if (!args.Transform.ParentUid.IsValid()) + return; + + // Avoid doing work if moving from a space-map to another space-map. + if (args.OldParent == null + || HasComp(args.OldParent) + || HasComp(args.Transform.ParentUid)) + { + RefreshMapAtmosphereTiles((grid, grid)); + } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index aceda3cd332..f156125b0ff 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -5,7 +5,6 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Database; -using Content.Shared.Doors.Components; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -27,7 +26,10 @@ public sealed partial class AtmosphereSystem private readonly TileAtmosphere[] _depressurizeSpaceTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit]; private readonly TileAtmosphere[] _depressurizeProgressionOrder = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit * 2]; - private void EqualizePressureInZone(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) + private void EqualizePressureInZone( + Entity ent, + TileAtmosphere tile, + int cycleNum) { if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum)) return; // Already done. @@ -56,7 +58,7 @@ private void EqualizePressureInZone(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) + private void ExplosivelyDepressurize( + Entity ent, + TileAtmosphere tile, + int cycleNum) { // Check if explosive depressurization is enabled and if the tile is valid. if (!MonstermosDepressurization || tile.Air == null) @@ -368,7 +382,7 @@ private void ExplosivelyDepressurize(Entity= limit) break; + if (tileCount >= limit) + break; } } else @@ -437,13 +458,21 @@ private void ExplosivelyDepressurize(Entity 10 && (totalMolesRemoved / tileCount) > 10) + if (tileCount > 10 && (totalMolesRemoved / tileCount) > 10) _adminLog.Add(LogType.ExplosiveDepressurization, LogImpact.High, $"Explosive depressurization removed {totalMolesRemoved} moles from {tileCount} tiles starting from position {tile.GridIndices:position} on grid ID {tile.GridIndex:grid}"); @@ -544,36 +573,33 @@ private void ExplosivelyDepressurize(Entity ent, TileAtmosphere tile, TileAtmosphere other, GasTileOverlayComponent? visuals, MapGridComponent mapGrid) + private void ConsiderFirelocks( + Entity ent, + TileAtmosphere tile, + TileAtmosphere other) { var reconsiderAdjacent = false; - foreach (var entity in mapGrid.GetAnchoredEntities(tile.GridIndices)) + var mapGrid = ent.Comp3; + foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, tile.GridIndices)) { - if (!TryComp(entity, out FirelockComponent? firelock)) - continue; - - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (_firelockQuery.TryGetComponent(entity, out var firelock)) + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } - foreach (var entity in mapGrid.GetAnchoredEntities(other.GridIndices)) + foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, other.GridIndices)) { - if (!TryComp(entity, out FirelockComponent? firelock)) - continue; - - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (_firelockQuery.TryGetComponent(entity, out var firelock)) + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } if (!reconsiderAdjacent) return; - var (owner, gridAtmosphere) = ent; - var tileEv = new UpdateAdjacentMethodEvent(owner, tile.GridIndices); - var otherEv = new UpdateAdjacentMethodEvent(owner, other.GridIndices); - GridUpdateAdjacent(owner, gridAtmosphere, ref tileEv); - GridUpdateAdjacent(owner, gridAtmosphere, ref otherEv); - InvalidateVisuals(tile.GridIndex, tile.GridIndices, visuals); - InvalidateVisuals(other.GridIndex, other.GridIndices, visuals); + UpdateAdjacentTiles(ent, tile); + UpdateAdjacentTiles(ent, other); + InvalidateVisuals(tile.GridIndex, tile.GridIndices, ent); + InvalidateVisuals(other.GridIndex, other.GridIndices, ent); } private void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, GasTileOverlayComponent? visuals) @@ -642,7 +668,7 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo if (adj == null) { var nonNull = tile.AdjacentTiles.Where(x => x != null).Count(); - Logger.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: {tile.Tile}, non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); + Log.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: ({tile.GridIndex}, {tile.GridIndices}), non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); return; } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 4f8df0af670..1f3ca2145b9 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -1,6 +1,5 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; -using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Maps; @@ -8,6 +7,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { @@ -30,131 +30,249 @@ public sealed partial class AtmosphereSystem private int _currentRunAtmosphereIndex; private bool _simulationPaused; - private readonly List> _currentRunAtmosphere = new(); + private TileAtmosphere GetOrNewTile(EntityUid owner, GridAtmosphereComponent atmosphere, Vector2i index) + { + var tile = atmosphere.Tiles.GetOrNew(index, out var existing); + if (existing) + return tile; + + atmosphere.InvalidatedCoords.Add(index); + tile.GridIndex = owner; + tile.GridIndices = index; + return tile; + } + + private readonly List> _currentRunAtmosphere = new(); /// /// Revalidates all invalid coordinates in a grid atmosphere. + /// I.e., process any tiles that have had their airtight blockers modified. /// /// The grid atmosphere in question. /// Whether the process succeeded or got paused due to time constrains. - private bool ProcessRevalidate(Entity ent, GasTileOverlayComponent? visuals) + private bool ProcessRevalidate(Entity ent) { - var (owner, atmosphere) = ent; + if (ent.Comp4.MapUid == null) + { + Log.Error($"Attempted to process atmosphere on a map-less grid? Grid: {ToPrettyString(ent)}"); + return true; + } + + var (uid, atmosphere, visuals, grid, xform) = ent; + var volume = GetVolumeForTiles(grid); + TryComp(xform.MapUid, out MapAtmosphereComponent? mapAtmos); + if (!atmosphere.ProcessingPaused) { - atmosphere.CurrentRunInvalidatedCoordinates.Clear(); - atmosphere.CurrentRunInvalidatedCoordinates.EnsureCapacity(atmosphere.InvalidatedCoords.Count); - foreach (var tile in atmosphere.InvalidatedCoords) + atmosphere.CurrentRunInvalidatedTiles.Clear(); + atmosphere.CurrentRunInvalidatedTiles.EnsureCapacity(atmosphere.InvalidatedCoords.Count); + foreach (var indices in atmosphere.InvalidatedCoords) { - atmosphere.CurrentRunInvalidatedCoordinates.Enqueue(tile); + var tile = GetOrNewTile(uid, atmosphere, indices); + atmosphere.CurrentRunInvalidatedTiles.Enqueue(tile); + + // Update tile.IsSpace and tile.MapAtmosphere, and tile.AirtightData. + UpdateTileData(ent, mapAtmos, tile); } atmosphere.InvalidatedCoords.Clear(); + + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + return false; } - if (!TryComp(owner, out MapGridComponent? mapGridComp)) - return true; + var number = 0; + while (atmosphere.CurrentRunInvalidatedTiles.TryDequeue(out var tile)) + { + DebugTools.Assert(atmosphere.Tiles.GetValueOrDefault(tile.GridIndices) == tile); + UpdateAdjacentTiles(ent, tile, activate: true); + UpdateTileAir(ent, tile, volume); + InvalidateVisuals(uid, tile.GridIndices, visuals); - var mapUid = _mapManager.GetMapEntityIdOrThrow(Transform(owner).MapID); + if (number++ < InvalidCoordinatesLagCheckIterations) + continue; - var volume = GetVolumeForTiles(mapGridComp); + number = 0; + // Process the rest next time. + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + return false; + } - var number = 0; - while (atmosphere.CurrentRunInvalidatedCoordinates.TryDequeue(out var indices)) + TrimDisconnectedMapTiles(ent); + return true; + } + + /// + /// This method queued a tile and all of its neighbours up for processing by . + /// + public void QueueTileTrim(GridAtmosphereComponent atmos, TileAtmosphere tile) + { + if (!tile.TrimQueued) { - if (!atmosphere.Tiles.TryGetValue(indices, out var tile)) + tile.TrimQueued = true; + atmos.PossiblyDisconnectedTiles.Add(tile); + } + + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection) (1 << i); + var indices = tile.GridIndices.Offset(direction); + if (atmos.Tiles.TryGetValue(indices, out var adj) + && adj.NoGridTile + && !adj.TrimQueued) { - tile = new TileAtmosphere(owner, indices, - new GasMixture(volume) { Temperature = Atmospherics.T20C }); - atmosphere.Tiles[indices] = tile; + adj.TrimQueued = true; + atmos.PossiblyDisconnectedTiles.Add(adj); } + } + } - var airBlockedEv = new IsTileAirBlockedMethodEvent(owner, indices, MapGridComponent:mapGridComp); - GridIsTileAirBlocked(owner, atmosphere, ref airBlockedEv); - var isAirBlocked = airBlockedEv.Result; + /// + /// Tiles in a are either grid-tiles, or they they should be are tiles + /// adjacent to grid-tiles that represent the map's atmosphere. This method trims any map-tiles that are no longer + /// adjacent to any grid-tiles. + /// + private void TrimDisconnectedMapTiles( + Entity ent) + { + var atmos = ent.Comp1; - var oldBlocked = tile.BlockedAirflow; - var updateAdjacentEv = new UpdateAdjacentMethodEvent(owner, indices, mapGridComp); - GridUpdateAdjacent(owner, atmosphere, ref updateAdjacentEv); + foreach (var tile in atmos.PossiblyDisconnectedTiles) + { + tile.TrimQueued = false; + if (!tile.NoGridTile) + continue; - // Blocked airflow changed, rebuild excited groups! - if (tile.Excited && tile.BlockedAirflow != oldBlocked) + var connected = false; + for (var i = 0; i < Atmospherics.Directions; i++) { - RemoveActiveTile(atmosphere, tile); + var indices = tile.GridIndices.Offset((AtmosDirection) (1 << i)); + if (_map.TryGetTile(ent.Comp3, indices, out var gridTile) && !gridTile.IsEmpty) + { + connected = true; + break; + } } - // Call this instead of the grid method as the map has a say on whether the tile is space or not. - if ((!mapGridComp.TryGetTileRef(indices, out var t) || t.IsSpace(_tileDefinitionManager)) && !isAirBlocked) + if (!connected) { - tile.Air = GetTileMixture(null, mapUid, indices); - tile.MolesArchived = tile.Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; - tile.Space = IsTileSpace(null, mapUid, indices, mapGridComp); + RemoveActiveTile(atmos, tile); + atmos.Tiles.Remove(tile.GridIndices); } - else if (isAirBlocked) + } + + atmos.PossiblyDisconnectedTiles.Clear(); + } + + /// + /// Checks whether a tile has a corresponding grid-tile, or whether it is a "map" tile. Also checks whether the + /// tile should be considered "space" + /// + private void UpdateTileData( + Entity ent, + MapAtmosphereComponent? mapAtmos, + TileAtmosphere tile) + { + var idx = tile.GridIndices; + bool mapAtmosphere; + if (_map.TryGetTile(ent.Comp3, idx, out var gTile) && !gTile.IsEmpty) + { + var contentDef = (ContentTileDefinition) _tileDefinitionManager[gTile.TypeId]; + mapAtmosphere = contentDef.MapAtmosphere; + tile.ThermalConductivity = contentDef.ThermalConductivity; + tile.HeatCapacity = contentDef.HeatCapacity; + tile.NoGridTile = false; + } + else + { + mapAtmosphere = true; + tile.ThermalConductivity = 0.5f; + tile.HeatCapacity = float.PositiveInfinity; + + if (!tile.NoGridTile) { - if (airBlockedEv.NoAir) - { - tile.Air = null; - tile.MolesArchived = null; - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Hotspot = new Hotspot(); - } + tile.NoGridTile = true; + + // This tile just became a non-grid atmos tile. + // It, or one of its neighbours, might now be completely disconnected from the grid. + QueueTileTrim(ent.Comp1, tile); } - else - { - if (tile.Air == null && NeedsVacuumFixing(mapGridComp, indices)) - { - var vacuumEv = new FixTileVacuumMethodEvent(owner, indices); - GridFixTileVacuum(owner, atmosphere, ref vacuumEv); - } + } - // Tile used to be space, but isn't anymore. - if (tile.Space || (tile.Air?.Immutable ?? false)) - { - tile.Air = null; - tile.MolesArchived = null; - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Space = false; - } + UpdateAirtightData(ent.Owner, ent.Comp1, ent.Comp3, tile); - tile.Air ??= new GasMixture(volume){Temperature = Atmospherics.T20C}; - tile.MolesArchived ??= new float[Atmospherics.AdjustedNumberOfGases]; + if (mapAtmosphere) + { + if (!tile.MapAtmosphere) + { + (tile.Air, tile.Space) = GetDefaultMapAtmosphere(mapAtmos); + tile.MapAtmosphere = true; + ent.Comp1.MapTiles.Add(tile); } - // We activate the tile. - AddActiveTile(atmosphere, tile); + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + return; + } - // TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity - var tileDef = mapGridComp.TryGetTileRef(indices, out var tileRef) - ? tileRef.GetContentTileDefinition(_tileDefinitionManager) - : null; + if (!tile.MapAtmosphere) + return; - tile.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f; - tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity; - InvalidateVisuals(owner, indices, visuals); + // Tile used to be exposed to the map's atmosphere, but isn't anymore. + RemoveMapAtmos(ent.Comp1, tile); + } - for (var i = 0; i < Atmospherics.Directions; i++) - { - var direction = (AtmosDirection) (1 << i); - var otherIndices = indices.Offset(direction); + private void RemoveMapAtmos(GridAtmosphereComponent atmos, TileAtmosphere tile) + { + DebugTools.Assert(tile.MapAtmosphere); + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + tile.MapAtmosphere = false; + atmos.MapTiles.Remove(tile); + tile.Air = null; + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Space = false; + } - if (atmosphere.Tiles.TryGetValue(otherIndices, out var otherTile)) - AddActiveTile(atmosphere, otherTile); - } + /// + /// Check whether a grid-tile should have an air mixture, and give it one if it doesn't already have one. + /// + private void UpdateTileAir( + Entity ent, + TileAtmosphere tile, + float volume) + { + if (tile.MapAtmosphere) + { + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + return; + } - if (number++ < InvalidCoordinatesLagCheckIterations) - continue; + var data = tile.AirtightData; + var fullyBlocked = data.BlockedDirections == AtmosDirection.All; - number = 0; - // Process the rest next time. - if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) - { - return false; - } + if (fullyBlocked && data.NoAirWhenBlocked) + { + if (tile.Air == null) + return; + + tile.Air = null; + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Hotspot = new Hotspot(); + return; } - return true; + if (tile.Air != null) + return; + + tile.Air = new GasMixture(volume){Temperature = Atmospherics.T20C}; + + if (data.FixVacuum) + GridFixTileVacuum(ent, tile, volume); } private void QueueRunTiles( @@ -170,19 +288,16 @@ private void QueueRunTiles( } } - private bool ProcessTileEqualize(Entity ent, GasTileOverlayComponent? visuals) + private bool ProcessTileEqualize(Entity ent) { - var (uid, atmosphere) = ent; + var atmosphere = ent.Comp1; if (!atmosphere.ProcessingPaused) QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles); - if (!TryComp(uid, out MapGridComponent? mapGridComp)) - throw new Exception("Tried to process a grid atmosphere on an entity that isn't a grid!"); - var number = 0; while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) { - EqualizePressureInZone((uid, mapGridComp, atmosphere), tile, atmosphere.UpdateCounter, visuals); + EqualizePressureInZone(ent, tile, atmosphere.UpdateCounter); if (number++ < LagCheckIterations) continue; @@ -198,7 +313,7 @@ private bool ProcessTileEqualize(Entity ent, GasTileOve return true; } - private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent? visuals) + private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent visuals) { if(!atmosphere.ProcessingPaused) QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles); @@ -240,11 +355,11 @@ private bool ProcessExcitedGroups(GridAtmosphereComponent gridAtmosphere) excitedGroup.BreakdownCooldown++; excitedGroup.DismantleCooldown++; - if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) + if (excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup); - - else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) - ExcitedGroupDismantle(gridAtmosphere, excitedGroup); + else if (excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) + DeactivateGroupTiles(gridAtmosphere, excitedGroup); + // TODO ATMOS. What is the point of this? why is this only de-exciting the group? Shouldn't it also dismantle it? if (number++ < LagCheckIterations) continue; @@ -435,10 +550,10 @@ private void UpdateProcessing(float frameTime) _currentRunAtmosphereIndex = 0; _currentRunAtmosphere.Clear(); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var grid)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var atmos, out var overlay, out var grid, out var xform )) { - _currentRunAtmosphere.Add((uid, grid)); + _currentRunAtmosphere.Add((uid, atmos, overlay, grid, xform)); } } @@ -448,8 +563,7 @@ private void UpdateProcessing(float frameTime) for (; _currentRunAtmosphereIndex < _currentRunAtmosphere.Count; _currentRunAtmosphereIndex++) { var ent = _currentRunAtmosphere[_currentRunAtmosphereIndex]; - var (owner, atmosphere) = ent; - TryComp(owner, out GasTileOverlayComponent? visuals); + var (owner, atmosphere, visuals, grid, xform) = ent; if (!TryComp(owner, out TransformComponent? x) || x.MapUid == null @@ -474,13 +588,14 @@ private void UpdateProcessing(float frameTime) switch (atmosphere.State) { case AtmosphereProcessingState.Revalidate: - if (!ProcessRevalidate(ent, visuals)) + if (!ProcessRevalidate(ent)) { atmosphere.ProcessingPaused = true; return; } atmosphere.ProcessingPaused = false; + // Next state depends on whether monstermos equalization is enabled or not. // Note: We do this here instead of on the tile equalization step to prevent ending it early. // Therefore, a change to this CVar might only be applied after that step is over. @@ -489,7 +604,7 @@ private void UpdateProcessing(float frameTime) : AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.TileEqualize: - if (!ProcessTileEqualize(ent, visuals)) + if (!ProcessTileEqualize(ent)) { atmosphere.ProcessingPaused = true; return; @@ -499,7 +614,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.ActiveTiles: - if (!ProcessActiveTiles(atmosphere, visuals)) + if (!ProcessActiveTiles(ent, ent)) { atmosphere.ProcessingPaused = true; return; @@ -520,7 +635,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.HighPressureDelta; continue; case AtmosphereProcessingState.HighPressureDelta: - if (!ProcessHighPressureDelta(ent)) + if (!ProcessHighPressureDelta((ent, ent))) { atmosphere.ProcessingPaused = true; return; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs index 33fa16a6c68..5c73cf11246 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems { @@ -12,7 +13,8 @@ private void Superconduct(GridAtmosphereComponent gridAtmosphere, TileAtmosphere for(var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - if (!directions.IsFlagSet(direction)) continue; + if (!directions.IsFlagSet(direction)) + continue; var adjacent = tile.AdjacentTiles[direction.ToIndex()]; @@ -92,7 +94,9 @@ public void NeighborConductWithSource(GridAtmosphereComponent gridAtmosphere, Ti { if (tile.Air == null) { - if (other.Tile != null) + // TODO ATMOS: why does this need to check if a tile exists if it doesn't use the tile? + if (TryComp(other.GridIndex, out var grid) + && _mapSystem.TryGetTileRef(other.GridIndex, grid, other.GridIndices, out var _)) { TemperatureShareOpenToSolid(other, tile); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs index 699c2a70aef..9b0d0d9670d 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs @@ -41,20 +41,6 @@ public void InvalidateVisuals(EntityUid gridUid, Vector2i tile, GasTileOverlayCo _gasTileOverlaySystem.Invalidate(gridUid, tile, comp); } - public bool NeedsVacuumFixing(MapGridComponent mapGrid, Vector2i indices) - { - var value = false; - - var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); - - while (enumerator.MoveNext(out var airtight)) - { - value |= airtight.FixVacuum; - } - - return value; - } - /// /// Gets the volume in liters for a number of tiles, on a specific grid. /// @@ -66,34 +52,44 @@ private float GetVolumeForTiles(MapGridComponent mapGrid, int tiles = 1) return Atmospherics.CellVolume * mapGrid.TileSize * tiles; } - /// - /// Gets all obstructing instances in a specific tile. - /// - /// The grid where to get the tile. - /// The indices of the tile. - /// The enumerator for the airtight components. - public AtmosObstructionEnumerator GetObstructingComponentsEnumerator(MapGridComponent mapGrid, Vector2i tile) + public readonly record struct AirtightData(AtmosDirection BlockedDirections, bool NoAirWhenBlocked, + bool FixVacuum); + + private void UpdateAirtightData(EntityUid uid, GridAtmosphereComponent atmos, MapGridComponent grid, TileAtmosphere tile) { - var ancEnumerator = mapGrid.GetAnchoredEntitiesEnumerator(tile); - var airQuery = GetEntityQuery(); + var oldBlocked = tile.AirtightData.BlockedDirections; + + tile.AirtightData = tile.NoGridTile + ? default + : GetAirtightData(uid, grid, tile.GridIndices); - var enumerator = new AtmosObstructionEnumerator(ancEnumerator, airQuery); - return enumerator; + if (tile.AirtightData.BlockedDirections != oldBlocked && tile.ExcitedGroup != null) + ExcitedGroupDispose(atmos, tile.ExcitedGroup); } - private AtmosDirection GetBlockedDirections(MapGridComponent mapGrid, Vector2i indices) + private AirtightData GetAirtightData(EntityUid uid, MapGridComponent grid, Vector2i tile) { - var value = AtmosDirection.Invalid; + var blockedDirs = AtmosDirection.Invalid; + var noAirWhenBlocked = false; + var fixVacuum = false; - var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); - - while (enumerator.MoveNext(out var airtight)) + foreach (var ent in _map.GetAnchoredEntities(uid, grid, tile)) { - if(airtight.AirBlocked) - value |= airtight.AirBlockedDirection; + if (!_airtightQuery.TryGetComponent(ent, out var airtight)) + continue; + + if(!airtight.AirBlocked) + continue; + + blockedDirs |= airtight.AirBlockedDirection; + noAirWhenBlocked |= airtight.NoAirWhenFullyAirBlocked; + fixVacuum |= airtight.FixVacuum; + + if (blockedDirs == AtmosDirection.All && noAirWhenBlocked && fixVacuum) + break; } - return value; + return new AirtightData(blockedDirs, noAirWhenBlocked, fixVacuum); } /// diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index dd2a9675591..d2f40e77169 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; +using Content.Shared.Doors.Components; using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Server.GameObjects; @@ -40,6 +41,9 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; + private EntityQuery _atmosQuery; + private EntityQuery _airtightQuery; + private EntityQuery _firelockQuery; private HashSet _entSet = new(); public override void Initialize() @@ -55,6 +59,9 @@ public override void Initialize() InitializeGridAtmosphere(); InitializeMap(); + _atmosQuery = GetEntityQuery(); + _airtightQuery = GetEntityQuery(); + _firelockQuery = GetEntityQuery(); SubscribeLocalEvent(OnTileChanged); diff --git a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs index 203c747e29e..70e3eef3c44 100644 --- a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs @@ -27,8 +27,12 @@ private void OnTileChanged(ref TileChangedEvent ev) // Also, these calls are surprisingly slow. // TODO: Make tiledefmanager cache the IsSpace property, and turn this lookup-through-two-interfaces into // TODO: a simple array lookup, as tile IDs are likely contiguous, and there's at most 2^16 possibilities anyway. - if (!((ev.OldTile.IsSpace(_tileDefinitionManager) && !ev.NewTile.IsSpace(_tileDefinitionManager)) || - (!ev.OldTile.IsSpace(_tileDefinitionManager) && ev.NewTile.IsSpace(_tileDefinitionManager))) || + + var oldSpace = ev.OldTile.IsSpace(_tileDefinitionManager); + var newSpace = ev.NewTile.IsSpace(_tileDefinitionManager); + + if (!(oldSpace && !newSpace || + !oldSpace && newSpace) || _atmosphereSystem.HasAtmosphere(ev.Entity)) return; diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 6a2c8f0a7e5..552ee142329 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -260,13 +260,13 @@ private GasEntry[] GenerateGasEntryArray(GasMixture? mixture) { var gas = _atmo.GetGas(i); - if (mixture?.Moles[i] <= UIMinMoles) + if (mixture?[i] <= UIMinMoles) continue; if (mixture != null) { var gasName = Loc.GetString(gas.Name); - gases.Add(new GasEntry(gasName, mixture.Moles[i], gas.Color)); + gases.Add(new GasEntry(gasName, mixture[i], gas.Color)); } } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 8ae9517379e..397f0167a9b 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -171,7 +171,7 @@ public GasOverlayData GetOverlayData(GasMixture? mixture) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = mixture?.Moles[id] ?? 0f; + var moles = mixture?[id] ?? 0f; ref var opacity = ref data.Opacity[i]; if (moles < gas.GasMolesVisible) @@ -216,13 +216,13 @@ private bool UpdateChunkTile(GridAtmosphereComponent gridAtmosphere, GasOverlayC oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity); } - if (tile.Air != null) + if (tile is {Air: not null, NoGridTile: false}) { for (var i = 0; i < VisibleGasId.Length; i++) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = tile.Air.Moles[id]; + var moles = tile.Air[id]; ref var oldOpacity = ref oldData.Opacity[i]; if (moles < gas.GasMolesVisible) diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index 0a2ef235a71..77fd7018333 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; +using Content.Shared.Atmos.EntitySystems; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -17,11 +18,13 @@ public sealed partial class GasMixture : IEquatable, ISerializationH { public static GasMixture SpaceGas => new() {Volume = Atmospherics.CellVolume, Temperature = Atmospherics.TCMB, Immutable = true}; - // This must always have a length that is a multiple of 4 for SIMD acceleration. - [DataField("moles")] - [ViewVariables(VVAccess.ReadWrite)] + // No access, to ensure immutable mixtures are never accidentally mutated. + [Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), Other = AccessPermissions.None)] + [DataField] public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases]; + public float this[int gas] => Moles[gas]; + [DataField("temperature")] [ViewVariables(VVAccess.ReadWrite)] private float _temperature = Atmospherics.TCMB; @@ -80,6 +83,19 @@ public GasMixture(float volume = 0f) Volume = volume; } + public GasMixture(float[] moles, float temp, float volume = Atmospherics.CellVolume) + { + if (moles.Length != Atmospherics.AdjustedNumberOfGases) + throw new InvalidOperationException($"Invalid mole array length"); + + if (volume < 0) + volume = 0; + + _temperature = temp; + Moles = moles; + Volume = volume; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MarkImmutable() { @@ -117,15 +133,16 @@ public void SetMoles(Gas gas, float quantity) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AdjustMoles(int gasId, float quantity) { - if (!Immutable) - { - if (!float.IsFinite(quantity)) - throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); + if (Immutable) + return; - // Clamping is needed because x - x can be negative with floating point numbers. If we don't - // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). - Moles[gasId] = MathF.Max(Moles[gasId] + quantity, 0); - } + if (!float.IsFinite(quantity)) + throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); + + // Clamping is needed because x - x can be negative with floating point numbers. If we don't + // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). + ref var moles = ref Moles[gasId]; + moles = MathF.Max(moles + quantity, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -163,7 +180,8 @@ public GasMixture RemoveRatio(float ratio) { var moles = Moles[i]; var otherMoles = removed.Moles[i]; - if (moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) + + if ((moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) && !Immutable) Moles[i] = 0; if (otherMoles < Atmospherics.GasMinMoles || float.IsNaN(otherMoles)) @@ -202,6 +220,9 @@ public void Multiply(float multiplier) void ISerializationHooks.AfterDeserialization() { + // ISerializationHooks is obsolete. + // TODO add fixed-length-array serializer + // The arrays MUST have a specific length. Array.Resize(ref Moles, Atmospherics.AdjustedNumberOfGases); } @@ -229,8 +250,12 @@ public override bool Equals(object? obj) public bool Equals(GasMixture? other) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + if (ReferenceEquals(this, other)) + return true; + + if (ReferenceEquals(null, other)) + return false; + return Moles.SequenceEqual(other.Moles) && _temperature.Equals(other._temperature) && ReactionResults.SequenceEqual(other.ReactionResults) @@ -258,11 +283,13 @@ public override int GetHashCode() public GasMixture Clone() { + if (Immutable) + return this; + var newMixture = new GasMixture() { Moles = (float[])Moles.Clone(), _temperature = _temperature, - Immutable = Immutable, Volume = Volume, }; return newMixture; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index 64d02d793bc..ad647fad1b8 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -136,7 +136,7 @@ private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent ca for (int i = 0; i < containedGasArray.Length; i++) { - containedGasDict.Add((Gas)i, canister.Air.Moles[i]); + containedGasDict.Add((Gas)i, canister.Air[i]); } _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs index 491bf600627..852542ec6cd 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs @@ -45,7 +45,7 @@ private void OnCondenserUpdated(Entity entity, ref AtmosD var removed = inlet.Air.Remove(molesToConvert); for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { - var moles = removed.Moles[i]; + var moles = removed[i]; if (moles <= 0) continue; diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index 7d385c530a9..71e4c2d0def 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -183,13 +183,7 @@ public void CopyTo(ISerializationManager serializationManager, Dictionary + /// Neighbouring tiles to which air can flow. This is a combination of this tile's unblocked direction, and the + /// unblocked directions on adjacent tiles. + /// [ViewVariables] public AtmosDirection AdjacentBits = AtmosDirection.Invalid; @@ -72,10 +77,7 @@ public sealed class TileAtmosphere : IGasMixtureHolder public EntityUid GridIndex { get; set; } [ViewVariables] - public TileRef? Tile => GridIndices.GetTileRef(GridIndex); - - [ViewVariables] - public Vector2i GridIndices { get; } + public Vector2i GridIndices; [ViewVariables] public ExcitedGroup? ExcitedGroup { get; set; } @@ -92,7 +94,7 @@ public sealed class TileAtmosphere : IGasMixtureHolder public float LastShare; [ViewVariables] - public float[]? MolesArchived; + public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; GasMixture IGasMixtureHolder.Air { @@ -103,8 +105,31 @@ GasMixture IGasMixtureHolder.Air [ViewVariables] public float MaxFireTemperatureSustained { get; set; } + /// + /// If true, then this tile is directly exposed to the map's atmosphere, either because the grid has no tile at + /// this position, or because the tile type is not airtight. + /// + [ViewVariables] + public bool MapAtmosphere; + + /// + /// If true, this tile does not actually exist on the grid, it only exists to represent the map's atmosphere for + /// adjacent grid tiles. + /// [ViewVariables] - public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid; + public bool NoGridTile; + + /// + /// If true, this tile is queued for processing in + /// + [ViewVariables] + public bool TrimQueued; + + /// + /// Cached information about airtight entities on this tile. This gets updated anytime a tile gets invalidated + /// (i.e., gets added to ). + /// + public AtmosphereSystem.AirtightData AirtightData; public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mixture = null, bool immutable = false, bool space = false) { @@ -112,10 +137,24 @@ public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mix GridIndices = gridIndices; Air = mixture; Space = space; - MolesArchived = Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; if(immutable) Air?.MarkImmutable(); } + + public TileAtmosphere(TileAtmosphere other) + { + GridIndex = other.GridIndex; + GridIndices = other.GridIndices; + Space = other.Space; + NoGridTile = other.NoGridTile; + MapAtmosphere = other.MapAtmosphere; + Air = other.Air?.Clone(); + Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length); + } + + public TileAtmosphere() + { + } } } diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index b5bac507391..4b60f8814b5 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -77,7 +77,7 @@ public void GasToReagent(EntityUid uid, LungComponent lung) foreach (var gas in Enum.GetValues()) { var i = (int) gas; - var moles = lung.Air.Moles[i]; + var moles = lung.Air[i]; if (moles <= 0) continue; var reagent = _atmosphereSystem.GasReagents[i]; diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs index e12cab80a91..e7466fbc85d 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs @@ -16,12 +16,15 @@ public sealed partial class ModifyLungGas : ReagentEffect public override void Effect(ReagentEffectArgs args) { - if (args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) + if (!args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) + return; + + foreach (var (gas, ratio) in _ratios) { - foreach (var (gas, ratio) in _ratios) - { - lung.Air.Moles[(int) gas] += (ratio * args.Quantity.Float()) / Atmospherics.BreathMolesToReagentMultiplier; - } + var quantity = ratio * args.Quantity.Float() / Atmospherics.BreathMolesToReagentMultiplier; + if (quantity < 0) + quantity = Math.Max(quantity, -lung.Air[(int)gas]); + lung.Air.AdjustMoles(gas, quantity); } } } diff --git a/Content.Server/Construction/Conditions/ComponentInTile.cs b/Content.Server/Construction/Conditions/ComponentInTile.cs index 8ab4046a721..36705e4c0ee 100644 --- a/Content.Server/Construction/Conditions/ComponentInTile.cs +++ b/Content.Server/Construction/Conditions/ComponentInTile.cs @@ -3,6 +3,7 @@ using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Utility; namespace Content.Server.Construction.Conditions @@ -48,7 +49,15 @@ public bool Condition(EntityUid uid, IEntityManager entityManager) var indices = transform.Coordinates.ToVector2i(entityManager, IoCManager.Resolve()); var lookup = entityManager.EntitySysManager.GetEntitySystem(); - var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Static, lookup); + + + if (!entityManager.TryGetComponent(transform.GridUid.Value, out var grid)) + return !HasEntity; + + if (!entityManager.System().TryGetTileRef(transform.GridUid.Value, grid, indices, out var tile)) + return !HasEntity; + + var entities = tile.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, lookup); foreach (var ent in entities) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 31451c425f5..4a9477e7443 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -475,7 +475,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef) return; - if (tileDef.IsSpace) + if (tileDef.MapAtmosphere) canCreateVacuum = true; // is already a vacuum. int tileBreakages = 0; @@ -491,7 +491,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileDef.BaseTurf] is not ContentTileDefinition newDef) break; - if (newDef.IsSpace && !canCreateVacuum) + if (newDef.MapAtmosphere && !canCreateVacuum) break; tileDef = newDef; diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index c4c2300870d..83cf9b9cb2d 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -1001,20 +1001,13 @@ public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, light.AmbientLightColor = Color.FromHex("#D8B059"); Dirty(mapUid, light, metadata); - // Atmos - var atmos = EnsureComp(mapUid); - var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - var mixture = new GasMixture(2500) - { - Temperature = 293.15f, - Moles = moles, - }; + var mixture = new GasMixture(moles, Atmospherics.T20C); - _atmos.SetMapAtmosphere(mapUid, false, mixture, atmos); + _atmos.SetMapAtmosphere(mapUid, false, mixture); } /// diff --git a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs index c61599edfc9..76cf90c3693 100644 --- a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs +++ b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs @@ -37,7 +37,7 @@ private void OnDeviceUpdated(EntityUid uid, GasPowerReceiverComponent component, if (pipe.Air.Temperature <= component.MaxTemperature) { // we have enough gas, so we consume it and are powered - if (pipe.Air.Moles[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) + if (pipe.Air[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) { pipe.Air.AdjustMoles(component.TargetGas, -component.MolesConsumedSec * timeDelta); SetPowered(uid, component, true); diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 2776db2283a..e2b17b58724 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -125,11 +125,7 @@ protected override async Task Process() air.Gases.CopyTo(moles, 0); var atmos = _entManager.EnsureComponent(mapUid); _entManager.System().SetMapSpace(mapUid, air.Space, atmos); - _entManager.System().SetMapGasMixture(mapUid, new GasMixture(2500) - { - Temperature = mission.Temperature, - Moles = moles, - }, atmos); + _entManager.System().SetMapGasMixture(mapUid, new GasMixture(moles, mission.Temperature), atmos); if (mission.Color != null) { diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 89951718236..5b2f3298a2b 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -18,6 +18,7 @@ namespace Content.Server.Spreader; /// public sealed class SpreaderSystem : EntitySystem { + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; @@ -33,6 +34,8 @@ public sealed class SpreaderSystem : EntitySystem // TODO PERFORMANCE Assign each prototype to an index and convert dictionary to array private readonly Dictionary> _gridUpdates = []; + private EntityQuery _query; + public const float SpreadCooldownSeconds = 1; [ValidatePrototypeId] @@ -47,6 +50,8 @@ public override void Initialize() SubscribeLocalEvent(OnTerminating); SetupPrototypes(); + + _query = GetEntityQuery(); } private void OnPrototypeReload(PrototypesReloadedEventArgs obj) @@ -66,13 +71,7 @@ private void SetupPrototypes() private void OnAirtightChanged(ref AirtightChanged ev) { - var neighbors = GetSpreadableNeighbors(ev.Entity, ev.Airtight, ev.Position); - - foreach (var neighbor in neighbors) - { - if (!TerminatingOrDeleted(neighbor)) - EnsureComp(neighbor); - } + ActivateSpreadableNeighbors(ev.Entity, ev.Position); } private void OnGridInit(GridInitializeEvent ev) @@ -82,13 +81,7 @@ private void OnGridInit(GridInitializeEvent ev) private void OnTerminating(Entity entity, ref EntityTerminatingEvent args) { - var neighbors = GetSpreadableNeighbors(entity); - - foreach (var neighbor in neighbors) - { - if (!TerminatingOrDeleted(neighbor)) - EnsureComp(neighbor); - } + ActivateSpreadableNeighbors(entity); } /// @@ -254,8 +247,7 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId - /// Given an entity, this returns a list of all adjacent entities with a . + /// This function activates all spreaders that are adjacent to a given entity. This also activates other spreaders + /// on the same tile as the current entity (for thin airtight entities like windoors). /// - public List GetSpreadableNeighbors(EntityUid uid, AirtightComponent? comp = null, - (EntityUid Grid, Vector2i Tile)? position = null) + public void ActivateSpreadableNeighbors(EntityUid uid, (EntityUid Grid, Vector2i Tile)? position = null) { - Resolve(uid, ref comp, false); - var neighbors = new List(); - Vector2i tile; EntityUid ent; MapGridComponent? grid; @@ -315,37 +303,40 @@ public List GetSpreadableNeighbors(EntityUid uid, AirtightComponent? { var transform = Transform(uid); if (!TryComp(transform.GridUid, out grid) || TerminatingOrDeleted(transform.GridUid.Value)) - return neighbors; + return; + tile = _map.TileIndicesFor(transform.GridUid.Value, grid, transform.Coordinates); ent = transform.GridUid.Value; } else { if (!TryComp(position.Value.Grid, out grid)) - return neighbors; - tile = position.Value.Tile; - ent = position.Value.Grid; + return; + (ent, tile) = position.Value; } - var spreaderQuery = GetEntityQuery(); + var anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, tile); + while (anchored.MoveNext(out var entity)) + { + if (entity == ent) + continue; + DebugTools.Assert(Transform(entity.Value).Anchored); + if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) + EnsureComp(entity.Value); + } for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - if (comp != null && !comp.AirBlockedDirection.IsFlagSet(direction)) - continue; + var adjacentTile = SharedMapSystem.GetDirection(tile, direction.ToDirection()); + anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, adjacentTile); - var directionEnumerator = - _map.GetAnchoredEntitiesEnumerator(ent, grid, SharedMapSystem.GetDirection(tile, direction.ToDirection())); - - while (directionEnumerator.MoveNext(out var entity)) + while (anchored.MoveNext(out var entity)) { DebugTools.Assert(Transform(entity.Value).Anchored); - if (spreaderQuery.HasComponent(entity) && !TerminatingOrDeleted(entity.Value)) - neighbors.Add(entity.Value); + if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) + EnsureComp(entity.Value); } } - - return neighbors; } } diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index 7460e08e46f..6a8587ca239 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -8,11 +8,6 @@ namespace Content.Shared.Atmos /// public static class Atmospherics { - static Atmospherics() - { - AdjustedNumberOfGases = MathHelper.NextMultipleOf(TotalNumberOfGases, 4); - } - #region ATMOS /// /// The universal gas constant, in kPa*L/(K*mol) @@ -183,7 +178,7 @@ static Atmospherics() /// This is the actual length of the gases arrays in mixtures. /// Set to the closest multiple of 4 relative to for SIMD reasons. /// - public static readonly int AdjustedNumberOfGases; + public const int AdjustedNumberOfGases = ((TotalNumberOfGases + 3) / 4) * 4; /// /// Amount of heat released per mole of burnt hydrogen or tritium (hydrogen isotope) diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs index eb0079eb358..f468724db33 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs @@ -66,7 +66,10 @@ public static Vector2i GetGasChunkIndices(Vector2i indices) [Serializable, NetSerializable] public readonly struct GasOverlayData : IEquatable { + [ViewVariables] public readonly byte FireState; + + [ViewVariables] public readonly byte[] Opacity; // TODO change fire color based on temps diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index ce7980509eb..32f5db0e821 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -81,7 +81,11 @@ public sealed partial class ContentTileDefinition : IPrototype, IInheritingProto [DataField("itemDrop", customTypeSerializer:typeof(PrototypeIdSerializer))] public string ItemDropPrototypeName { get; private set; } = "FloorTileItemSteel"; - [DataField("isSpace")] public bool IsSpace { get; private set; } + // TODO rename data-field in yaml + /// + /// Whether or not the tile is exposed to the map's atmosphere. + /// + [DataField("isSpace")] public bool MapAtmosphere { get; private set; } /// /// Friction override for mob mover in diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs index a87b8c97d15..58a5d133b55 100644 --- a/Content.Shared/Maps/TurfHelpers.cs +++ b/Content.Shared/Maps/TurfHelpers.cs @@ -11,22 +11,6 @@ namespace Content.Shared.Maps // That, or make the interface arguments non-optional so people stop failing to pass them in. public static class TurfHelpers { - /// - /// Attempts to get the turf at map indices with grid id or null if no such turf is found. - /// - public static TileRef GetTileRef(this Vector2i vector2i, EntityUid gridId, IMapManager? mapManager = null) - { - mapManager ??= IoCManager.Resolve(); - - if (!mapManager.TryGetGrid(gridId, out var grid)) - return default; - - if (!grid.TryGetTileRef(vector2i, out var tile)) - return default; - - return tile; - } - /// /// Attempts to get the turf at a certain coordinates or null if no such turf is found. /// @@ -67,7 +51,7 @@ public static ContentTileDefinition GetContentTileDefinition(this Tile tile, ITi /// public static bool IsSpace(this Tile tile, ITileDefinitionManager? tileDefinitionManager = null) { - return tile.GetContentTileDefinition(tileDefinitionManager).IsSpace; + return tile.GetContentTileDefinition(tileDefinitionManager).MapAtmosphere; } /// @@ -115,15 +99,6 @@ public static IEnumerable GetEntitiesInTile(this EntityCoordinates co return GetEntitiesInTile(turf.Value, flags, lookupSystem); } - /// - /// Helper that returns all entities in a turf. - /// - [Obsolete("Use the lookup system")] - public static IEnumerable GetEntitiesInTile(this Vector2i indices, EntityUid gridId, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null) - { - return GetEntitiesInTile(indices.GetTileRef(gridId), flags, lookupSystem); - } - /// /// Checks if a turf has something dense on it. /// diff --git a/Resources/Locale/en-US/atmos/commands.ftl b/Resources/Locale/en-US/atmos/commands.ftl new file mode 100644 index 00000000000..692908d42ad --- /dev/null +++ b/Resources/Locale/en-US/atmos/commands.ftl @@ -0,0 +1,8 @@ +cmd-set-map-atmos-desc = Sets a map's atmosphere +cmd-set-map-atmos-help = setmapatmos [ [moles...]] +cmd-set-map-atmos-removed = Atmosphere removed from map {$map} +cmd-set-map-atmos-updated = Atmosphere set for map {$map} +cmd-set-map-atmos-hint-map = +cmd-set-map-atmos-hint-space = +cmd-set-map-atmos-hint-temp = (float) +cmd-set-map-atmos-hint-gas = <{$gas} moles> (float) From eb7a08980e85c492789d899b2e18520002233f27 Mon Sep 17 00:00:00 2001 From: SimpleStation14 <130339894+SimpleStation14@users.noreply.github.com> Date: Mon, 20 May 2024 15:56:20 -0700 Subject: [PATCH 07/10] Mirror: Store keybind priority (#365) ## Mirror of PR #26356: [Store keybind priority](https://github.com/space-wizards/space-station-14/pull/26356) from space-wizards [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `f7a1ffd0aab25d70ac185753d596469fc1e87480` PR opened by wrexbe at 2024-03-23 02:49:07 UTC --- PR changed 2 files with 2 additions and 1 deletions. The PR had the following labels: - Changes: UI ---

Original Body

> Changed it so the priority isn't lost when you set a binding in the UI. > Also added a priority to MoveStoredItem so it doesn't conflict with Use. > Fixes https://github.com/space-wizards/space-station-14/issues/26142 > Does not fix old keybinds files, so they will need to reset it, and rebind it. > > A better solution might be to change it so the keybinds are always in the order they appear in the default keybinds folder, to prevent the ordering from changing unpredictably based on what the user overrides.
Co-authored-by: SimpleStation14 --- Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs | 2 +- Resources/keybinds.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index ce5cf421aef..f0537079b97 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -403,7 +403,7 @@ private void InputManagerOnFirstChanceOnKeyEvent(KeyEventArgs keyEvent, KeyEvent Mod1 = mods[0], Mod2 = mods[1], Mod3 = mods[2], - Priority = 0, + Priority = _currentlyRebinding.Binding?.Priority ?? 0, Type = bindType, CanFocus = key == Keyboard.Key.MouseLeft || key == Keyboard.Key.MouseRight diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index b8cfc40c1c4..346156159a7 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -167,6 +167,7 @@ binds: type: State key: MouseLeft canFocus: true + priority: 10 - function: RotateStoredItem type: State key: MouseRight From e5314b25a1042b431323d46f21e10302da5de19a Mon Sep 17 00:00:00 2001 From: SimpleStation14 <130339894+SimpleStation14@users.noreply.github.com> Date: Mon, 20 May 2024 15:56:51 -0700 Subject: [PATCH 08/10] Mirror: Removed Cannabis from thief objectives (#369) ## Mirror of PR #26412: [Removed Cannabis from thief objectives](https://github.com/space-wizards/space-station-14/pull/26412) from space-wizards [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `b44015bd554eb97a2d4762d7b585c71e43865571` PR opened by ChaseFlorom at 2024-03-24 21:40:14 UTC --- PR changed 3 files with 4 additions and 26 deletions. The PR had the following labels: - No C# - Status: Needs Review ---

Original Body

> > > > ## About the PR > > > Removed the cannabis objective from the thief objectives. > > ## Why / Balance > > > 20-30 cannabis leaves is neither fun for the thief, or for the botanist that they're asking to grow it. It doesn't fit with the heart of the thief objective system, as the only real way to accomplish it is to ask the botanist to grow it for you, or grow it yourself. Neither of which is stealing. > > Resolve [#26321] > > ## Technical details > > Removed the proper .yml code. > ## Media > > > - [x] I have added screenshots/videos to this PR showcasing its changes ingame, **or** this PR does not require an ingame showcase > > ## Breaking changes > > > **Changelog** > > :cl: > - remove: removed cannabis thief objective.
Co-authored-by: SimpleStation14 --- .../Objects/Specific/Hydroponics/leaves.yml | 8 ++------ .../Prototypes/Objectives/stealTargetGroups.yml | 7 +------ Resources/Prototypes/Objectives/thief.yml | 15 +-------------- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml index e87fec22acc..b847416211d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml @@ -17,8 +17,7 @@ reagents: - ReagentId: THC Quantity: 15 - - type: StealTarget - stealGroup: Cannabis + - type: entity name: dried cannabis leaves @@ -38,8 +37,6 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/tobacco.rsi state: dried - - type: StealTarget - stealGroup: Cannabis - type: entity name: ground cannabis @@ -68,8 +65,7 @@ - Smokable - type: Item size: Tiny - - type: StealTarget - stealGroup: Cannabis + - type: entity name: tobacco leaves diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index fb1e5e76fc0..006c061666b 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -142,12 +142,7 @@ sprite: Objects/Misc/id_cards.rsi state: default -- type: stealTargetGroup - id: Cannabis - name: cannabis - sprite: - sprite: Objects/Specific/Hydroponics/cannabis.rsi - state: produce + - type: stealTargetGroup id: LAMP diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 66258870d61..18154850973 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -142,20 +142,7 @@ - type: Objective difficulty: 0.7 -- type: entity - noSpawn: true - parent: BaseThiefStealCollectionObjective - id: CannabisStealCollectionObjective - components: - - type: NotJobRequirement - job: Botanist - - type: StealCondition - stealGroup: Cannabis - minCollectionSize: 20 - maxCollectionSize: 30 - verifyMapExistence: false - - type: Objective - difficulty: 0.5 + - type: entity noSpawn: true From feb7db5db8edad714fcf89a0555ac2a0bd622bb9 Mon Sep 17 00:00:00 2001 From: SimpleStation14 <130339894+SimpleStation14@users.noreply.github.com> Date: Mon, 20 May 2024 15:57:19 -0700 Subject: [PATCH 09/10] Mirror: Gives borg industrial welder (#370) ## Mirror of PR #26332: [Gives borg industrial welder](https://github.com/space-wizards/space-station-14/pull/26332) from space-wizards [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `1dff97901d5c4ea3f23cf29a9e6f1c2edebdbc27` PR opened by SoulFN at 2024-03-22 09:48:46 UTC --- PR changed 1 files with 1 additions and 1 deletions. The PR had the following labels: - No C# ---

Original Body

> > > > ## About the PR > Changes basic welder in borg tool module to industrial welder > > > ## Why / Balance > Basic welder sucks > > > ## Technical details > No > > > ## Media > > > - This PR does not require an ingame showcase > > ## Breaking changes > No > > > **Changelog** > :cl: > - tweak: The borg tool module now has an industrial welding tool. > > > >
Co-authored-by: SimpleStation14 --- .../Entities/Objects/Specific/Robotics/borg_modules.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 8d195a25bea..e14f29746dc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -177,7 +177,7 @@ - Screwdriver - Wirecutter - Multitool - - Welder + - WelderIndustrial # cargo modules - type: entity From 156dfb61a88293d99024b784d580fec1ef5a3225 Mon Sep 17 00:00:00 2001 From: SimpleStation14 <130339894+SimpleStation14@users.noreply.github.com> Date: Mon, 20 May 2024 15:57:56 -0700 Subject: [PATCH 10/10] Mirror: Code cleanup: Purge obsoleted SharedPhysicsSystem methods (#384) ## Mirror of PR #26287: [Code cleanup: Purge obsoleted SharedPhysicsSystem methods](https://github.com/space-wizards/space-station-14/pull/26287) from space-wizards [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `964c6d54caae45b205a326143f56d6458a1bbc8a` PR opened by Tayrtahn at 2024-03-20 13:37:25 UTC --- PR changed 16 files with 43 additions and 43 deletions. The PR had the following labels: - Status: Needs Review ---

Original Body

> > > > Requires https://github.com/space-wizards/RobustToolbox/pull/4979 > > ## About the PR > > Cleans up some obsolete method calls. > > ## Why / Balance / Technical > > Cleaning up obsolete Dirty calls in RT required changing the signatures of some public methods in SharedPhysicsSystem. This updates the calls to those methods here in Content to use the new signatures passing in UIDs. > >
Co-authored-by: SimpleStation14 --- .../Administration/Systems/AdminVerbSystem.Smites.cs | 12 ++++++------ .../AtmosphereSystem.HighPressureDelta.cs | 8 ++++---- .../Chemistry/EntitySystems/VaporSystem.cs | 4 ++-- Content.Server/ImmovableRod/ImmovableRodSystem.cs | 6 +++--- .../ParticleAcceleratorSystem.Emitter.cs | 2 +- .../Physics/Controllers/ChasingWalkSystem.cs | 2 +- .../Systems/ShuttleSystem.FasterThanLight.cs | 8 ++++---- Content.Server/Shuttles/Systems/ShuttleSystem.cs | 8 ++++---- .../StationEvents/Events/MeteorSwarmRule.cs | 6 +++--- Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs | 2 +- .../Movement/Systems/SharedJetpackSystem.cs | 4 ++-- Content.Shared/Throwing/ThrowingSystem.cs | 6 +++--- Content.Shared/Throwing/ThrownItemSystem.cs | 2 +- .../Weapons/Melee/MeleeThrowOnHitSystem.cs | 4 ++-- Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs | 10 +++++----- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- 16 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 8a819f59420..8ee52ad03e7 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -409,7 +409,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) var fixtures = Comp(args.Target); xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, manager: fixtures, body: physics); - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -424,8 +424,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(1.5f, 1.5f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(args.Target, physics, 0f); + _physics.SetAngularDamping(args.Target, physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-pinball-description") @@ -444,7 +444,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, body: physics); - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -454,8 +454,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(8.0f, 8.0f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(args.Target, physics, 0f); + _physics.SetAngularDamping(args.Target, physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-yeet-description") diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index b0c823426d6..77b5bf18af2 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -52,7 +52,7 @@ private void UpdateHighPressure(float frameTime) if (HasComp(uid) && TryComp(uid, out var body)) { - _physics.SetBodyStatus(body, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, body, BodyStatus.OnGround); } if (TryComp(uid, out var fixtures)) @@ -75,7 +75,7 @@ private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent compo if (!TryComp(uid, out var fixtures)) return; - _physics.SetBodyStatus(body, BodyStatus.InAir); + _physics.SetBodyStatus(uid, body, BodyStatus.InAir); foreach (var (id, fixture) in fixtures.Fixtures) { @@ -94,9 +94,9 @@ private void HighPressureMovements(Entity gridAtmospher // TODO ATMOS finish this // Don't play the space wind sound on tiles that are on fire... - if(tile.PressureDifference > 15 && !tile.Hotspot.Valid) + if (tile.PressureDifference > 15 && !tile.Hotspot.Valid) { - if(_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) + if (_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) { var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices); _audio.PlayPvs(SpaceWindSound, coordinates, AudioParams.Default.WithVariation(0.125f).WithVolume(MathHelper.Clamp(tile.PressureDifference / 10, 10, 100))); diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index d945c1f818b..7d3f70bc0d8 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -64,8 +64,8 @@ public void Start(Entity vapor, TransformComponent vaporXform, V // Set Move if (EntityManager.TryGetComponent(vapor, out PhysicsComponent? physics)) { - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(vapor, physics, 0f); + _physics.SetAngularDamping(vapor, physics, 0f); _throwing.TryThrow(vapor, dir, speed, user: user); diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 0fa8f7d292f..31aa39cf03a 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -53,9 +53,9 @@ private void OnMapInit(EntityUid uid, ImmovableRodComponent component, MapInitEv { if (EntityManager.TryGetComponent(uid, out PhysicsComponent? phys)) { - _physics.SetLinearDamping(phys, 0f); - _physics.SetFriction(phys, 0f); - _physics.SetBodyStatus(phys, BodyStatus.InAir); + _physics.SetLinearDamping(uid, phys, 0f); + _physics.SetFriction(uid, phys, 0f); + _physics.SetBodyStatus(uid, phys, BodyStatus.InAir); if (!component.RandomizeVelocity) return; diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs index 46b25163cc0..06f1b6b154c 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs @@ -28,7 +28,7 @@ private void FireEmitter(EntityUid uid, ParticleAcceleratorPowerState strength, if (TryComp(emitted, out var particlePhys)) { var angle = _transformSystem.GetWorldRotation(uid, xformQuery); - _physicsSystem.SetBodyStatus(particlePhys, BodyStatus.InAir); + _physicsSystem.SetBodyStatus(emitted, particlePhys, BodyStatus.InAir); var velocity = angle.ToWorldVec() * 20f; if (TryComp(uid, out var phys)) diff --git a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs index 215e7e3124e..618dd4156fc 100644 --- a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs +++ b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs @@ -97,6 +97,6 @@ private void ForceImpulse(EntityUid uid, ChasingWalkComponent component) var speed = delta.Length() > 0 ? delta.Normalized() * component.Speed : Vector2.Zero; _physics.SetLinearVelocity(uid, speed); - _physics.SetBodyStatus(physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. + _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. } } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index f9ceab8f7b1..e4e4534b0c5 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -371,8 +371,8 @@ private void UpdateFTLStarting(Entity entity) Enable(uid, component: body); _physics.SetLinearVelocity(uid, new Vector2(0f, 20f), body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(body, 0f); - _physics.SetAngularDamping(body, 0f); + _physics.SetLinearDamping(uid, body, 0f); + _physics.SetAngularDamping(uid, body, 0f); _dockSystem.SetDockBolts(uid, true); _console.RefreshShuttleConsoles(uid); @@ -426,8 +426,8 @@ private void UpdateFTLArriving(Entity entity) _physics.SetLinearVelocity(uid, Vector2.Zero, body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(body, entity.Comp2.LinearDamping); - _physics.SetAngularDamping(body, entity.Comp2.AngularDamping); + _physics.SetLinearDamping(uid, body, entity.Comp2.LinearDamping); + _physics.SetAngularDamping(uid, body, entity.Comp2.AngularDamping); var target = entity.Comp1.TargetCoordinates; diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 8d44dae4b2e..7c42753a7de 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -129,10 +129,10 @@ public void Enable(EntityUid uid, FixturesComponent? manager = null, PhysicsComp return; _physics.SetBodyType(uid, BodyType.Dynamic, manager: manager, body: component); - _physics.SetBodyStatus(component, BodyStatus.InAir); + _physics.SetBodyStatus(uid, component, BodyStatus.InAir); _physics.SetFixedRotation(uid, false, manager: manager, body: component); - _physics.SetLinearDamping(component, shuttle.LinearDamping); - _physics.SetAngularDamping(component, shuttle.AngularDamping); + _physics.SetLinearDamping(uid, component, shuttle.LinearDamping); + _physics.SetAngularDamping(uid, component, shuttle.AngularDamping); } public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsComponent? component = null) @@ -141,7 +141,7 @@ public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsCom return; _physics.SetBodyType(uid, BodyType.Static, manager: manager, body: component); - _physics.SetBodyStatus(component, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, component, BodyStatus.OnGround); _physics.SetFixedRotation(uid, true, manager: manager, body: component); } diff --git a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs index 192a620c9fc..ad56479b379 100644 --- a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs +++ b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs @@ -68,9 +68,9 @@ protected override void ActiveTick(EntityUid uid, MeteorSwarmRuleComponent compo var spawnPosition = new MapCoordinates(center + offset, mapId); var meteor = Spawn("MeteorLarge", spawnPosition); var physics = EntityManager.GetComponent(meteor); - _physics.SetBodyStatus(physics, BodyStatus.InAir); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetBodyStatus(meteor, physics, BodyStatus.InAir); + _physics.SetLinearDamping(meteor, physics, 0f); + _physics.SetAngularDamping(meteor, physics, 0f); _physics.ApplyLinearImpulse(meteor, -offset.Normalized() * component.MeteorVelocity * physics.Mass, body: physics); _physics.ApplyAngularImpulse( meteor, diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index b58bdf83e49..8172947a039 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -358,7 +358,7 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid if (TryComp(buckleUid, out var physics)) { - _physics.ResetDynamics(physics); + _physics.ResetDynamics(buckleUid, physics); } if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index abe12b79d1a..8c42511f846 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -92,7 +92,7 @@ private void SetupUser(EntityUid user, EntityUid jetpackUid) _mover.SetRelay(user, jetpackUid); if (TryComp(user, out var physics)) - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(user, physics, BodyStatus.InAir); userComp.Jetpack = jetpackUid; } @@ -103,7 +103,7 @@ private void RemoveUser(EntityUid uid) return; if (TryComp(uid, out var physics)) - _physics.SetBodyStatus(physics, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); RemComp(uid); } diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 54294318315..01682863389 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -160,7 +160,7 @@ public void TryThrow(EntityUid uid, } else { - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); } if (user == null) @@ -176,10 +176,10 @@ public void TryThrow(EntityUid uid, { var msg = new ThrowPushbackAttemptEvent(); RaiseLocalEvent(uid, msg); - const float MassLimit = 5f; + const float massLimit = 5f; if (!msg.Cancelled) - _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(MassLimit, physics.Mass), body: userPhysics); + _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(massLimit, physics.Mass), body: userPhysics); } } } diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index b3b5bcf7870..cc50094e3dd 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -93,7 +93,7 @@ public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent) { if (TryComp(uid, out var physics)) { - _physics.SetBodyStatus(physics, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); if (physics.Awake) _broadphase.RegenerateContacts(uid, physics); diff --git a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs index e840bd1ddd5..e0696022606 100644 --- a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs +++ b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs @@ -74,7 +74,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar comp.PreviousStatus = body.BodyStatus; comp.ThrownEndTime = _timing.CurTime + TimeSpan.FromSeconds(comp.Lifetime); comp.MinLifetimeTime = _timing.CurTime + TimeSpan.FromSeconds(comp.MinLifetime); - _physics.SetBodyStatus(body, BodyStatus.InAir); + _physics.SetBodyStatus(ent, body, BodyStatus.InAir); _physics.SetLinearVelocity(ent, Vector2.Zero, body: body); _physics.ApplyLinearImpulse(ent, comp.Velocity * body.Mass, body: body); Dirty(ent, ent.Comp); @@ -83,7 +83,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar private void OnThrownShutdown(Entity ent, ref ComponentShutdown args) { if (TryComp(ent, out var body)) - _physics.SetBodyStatus(body,ent.Comp.PreviousStatus); + _physics.SetBodyStatus(ent, body, ent.Comp.PreviousStatus); var ev = new MeleeThrowOnHitEndEvent(); RaiseLocalEvent(ent, ref ev); } diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs index 177cb310d18..3a950bcd29e 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -207,12 +207,12 @@ protected virtual void StartTether(EntityUid gunUid, BaseForceGunComponent compo TransformSystem.Unanchor(target, targetXform); component.Tethered = target; var tethered = EnsureComp(target); - _physics.SetBodyStatus(targetPhysics, BodyStatus.InAir, false); + _physics.SetBodyStatus(target, targetPhysics, BodyStatus.InAir, false); _physics.SetSleepingAllowed(target, targetPhysics, false); tethered.Tetherer = gunUid; tethered.OriginalAngularDamping = targetPhysics.AngularDamping; - _physics.SetAngularDamping(targetPhysics, 0f); - _physics.SetLinearDamping(targetPhysics, 0f); + _physics.SetAngularDamping(target, targetPhysics, 0f); + _physics.SetLinearDamping(target, targetPhysics, 0f); _physics.SetAngularVelocity(target, SpinVelocity, body: targetPhysics); _physics.WakeBody(target, body: targetPhysics); var thrown = EnsureComp(component.Tethered.Value); @@ -264,9 +264,9 @@ protected virtual void StopTether(EntityUid gunUid, BaseForceGunComponent compon _thrown.StopThrow(component.Tethered.Value, thrown); } - _physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround); + _physics.SetBodyStatus(component.Tethered.Value, targetPhysics, BodyStatus.OnGround); _physics.SetSleepingAllowed(component.Tethered.Value, targetPhysics, true); - _physics.SetAngularDamping(targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); + _physics.SetAngularDamping(component.Tethered.Value, targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); } if (!transfer) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 36b5bbd1927..d3aee5a48e9 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -388,7 +388,7 @@ public abstract void Shoot( public void ShootProjectile(EntityUid uid, Vector2 direction, Vector2 gunVelocity, EntityUid gunUid, EntityUid? user = null, float speed = 20f) { var physics = EnsureComp(uid); - Physics.SetBodyStatus(physics, BodyStatus.InAir); + Physics.SetBodyStatus(uid, physics, BodyStatus.InAir); var targetMapVelocity = gunVelocity + direction.Normalized() * speed; var currentMapVelocity = Physics.GetMapLinearVelocity(uid, physics);