Compare commits

...

42 Commits

Author SHA1 Message Date
Pieter-Jan Briers
73885cf74e Version: 208.0.3 2024-08-11 19:32:38 +02:00
Pieter-Jan Briers
fe725d0028 Compile compat fixes
(cherry picked from commit 025d90d281)
(cherry picked from commit 799702b814)
(cherry picked from commit 4600ee8e5788891f1b610e2d5141fb4e1228d323)
2024-08-11 19:32:37 +02:00
Pieter-Jan Briers
4a1ed6cff3 Version: 208.0.2 2024-08-11 17:56:11 +02:00
Pieter-Jan Briers
7194c77653 Security updates (#5353)
* Fix security bug in WritableDirProvider.OpenOsWindow()

Reported by @NarryG and @nyeogmi

* Sandbox updates

* Update ImageSharp again

(cherry picked from commit 7d778248ee)
(cherry picked from commit f66cda74e95619ddba2221bda644bf4394619805)
(cherry picked from commit db8ba83866c523e08e4fba0b80cd954f4f190613)
2024-08-11 17:56:11 +02:00
Pieter-Jan Briers
e29e1a786d Version: 208.0.1 2024-03-10 21:09:04 +01:00
Pieter-Jan Briers
a38887cf9f YIPPEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE IMAGESHARP VULNERABILITY
(cherry picked from commit 859f150404)
2024-03-10 21:09:04 +01:00
metalgearsloth
ca82767b07 Version: 208.0.0 2024-01-25 17:47:44 +11:00
Kevin Zheng
76024330a7 Do not crash failing to load user keybindings (#4844) 2024-01-25 17:44:34 +11:00
metalgearsloth
21e8107eb1 Don't serialize metadata flags (#4861)
* Don't serialize metadata flags

Probably fine, saves us saving it to map files.

* Release notes
2024-01-25 17:44:16 +11:00
metalgearsloth
bcaa97a79b Version: 207.1.0 2024-01-21 18:55:44 +11:00
metalgearsloth
19727f6a25 Localise merge_grids command (#4850) 2024-01-21 18:20:21 +11:00
metalgearsloth
2102b96323 Update uploadfile dependencies (#4849)
* Update uploadfile dependencies

Also removed the 1 warning in there.

* Thanks rider
2024-01-21 18:20:13 +11:00
metalgearsloth
59b3ffda4f Add grid merging (#3627)
* Add grid merging

* More preliminary cleanup

* Fixes

* Fixes

* weh

* tweaks

* Tests

* weh

* Fix direction test

* Release notes
2024-01-21 17:41:04 +11:00
metalgearsloth
aae929966c Add NotNullWhen true to EntMan HasComp (#4848)
The proxy methods already have it but not the interface itself.
2024-01-20 15:03:47 +11:00
metalgearsloth
0cf842cacc Version: 207.0.0 2024-01-19 13:30:24 +11:00
metalgearsloth
96885c5b53 Quick lookup fix (#4847)
* Quick lookup fix

Forgor to push, just makes the Box2Rotated query use polyshape so it's accurate.

* a
2024-01-19 13:28:29 +11:00
metalgearsloth
d45ce7742e Entitylookup approx / shape changes (#4842)
* Entitylookup approx / shape changes

- Make the shape queries respect the approx flag.
- Make everything use shape queries.
- Hopefully reduce some of the internal cruft.
- Add some new methods I need for trade station.

* Bunch of deduplication

* Remove some more duplication abuse

* Remove intersection duplication

* Bunch more cleanup

* MapManager rejig

* Fix some stuff

* More fixes

* Release notes

* Fix TryFindGrid

* Sensor check

* Fix query

* Fix map queries

* More cleanup

* Fix whatever this is.

* also dis

* Fix entity query

* Smol optimisations

* Also this
2024-01-19 13:02:22 +11:00
Kot
50e27fd204 Fix full state updates (#4833)
* Clear entities seen by a session when the full update is requested

* Disable PVS budged for the full update

It helps preventing weird intermediate states when a client observes
themselves in a void with all the alert notifications going wild.
However it introduces a spike on CPU and networking.

* Add changelog line

* Move the changelog line to the proper place

* Update RELEASE-NOTES.md

* Revert "Disable PVS budged for the full update"

This reverts commit 6976ca04b8.

* Update RELEASE-NOTES.md

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-01-18 17:40:55 +13:00
Pieter-Jan Briers
af98933173 Isolate net messages in integration tests. (#4838)
* Isolate net messages in integration tests.

Integration tests don't use Lidgren to connect client and send, instead they just use some in-process channels to communicate. Because of this, the original implementation of net messages *directly* passed the net message instances between client and server instances. This caused issues whenever content would mutate data in a NetMessage after it "passed through".

Now we run the messages through WriteToBuffer() and ReadFromBuffer() so they pass through binary serialization. This means there's no more implicit sharing of the objects.

Note that this requires some trickery: Lidgren's message types have internal constructors. Really ideally we'd change the engine to make this more testable... but that's a content breaking change. Instead I just added InternalsVisibleTo to Lidgren so we can mess with it. We maintain the library ourselves anyways I can do what I want.

Fixes #4836

* Register Robust.UnitTesting as assembly for reflection.

This is necessary so that serialized types in the assembly can be picked up by NetSerializer.

Have to disable automatic reflection on all entity systems/components that tests register manually right now, because otherwise tests break.

* Stop shallow cloning specific net messages in integration tests.

This isn't necessary anymore now that we have a thorough fix.

* Wow I really forgot to copy-paste that line to the other side huh.

* Add test that serializer hash matches.

* Another test one I missed earlier.

* Changelog
2024-01-16 21:04:39 +01:00
metalgearsloth
e357dada65 Version: 206.0.0 2024-01-14 19:13:14 +11:00
metalgearsloth
19c48862e2 Entitylookup tweaks (#4808)
* Entitylookup tweaks

- Removed a dupe internal method.
- Removed some dupe internal code.
- Renamed some methods in line with local vs non-local.

* Update release

* Also this
2024-01-14 19:10:33 +11:00
metalgearsloth
448ce94b35 Make MIDI update rate comically low (#4830)
Was around this before but apparently avoiding lock contention not hard enough.
2024-01-14 18:19:56 +11:00
metalgearsloth
3681b7f0d5 Cleanup and tweak teleport commands (#4835)
* Cleanup and tweak teleport commands

- Cleanup the code duplication.
- Teleports to grid-local center instead.

* Release notes.
2024-01-14 17:44:02 +11:00
DrSmugleaf
7b3c883653 Add support for forcing prototypes in a file or directory to be parsed as abstract (#4829)
* Add support for forcing prototypes in a file or directory to be parsed as abstract

* Simplify mapping add abstract true call

* Fix docs

* Address reviews
2024-01-13 03:51:36 -08:00
Pieter-Jan Briers
c81004ddb4 Skip serialization generator with SkipRobustAnalyzer
Skips it in GLFW and Lidgren.
2024-01-12 23:18:53 +01:00
Pieter-Jan Briers
f844011348 Version: 205.0.0 2024-01-12 23:08:42 +01:00
Pieter-Jan Briers
0094040d68 Dependency update / fixes / skrungle bungle (#4825)
* Move to Central Package Management.

Allows us to store NuGet package versions all in one place. Yay!

* Update NuGet packages and fix code for changes.

Notable:

Changes to ILVerify.
Npgsql doesn't need hacks for inet anymore, now we need hacks to make the old code work with this new reality.
NUnit's analyzers are already complaining and I didn't even update it to 4.x yet.
TerraFX changed to GetLastSystemError so error handling had to be changed.
Buncha APIs have more NRT annotations.

* Remove dotnet-eng NuGet package source.

I genuinely don't know what this was for, and Central Package Management starts throwing warnings about it, so YEET.

* Fix double loading of assemblies due to ALC shenanigans.

Due to how the "sideloading" code for the ModLoader was set up, it would first try to load Microsoft.Extensions.Primitives from next to the content dll. But we already have that library in Robust!

Chaos ensues.

We now try to forcibly prioritize loading from the default ALC first to avoid this.

* Remove Robust.Physics project.

Never used.

* Remove erroneous NVorbis reference.

Should be VorbisPizza and otherwise wasn't used.

* Sandbox fixes

* Remove unused unit test package references.

Castle.Core and NUnit.ConsoleRunner.

* Update NUnit to 4.0.1

This requires replacing all the old assertion methods because they removed them 🥲

* Mute CA1416 (platform check) errors

TerraFX started annotating APIs with this and I can't be arsed to entertain this analyzer so out it goes.

* Fine ya cranky, no more CPM for Robust.Client.Injectors

* Changelog

* Oh so that's what dotnet-eng was used for. Yeah ok that makes sense.

* Central package management for remaining 2 robust projects

* Ok that was a bad idea let's just use NUnit 3 on the analyzer test project

* Oh right forgot to remove this one

* Update to a newer version of RemoteExecutor

* Disable RemoteExecutor test

https://github.com/dotnet/arcade/issues/8483 Yeah this package is not well maintained and clearly we can't rely on it.

* Fix immutable list serialization
2024-01-12 22:59:52 +01:00
metalgearsloth
dfb5369664 Version: 204.1.0 2024-01-12 12:57:42 +11:00
Pieter-Jan Briers
2462c906b3 Remove Herobrine
Idk according to the changelog I already did this once but clearly I didn't so ???
2024-01-11 02:01:23 +01:00
metalgearsloth
8cbc05840f Remove some unnecessary GetEntityQuery<T> (#4823) 2024-01-10 18:31:32 +01:00
Pieter-Jan Briers
510846321d BUI Improvements / fixes (#4826)
* Extension helper function for registering BUI events filtered to UI key.

Usages of events like BoundUIClosedEvent frequently did not check the UI key or do it improperly. This has, and will continue to cause, bugs.

The new helper (accessible as Subs.BuiEvents() from an entity system) makes it easy to subscribe to BUI events while also filtering to the correct UI key.

Also added missing SubscribeLocalEvent overloads with new handler types to EntitySystem.Subscriptions.

* Sprinkle [ViewVariables] around BUI

* Avoid buggy behavior if a Bound UI is closed inside the `BoundUIOpenedEvent` that's opening it.
2024-01-10 18:30:57 +01:00
metalgearsloth
ac60567583 Version: 204.0.0 2024-01-09 21:52:36 +11:00
metalgearsloth
7592997f4e Add random pick / take methods for sets (#4821)
* Add random pick / take methods for sets

I want it don't at me.

* cleanup (mraow)

* Revert "cleanup (mraow)"

This reverts commit e279957f21.

* flatpak

* notes
2024-01-09 00:37:19 +11:00
Pieter-Jan Briers
c68b3dccb7 Fix server NRE in console command completions.
Happens if you just type "tp:to<space>" into the console.

Toolshed can fail to provide completion results, in which case a null propagates and possibly crashes the server.
2024-01-08 11:18:11 +01:00
Pieter-Jan Briers
da2a2ce4ff Remove "Do not use from content" public members. 2024-01-07 04:43:59 +01:00
Pieter-Jan Briers
538418ea93 Fix exception when VVing non-networked components
The VV code forcibly dirties all components, which trips an assert for non-networked components.
2024-01-07 04:22:38 +01:00
Kara
2bf284bce8 Infer VVAccess.ReadWrite for all datafields (#4442) 2024-01-06 18:27:58 -08:00
Pieter-Jan Briers
b51cb06d53 Changelog for #4818 2024-01-06 19:23:58 +01:00
Kot
bab6c29fbe Add TextEdit.OnTextChanged event (#4818) 2024-01-06 18:59:19 +01:00
Pieter-Jan Briers
9502c86a65 Fix GLFW clipboard sometimes returning null.
Fixes #4817
2024-01-06 18:52:28 +01:00
Pieter-Jan Briers
359811f71e Fix incorrect IPostInjectInit in DebugConsole
IPostInjectInit does not run through IoCManager.InjectDependencies(). This meant the logger was not initialized, and loading failures in the console history would crash the client startup due to an NRE while trying to log a warning.

See https://github.com/space-wizards/space-station-14/issues/23624
2024-01-06 15:47:55 +01:00
DrSmugleaf
9de5840017 Make IEntityManager.EntityNetManager not nullable, make EntityManager abstract (#4445)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-01-07 00:05:02 +11:00
152 changed files with 3219 additions and 1755 deletions

View File

@@ -10,5 +10,8 @@ charset = utf-8
[*.{csproj,xml,yml,dll.config,targets,props}]
indent_size = 2
[nuget.config]
indent_size = 2
[*.gdsl]
indent_style = tab

View File

@@ -33,10 +33,10 @@ jobs:
mkdir "release/${{ steps.parse_version.outputs.version }}"
mv release/*.zip "release/${{ steps.parse_version.outputs.version }}"
- name: Upload files to centcomm
- name: Upload files to Suns
uses: appleboy/scp-action@master
with:
host: centcomm.spacestation14.io
host: suns.spacestation14.com
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
source: "release/${{ steps.parse_version.outputs.version }}"
@@ -46,7 +46,7 @@ jobs:
- name: Update manifest JSON
uses: appleboy/ssh-action@master
with:
host: centcomm.spacestation14.io
host: suns.spacestation14.com
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
script: /home/robust-build-push/push.ps1 ${{ steps.parse_version.outputs.version }}

71
Directory.Packages.props Normal file
View File

@@ -0,0 +1,71 @@
<Project>
<PropertyGroup>
<!--
We actually set ManagePackageVersionsCentrally manually in another import file.
Since .NET SDK 8.0.300, ManagePackageVersionsCentrally is automatically set if Directory.Packages.props exists.
https://github.com/NuGet/NuGet.Client/pull/5572
We actively negate this here, as we have some packages in tree we don't want such automatic behavior for.
We use Directory.Build.props to get copy the state *after* our MSBuild config but before Nuget's config.
-->
<ManagePackageVersionsCentrally />
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.13.12" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="ILReader.Core" Version="1.0.0.4" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageVersion Include="JetBrains.Profiler.Api" Version="1.4.0" />
<PackageVersion Include="Linguini.Bundle" Version="0.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit" Version="1.1.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeCoverage" Version="17.8.0" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="8.0.0" />
<PackageVersion Include="Microsoft.DotNet.RemoteExecutor" Version="8.0.0-beta.24059.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="8.0.0" />
<PackageVersion Include="Microsoft.ILVerification" Version="8.0.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="Microsoft.NET.ILLink.Tasks" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="NUnit" Version="4.0.1" />
<PackageVersion Include="NUnit.Analyzers" Version="3.10.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="Nett" Version="0.15.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
<PackageVersion Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" />
<PackageVersion Include="Pidgin" Version="3.2.2" />
<PackageVersion Include="Robust.Natives" Version="0.1.1" />
<PackageVersion Include="Robust.Natives.Cef" Version="120.1.9" />
<PackageVersion Include="Robust.Shared.AuthLib" Version="0.1.2" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.7" />
<PackageVersion Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.7" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.Sinks.Loki" Version="4.0.0-beta3" />
<PackageVersion Include="SharpZstd.Interop" Version="1.5.2-beta2" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.0" />
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.0.2" />
<PackageVersion Include="SpaceWizards.Sodium" Version="0.2.1" />
<PackageVersion Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageVersion Include="TerraFX.Interop.Windows" Version="10.0.22621.5" />
<PackageVersion Include="TerraFX.Interop.Xlib" Version="6.4.0" />
<PackageVersion Include="VorbisPizza" Version="1.3.0" />
<PackageVersion Include="YamlDotNet" Version="13.7.1" />
<PackageVersion Include="prometheus-net" Version="8.2.1" />
<PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
using System.Runtime.CompilerServices;
// So I wanted to mess with NetIncomingMessage and NetOutgoingMessage from tests.
// Now.. the instructors are internal...
// Unless...
// I mean we have this project here from the weird way we're compiling Lidgren.
// I could just put this in here... it wouldn't touch the main Lidgren repo at all...
[assembly: InternalsVisibleTo("Robust.UnitTesting")]

View File

@@ -16,6 +16,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="CursedHorrorsBeyondOurWildestImagination.cs" />
<Compile Include="Lidgren.Network\Lidgren.Network\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>

View File

@@ -1,4 +1,4 @@
<Project>
<!-- This file automatically reset by Tools/version.py -->
<!-- This file automatically reset by Tools/version.py -->

View File

@@ -4,6 +4,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<Import Project="Robust.Custom.targets" Condition="Exists('Robust.Custom.targets')"/>
@@ -27,5 +28,5 @@
<Import Project="Robust.Analyzers.targets" Condition="'$(SkipRobustAnalyzer)' != 'true'" />
<!-- serialization generator -->
<Import Project="Robust.Serialization.Generator.targets" />
<Import Project="Robust.Serialization.Generator.targets" Condition="'$(SkipRobustAnalyzer)' != 'true'" />
</Project>

View File

@@ -54,6 +54,130 @@ END TEMPLATE-->
*None yet*
## 208.0.3
## 208.0.2
## 208.0.1
## 208.0.0
### Breaking changes
* Metadata flags are no longer serialized as they get rebuilt on entity startup.
### Bugfixes
* Log failing to load user keybinds and handle the exception.
## 207.1.0
### New features
* Add the ability to merge grids via GridFixtureSystem.
## 207.0.0
### Breaking changes
* Update EntityLookup internally so non-approximate queries use the GJK solver and are much more accurate. This also means the approximate flag matters much more if you don't need narrowphase checks.
* Add shape versions of queries for both EntityLookup and MapManager.
### Bugfixes
* Fix PVS full state updates not clearing session entities and causing exceptions.
### Other
* Integration tests now run `NetMessage`s through serialization rather than passing the objects between client and server. This causes tests that missed `[NetSerializer]` attributes on any objects that need them to fail.
### Internal
* Remove a lot of duplicate code internally from EntityLookup and MapManager.
## 206.0.0
### Breaking changes
* tpto will teleport you to physics-center instead of transform center instead.
* Rename local EntityLookup methods to reflect they take local AABBs and not world AABBs.
### New features
* Add some additional EntityLookup methods for local queries.
* Add support to PrototypeManager for parsing specific files / directories as abstract.
### Bugfixes
* Fix tpto short-circuiting if one of the listed entities isn't found.
* Fix tpto not allowing grids as targets.
### Other
* Reduce MIDI source update rate from 10hz to 4hz.
### Internal
* Remove some duplicate internal code in EntityLookupSystem.
* Skip serialization sourcegen in GLFW and Lidgren.
## 205.0.0
### Breaking changes
* The unused `Robust.Physics` project has been deleted.
* The project now uses [Central Package Management](https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management).
* (Almost) all the NuGet packages have been updated. This causes many problems. I am so sorry.
* Cleaned up some unused packages as well.
## 204.1.0
### New features
* New `EntitySystem` subscription helper for working with Bound User Interface events. You can find them by doing `Subs.BuiEvents<>()` in a system.
* The `EntityManager.Subscriptions` type (for building helper extension methods) now uses
### Bugfixes
* Avoid loading assemblies from content `/Assemblies` if Robust ships its own copy. This avoid duplicate or weird mismatching version issues.
### Other
* Removed glibc version check warning.
## 204.0.0
### Breaking changes
* Make EntityManager abstract and make IEntityManager.EntityNetManager not nullable.
* Make VVAccess.ReadWrite default for all Datafields instead of VVAccess.ReadOnly
### New features
* `TextEdit.OnTextChanged`
* Add Pick and PickAndTake versions for System.Random for ICollections.
### Bugfixes
* Fix `IClipboardManager.GetText()` returning null in some cases.
* Fix possible NRE in server-side console command completion code.
* Fix possible NRE on DebugConsole logs.
* Fix exception when VVing non-networked components.
### Other
* Remove "Do not use from content" from IComponent.
## 203.0.0
### Breaking changes
@@ -67,8 +191,8 @@ END TEMPLATE-->
### New features
* `RobustUnitTest` now has a `ExtraComponents` field for automatically registering additional components.
* `IComponentFactory.RegisterIgnore()` now accepts more than one string.
* Added `IComponentFactory.RegisterTypes` for simultaneously registering multiple components.
* `IComponentFactory.RegisterIgnore()` now accepts more than one string.
* Added `IComponentFactory.RegisterTypes` for simultaneously registering multiple components.
### Bugfixes
@@ -82,7 +206,7 @@ END TEMPLATE-->
* Reverted some map/grid initialisation changes that might've been causing broadphase/physics errors.
* Fixed PVS sometimes sending entities without first sending their children.
* Fixed a container state handling bug caused by containers not removing expected entities when shutting down.
* Fixed a `EnsureEntity<T>` state handling bug caused by improper handling of entity deletions.
* Fixed a `EnsureEntity<T>` state handling bug caused by improper handling of entity deletions.
* Fixed a bad NetSyncEnabled debug assert.
@@ -98,7 +222,7 @@ END TEMPLATE-->
### Breaking changes
* Various entity manager methods now have a new `where T : IComponent` constraint.
* The `IComponentFactory.ComponentAdded` event has been renamed to `ComponentsAdded` and now provides an array of component registrations.
* The `IComponentFactory.ComponentAdded` event has been renamed to `ComponentsAdded` and now provides an array of component registrations.
* `IComponentFactory.RegisterIgnore()` no longer supports overwriting existing registrations, components should get ignored before they are registered.
### New features

View File

@@ -0,0 +1,8 @@
cmd-merge_grids-desc = Combines 2 grids into 1 grid
cmd-merge_grids-help = merge_grids <gridUid1> <gridUid2> <offsetX> <offsetY> [angle]
cmd-merge_grids-hintA = Grid A
cmd-merge_grids-hintB = Grid B
cmd-merge_grids-xOffset = X offset
cmd-merge_grids-yOffset = Y offset
cmd-merge_grids-angle = [Angle]

View File

@@ -1,23 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Properties.targets" />
<Import Project="..\MSBuild\Robust.Engine.props" />
<Import Project="..\MSBuild\Robust.Properties.targets"/>
<Import Project="..\MSBuild\Robust.Engine.props"/>
<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.1"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit" Version="1.1.1"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1"/>
<PackageReference Include="NUnit" Version="3.13.2"/>
<PackageReference Include="NUnit.ConsoleRunner" Version="3.15.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.3.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageVersion Update="NUnit" Version="3.14.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzer.Testing"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces"/>
<PackageReference Include="NUnit"/>
<PackageReference Include="NUnit3TestAdapter"/>
<PackageReference Include="NUnit.Analyzers"/>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Robust.Analyzers\Robust.Analyzers.csproj"/>
</ItemGroup>

View File

@@ -3,19 +3,20 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>10</LangVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.0.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" />
</ItemGroup>
<ItemGroup>
<!-- Needed for NotNullableFlagAnalyzer. -->
<Compile Include="..\Robust.Shared\Analyzers\NotNullableFlagAttribute.cs" />
</ItemGroup>
<ItemGroup>
<!-- Needed for FriendAnalyzer. -->
<Compile Include="..\Robust.Shared\Analyzers\AccessAttribute.cs" />

View File

@@ -1,15 +1,18 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Globalization;
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.EventProcessors;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
using Robust.Benchmarks.Exporters;
@@ -44,10 +47,16 @@ public sealed class DefaultSQLConfig : IConfig
public IEnumerable<BenchmarkLogicalGroupRule> GetLogicalGroupRules() => DefaultConfig.Instance.GetLogicalGroupRules();
public IEnumerable<EventProcessor> GetEventProcessors() => DefaultConfig.Instance.GetEventProcessors();
public IEnumerable<IColumnHidingRule> GetColumnHidingRules() => DefaultConfig.Instance.GetColumnHidingRules();
public IOrderer Orderer => DefaultConfig.Instance.Orderer!;
public ICategoryDiscoverer? CategoryDiscoverer => DefaultConfig.Instance.CategoryDiscoverer;
public SummaryStyle SummaryStyle => DefaultConfig.Instance.SummaryStyle;
public ConfigUnionRule UnionRule => DefaultConfig.Instance.UnionRule;
public string ArtifactsPath => DefaultConfig.Instance.ArtifactsPath;
public CultureInfo CultureInfo => DefaultConfig.Instance.CultureInfo!;
public ConfigOptions Options => DefaultConfig.Instance.Options;
public TimeSpan BuildTimeout => DefaultConfig.Instance.BuildTimeout;
public IReadOnlyList<Conclusion> ConfigAnalysisConclusion => DefaultConfig.Instance.ConfigAnalysisConclusion;
}

View File

@@ -13,12 +13,12 @@
<ProjectReference Include="..\Robust.UnitTesting\Robust.UnitTesting.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />

View File

@@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="17.0.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.8.3" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Pidgin" Version="2.5.0" />
</ItemGroup>

View File

@@ -2,11 +2,12 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,8 +8,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
<PackageReference Include="Robust.Natives.Cef" Version="120.1.9" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Robust.Natives.Cef" />
</ItemGroup>
<ItemGroup>

View File

@@ -72,7 +72,7 @@ internal sealed partial class MidiManager : IMidiManager
// To avoid lock contention until some kind of MIDI refactor.
private TimeSpan _nextUpdate;
private TimeSpan _updateFrequency = TimeSpan.FromSeconds(0.1f);
private TimeSpan _updateFrequency = TimeSpan.FromSeconds(0.25f);
private SemaphoreSlim _updateSemaphore = new(1);

View File

@@ -11,7 +11,7 @@ namespace Robust.Client.Console.Commands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var type = Type.GetType(args[0]);
var type = GetType(args[0]);
if (type == null)
{
@@ -25,6 +25,17 @@ namespace Robust.Client.Console.Commands
shell.WriteLine(sig);
}
}
private Type? GetType(string name)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.GetType(name) is { } type)
return type;
}
return null;
}
}
#endif
}

View File

@@ -35,8 +35,6 @@ namespace Robust.Client
throw new InvalidOperationException("Cannot start twice!");
}
GlibcBug.Check();
_hasStarted = true;
if (CommandLineArgs.TryParse(args, out var parsed))

View File

@@ -27,7 +27,6 @@ internal sealed class ClientOccluderSystem : OccluderSystem
base.Initialize();
SubscribeLocalEvent<OccluderComponent, AnchorStateChangedEvent>(OnAnchorChanged);
SubscribeLocalEvent<OccluderComponent, ReAnchorEvent>(OnReAnchor);
SubscribeLocalEvent<OccluderComponent, ComponentShutdown>(OnShutdown);
}
@@ -90,11 +89,6 @@ internal sealed class ClientOccluderSystem : OccluderSystem
AnchorStateChanged(uid, comp, args.Transform);
}
private void OnReAnchor(EntityUid uid, OccluderComponent comp, ref ReAnchorEvent args)
{
AnchorStateChanged(uid, comp, args.Xform);
}
private void QueueOccludedDirectionUpdate(EntityUid sender, OccluderComponent occluder, TransformComponent? xform = null)
{
if (!Resolve(sender, ref xform))
@@ -174,8 +168,9 @@ internal sealed class ClientOccluderSystem : OccluderSystem
var tile = grid.TileIndicesFor(xform.Coordinates);
DebugTools.Assert(occluder.LastPosition == null
|| occluder.LastPosition.Value.Grid == xform.GridUid && occluder.LastPosition.Value.Tile == tile);
// TODO: Sub to parent changes instead or something.
// DebugTools.Assert(occluder.LastPosition == null
// || occluder.LastPosition.Value.Grid == xform.GridUid && occluder.LastPosition.Value.Tile == tile);
occluder.LastPosition = (xform.GridUid.Value, tile);
// dir starts at the relative effective south direction;

View File

@@ -28,6 +28,8 @@ namespace Robust.Client.Graphics.Clyde
private int _verticesPerChunk(MapChunk chunk) => chunk.ChunkSize * chunk.ChunkSize * 4;
private int _indicesPerChunk(MapChunk chunk) => chunk.ChunkSize * chunk.ChunkSize * GetQuadBatchIndexCount();
private List<Entity<MapGridComponent>> _grids = new();
private void _drawGrids(Viewport viewport, Box2 worldAABB, Box2Rotated worldBounds, IEye eye)
{
var mapId = eye.Position.MapId;
@@ -37,14 +39,15 @@ namespace Robust.Client.Graphics.Clyde
mapId = MapId.Nullspace;
}
var grids = new List<Entity<MapGridComponent>>();
_mapManager.FindGridsIntersecting(mapId, worldBounds, ref grids);
_grids.Clear();
_mapManager.FindGridsIntersecting(mapId, worldBounds, ref _grids);
var requiresFlush = true;
GLShaderProgram gridProgram = default!;
var gridOverlays = GetOverlaysForSpace(OverlaySpace.WorldSpaceGrids);
var mapSystem = _entityManager.System<SharedMapSystem>();
foreach (var mapGrid in grids)
foreach (var mapGrid in _grids)
{
if (!_mapChunkData.TryGetValue(mapGrid, out var data))
{
@@ -65,7 +68,7 @@ namespace Robust.Client.Graphics.Clyde
var transform = _entityManager.GetComponent<TransformComponent>(mapGrid);
gridProgram.SetUniform(UniIModelMatrix, transform.WorldMatrix);
var enumerator = mapGrid.Comp.GetMapChunks(worldBounds);
var enumerator = mapSystem.GetMapChunks(mapGrid.Owner, mapGrid.Comp, worldBounds);
while (enumerator.MoveNext(out var chunk))
{

View File

@@ -224,8 +224,8 @@ namespace Robust.Client.Graphics.Clyde
fixed (char* pCaption = "RobustToolbox: Failed to create window")
{
Windows.MessageBoxW(HWND.NULL,
(ushort*) pText,
(ushort*) pCaption,
pText,
pCaption,
MB.MB_OK | MB.MB_ICONERROR);
}
}

View File

@@ -413,7 +413,7 @@ namespace Robust.Client.Graphics.Clyde
DXGI_ADAPTER_DESC1 desc;
ThrowIfFailed("GetDesc1", _adapter->GetDesc1(&desc));
var descName = new ReadOnlySpan<char>(desc.Description, 128).TrimEnd('\0');
var descName = ((ReadOnlySpan<char>)desc.Description).TrimEnd('\0');
Logger.DebugS("clyde.ogl.angle", "Successfully created D3D11 device!");
Logger.DebugS("clyde.ogl.angle", $"D3D11 Device Adapter: {descName.ToString()}");
@@ -493,7 +493,7 @@ namespace Robust.Client.Graphics.Clyde
DXGI_ADAPTER_DESC1 desc;
ThrowIfFailed("GetDesc1", adapter->GetDesc1(&desc));
var descName = new ReadOnlySpan<char>(desc.Description, 128);
var descName = ((ReadOnlySpan<char>)desc.Description);
if (descName.StartsWith(name))
return adapter;

View File

@@ -36,7 +36,7 @@ namespace Robust.Client.Graphics.Clyde
adapter->Release();
ThrowIfFailed("GetDesc", adapter3->GetDesc2(&desc));
var descString = new ReadOnlySpan<char>(desc.Description, 128).TrimEnd('\0');
var descString = ((ReadOnlySpan<char>)desc.Description).TrimEnd('\0');
shell.WriteLine(descString.ToString());
DXGI_QUERY_VIDEO_MEMORY_INFO memInfo;

View File

@@ -654,7 +654,7 @@ namespace Robust.Client.Graphics.Clyde
private static void WinThreadGetClipboard(CmdGetClipboard cmd)
{
var clipboard = GLFW.GetClipboardString((Window*) cmd.Window);
var clipboard = GLFW.GetClipboardString((Window*) cmd.Window) ?? "";
// Don't have to care about synchronization I don't think so just fire this immediately.
cmd.Tcs.TrySetResult(clipboard);
}

View File

@@ -124,7 +124,14 @@ namespace Robust.Client.Input
var path = new ResPath(KeybindsPath);
if (_resourceMan.UserData.Exists(path))
{
LoadKeyFile(path, true);
try
{
LoadKeyFile(path, true);
}
catch (Exception e)
{
Logger.ErrorS("input", "Failed to load user keybindings: " + e);
}
}
if (_resourceMan.ContentFileExists(path))

View File

@@ -207,8 +207,8 @@ public sealed partial class PhysicsSystem
var contact = contacts[i];
var uidA = contact.EntityA;
var uidB = contact.EntityB;
var bodyATransform = GetPhysicsTransform(uidA, xformQuery.GetComponent(uidA), xformQuery);
var bodyBTransform = GetPhysicsTransform(uidB, xformQuery.GetComponent(uidB), xformQuery);
var bodyATransform = GetPhysicsTransform(uidA, xformQuery.GetComponent(uidA));
var bodyBTransform = GetPhysicsTransform(uidB, xformQuery.GetComponent(uidB));
contact.UpdateIsTouching(bodyATransform, bodyBTransform);
}

View File

@@ -5,33 +5,33 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>WinExe</OutputType>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<NoWarn>NU1701</NoWarn>
<NoWarn>NU1701;CA1416</NoWarn>
<OutputPath>../bin/Client</OutputPath>
<RobustILLink>true</RobustILLink>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DiscordRichPresence" Version="1.0.175" PrivateAssets="compile" />
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="6.0.9" PrivateAssets="compile" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' == 'True'" PrivateAssets="compile" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' != 'True'" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.NFluidsynth" Version="0.1.1" PrivateAssets="compile" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" PrivateAssets="compile" />
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.SharpFont" Version="1.0.1" PrivateAssets="compile" />
<PackageReference Include="Robust.Natives" Version="0.1.1" />
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.20348-rc2" PrivateAssets="compile" />
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" Version="1.2.0" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" Version="0.2.1" PrivateAssets="compile" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" Version="8.0.0" />
<PackageReference Include="TerraFX.Interop.Xlib" Version="6.4.0" />
<PackageReference Include="DiscordRichPresence" PrivateAssets="compile" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" PrivateAssets="compile" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Condition="'$(UseSystemSqlite)' == 'True'" PrivateAssets="compile" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Condition="'$(UseSystemSqlite)' != 'True'" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.NFluidsynth" PrivateAssets="compile" />
<PackageReference Include="SixLabors.ImageSharp" />
<PackageReference Include="OpenToolkit.Graphics" PrivateAssets="compile" />
<PackageReference Include="OpenTK.OpenAL" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.SharpFont" PrivateAssets="compile" />
<PackageReference Include="Robust.Natives" />
<PackageReference Include="System.Numerics.Vectors" />
<PackageReference Include="TerraFX.Interop.Windows" PrivateAssets="compile" />
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" PrivateAssets="compile" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" />
<PackageReference Include="TerraFX.Interop.Xlib" />
</ItemGroup>
<ItemGroup Condition="'$(EnableClientScripting)' == 'True'">
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.0.1" PrivateAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" PrivateAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" PrivateAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" PrivateAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" PrivateAssets="compile" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" PrivateAssets="compile" />
<ProjectReference Include="..\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj" />
</ItemGroup>
@@ -40,7 +40,6 @@
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\OpenToolkit.GraphicsLibraryFramework\OpenToolkit.GraphicsLibraryFramework.csproj" />
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj" />
<ProjectReference Include="..\Robust.Physics\Robust.Physics.csproj" />
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>

View File

@@ -11,15 +11,17 @@ namespace Robust.Client.Upload.Commands;
public sealed class UploadFileCommand : IConsoleCommand
{
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IFileDialogManager _dialog = default!;
[Dependency] private readonly INetManager _netManager = default!;
public string Command => "uploadfile";
public string Description => "Uploads a resource to the server.";
public string Help => $"{Command} [relative path for the resource]";
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var cfgMan = IoCManager.Resolve<IConfigurationManager>();
if (!cfgMan.GetCVar(CVars.ResourceUploadingEnabled))
if (!_cfgManager.GetCVar(CVars.ResourceUploadingEnabled))
{
shell.WriteError("Network Resource Uploading is currently disabled by the server.");
return;
@@ -33,10 +35,8 @@ public sealed class UploadFileCommand : IConsoleCommand
var path = new ResPath(args[0]).ToRelativePath();
var dialog = IoCManager.Resolve<IFileDialogManager>();
var filters = new FileDialogFilters(new FileDialogFilters.Group(path.Extension));
await using var file = await dialog.OpenFile(filters);
await using var file = await _dialog.OpenFile(filters);
if (file == null)
{
@@ -44,7 +44,7 @@ public sealed class UploadFileCommand : IConsoleCommand
return;
}
var sizeLimit = cfgMan.GetCVar(CVars.ResourceUploadingLimitMb);
var sizeLimit = _cfgManager.GetCVar(CVars.ResourceUploadingLimitMb);
if (sizeLimit > 0f && file.Length * SharedNetworkResourceManager.BytesToMegabytes > sizeLimit)
{
@@ -54,12 +54,12 @@ public sealed class UploadFileCommand : IConsoleCommand
var data = file.CopyToArray();
var netManager = IoCManager.Resolve<INetManager>();
var msg = netManager.CreateNetMessage<NetworkResourceUploadMessage>();
var msg = new NetworkResourceUploadMessage
{
RelativePath = path,
Data = data
};
msg.RelativePath = path;
msg.Data = data;
netManager.ClientSendMessage(msg);
_netManager.ClientSendMessage(msg);
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using Robust.Shared;
using Robust.Shared.Configuration;
@@ -13,21 +14,20 @@ namespace Robust.Client.Upload.Commands;
public sealed class UploadFolderCommand : IConsoleCommand
{
[Dependency] private IResourceManager _resourceManager = default!;
[Dependency] private IConfigurationManager _configManager = default!;
[Dependency] private INetManager _netMan = default!;
public string Command => "uploadfolder";
public string Description => Loc.GetString("uploadfolder-command-description");
public string Help => Loc.GetString("uploadfolder-command-help");
private static readonly ResPath BaseUploadFolderPath = new("/UploadFolder");
[Dependency] private IResourceManager _resourceManager = default!;
[Dependency] private IConfigurationManager _configManager = default!;
[Dependency] private INetManager _netMan = default!;
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var fileCount = 0;
if (!_configManager.GetCVar(CVars.ResourceUploadingEnabled))
{
shell.WriteError( Loc.GetString("uploadfolder-command-resource-upload-disabled"));
@@ -52,8 +52,7 @@ public sealed class UploadFolderCommand : IConsoleCommand
//Grab all files in specified folder and upload them
foreach (var filepath in _resourceManager.UserData.Find($"{folderPath.ToRelativePath()}/").files )
{
await using var filestream = _resourceManager.UserData.Open(filepath,FileMode.Open);
await using var filestream = _resourceManager.UserData.Open(filepath, FileMode.Open);
{
var sizeLimit = _configManager.GetCVar(CVars.ResourceUploadingLimitMb);
if (sizeLimit > 0f && filestream.Length * SharedNetworkResourceManager.BytesToMegabytes > sizeLimit)
@@ -64,9 +63,11 @@ public sealed class UploadFolderCommand : IConsoleCommand
var data = filestream.CopyToArray();
var msg = _netMan.CreateNetMessage<NetworkResourceUploadMessage>();
msg.RelativePath = filepath.RelativeTo(BaseUploadFolderPath);
msg.Data = data;
var msg = new NetworkResourceUploadMessage
{
RelativePath = filepath.RelativeTo(BaseUploadFolderPath),
Data = data
};
_netMan.ClientSendMessage(msg);
fileCount++;

View File

@@ -90,6 +90,8 @@ public sealed class TextEdit : Control
internal bool DebugOverlay;
private Vector2? _lastDebugMousePos;
public event Action<TextEditEventArgs>? OnTextChanged;
public TextEdit()
{
IoCManager.InjectDependencies(this);
@@ -315,7 +317,7 @@ public sealed class TextEdit : Control
if (changed)
{
_selectionStart = _cursorPosition;
// OnTextChanged?.Invoke(new LineEditEventArgs(this, _text));
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
// _updatePseudoClass();
// OnBackspace?.Invoke(new LineEditBackspaceEventArgs(oldText, _text, cursor, selectStart));
}
@@ -349,7 +351,7 @@ public sealed class TextEdit : Control
if (changed)
{
_selectionStart = _cursorPosition;
// OnTextChanged?.Invoke(new LineEditEventArgs(this, _text));
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
// _updatePseudoClass();
}
@@ -382,7 +384,10 @@ public sealed class TextEdit : Control
}
if (changed)
{
_selectionStart = _cursorPosition;
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
}
InvalidateHorizontalCursorPos();
args.Handle();
@@ -411,7 +416,10 @@ public sealed class TextEdit : Control
}
if (changed)
{
_selectionStart = _cursorPosition;
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
}
InvalidateHorizontalCursorPos();
args.Handle();
@@ -748,6 +756,7 @@ public sealed class TextEdit : Control
var startPos = _cursorPosition;
TextRope = Rope.Insert(TextRope, startPos.Index, ev.Text);
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
_selectionStart = _cursorPosition = new CursorPos(startPos.Index + startChars, LineBreakBias.Top);
_imeData = (startPos, ev.Text.Length);
@@ -844,6 +853,7 @@ public sealed class TextEdit : Control
var upper = SelectionUpper.Index;
TextRope = Rope.ReplaceSubstring(TextRope, lower, upper - lower, text);
OnTextChanged?.Invoke(new TextEditEventArgs(this, _textRope));
_selectionStart = _cursorPosition = new CursorPos(lower + text.Length, LineBreakBias.Top);
// OnTextChanged?.Invoke(new LineEditEventArgs(this, _text));
@@ -1441,6 +1451,12 @@ public sealed class TextEdit : Control
AbortIme(delete: false);
}
public sealed class TextEditEventArgs(TextEdit control, Rope.Node textRope) : EventArgs
{
public TextEdit Control { get; } = control;
public Rope.Node TextRope { get; } = textRope;
}
/// <summary>
/// Specifies which line the cursor is positioned at when on a word-wrapping break.
/// </summary>

View File

@@ -39,7 +39,7 @@ namespace Robust.Client.UserInterface.CustomControls
// And also if Update() stops firing due to an exception loop the console will still work.
// (At least from the main thread, which is what's throwing the exceptions..)
[GenerateTypedNameReferences]
public sealed partial class DebugConsole : Control, IDebugConsoleView, IPostInjectInit
public sealed partial class DebugConsole : Control, IDebugConsoleView
{
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
@@ -49,7 +49,7 @@ namespace Robust.Client.UserInterface.CustomControls
private static readonly ResPath HistoryPath = new("/debug_console_history.json");
private readonly ConcurrentQueue<FormattedMessage> _messageQueue = new();
private ISawmill _logger = default!;
private readonly ISawmill _logger;
public DebugConsole()
{
@@ -57,6 +57,8 @@ namespace Robust.Client.UserInterface.CustomControls
IoCManager.InjectDependencies(this);
_logger = _logMan.GetSawmill("dbgconsole");
InitCompletions();
CommandBar.OnTextChanged += OnCommandChanged;
@@ -282,10 +284,5 @@ namespace Robust.Client.UserInterface.CustomControls
}
});
}
void IPostInjectInit.PostInject()
{
_logger = _logMan.GetSawmill("dbgconsole");
}
}
}

View File

@@ -4,6 +4,7 @@ using Robust.Shared.Resources;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.PixelFormats;
namespace Robust.Packaging.AssetProcessing.Passes;
@@ -168,7 +169,7 @@ internal sealed class AssetPassPackRsis : AssetPass
}
var ms = new MemoryStream();
sheet.Metadata.GetPngMetadata().TextData.Add(new PngTextData("Description", metaJson, null, null));
sheet.Metadata.GetPngMetadata().TextData.Add(new PngTextData("Description", metaJson, "", ""));
sheet.SaveAsPng(ms);
sheet.Dispose();

View File

@@ -10,9 +10,5 @@
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NVorbis" Version="0.10.5" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />
</Project>

View File

@@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Engine.props" />
<PropertyGroup>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>TRACE;RELEASE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />
</Project>

View File

@@ -4,12 +4,13 @@
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>11</LangVersion>
<Nullable>enable</Nullable>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.4.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" />
</ItemGroup>
</Project>

View File

@@ -259,6 +259,9 @@ namespace Robust.Server.Console
}
done:
result ??= CompletionResult.Empty;
var msg = new MsgConCompletionResp
{
Result = result,

View File

@@ -19,13 +19,15 @@ internal sealed partial class MetricsManager
{
private readonly ISawmill _sawmill;
private readonly HttpListener _listener;
private readonly CollectorRegistry _registry;
public ManagedHttpListenerMetricsServer(ISawmill sawmill, string host, int port, string url = "metrics/",
CollectorRegistry? registry = null) : base(registry)
CollectorRegistry? registry = null)
{
_sawmill = sawmill;
_listener = new HttpListener();
_listener.Prefixes.Add($"http://{host}:{port}/{url}");
_registry = registry ?? Metrics.DefaultRegistry;
}
protected override Task StartServer(CancellationToken cancel)

View File

@@ -193,5 +193,6 @@ internal sealed partial class PvsSystem
session.PreviouslySent.Clear();
session.LastSent = null;
session.Entities.Clear();
}
}

View File

@@ -27,7 +27,7 @@ namespace Robust.Server.Log
if (valid)
{
message.AddOrUpdateProperty(sawmillProperty);
message.AddOrUpdateProperty(sawmillProperty!);
}
_sLogger.Write(message);

View File

@@ -0,0 +1,138 @@
using System.Collections.Generic;
using System.Numerics;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Server.Physics;
public sealed partial class GridFixtureSystem
{
/*
* Something to keep in mind is that they rotate around the origin of a tile (e.g. 0,0), so a rotation of -90 degrees
* moves the origin to 0, -1.
*/
/// <summary>
/// Merges GridB into GridA.
/// </summary>
/// <param name="offset">Origin of GridB relative to GridA</param>
/// <param name="rotation">Rotation to apply to GridB when being merged.
/// Note that the rotation is applied before the offset so the offset itself will be rotated.</param>
public void Merge(
EntityUid gridAUid,
EntityUid gridBUid,
Vector2i offset,
Angle rotation,
MapGridComponent? gridA = null,
MapGridComponent? gridB = null,
TransformComponent? xformA = null,
TransformComponent? xformB = null)
{
var matrix = Matrix3.CreateTransform(offset, rotation);
Merge(gridAUid, gridBUid, matrix, gridA, gridB, xformA, xformB);
}
/// <summary>
/// Merges GridB into GridA.
/// </summary>
/// <param name="offset">Origin of GridB relative to GridA</param>
/// <param name="matrix">Matrix to apply to gridB when being merged.
/// Note that rotation is applied first and then offset so the offset itself will be rotated.</param>
public void Merge(
EntityUid gridAUid,
EntityUid gridBUid,
Matrix3 matrix,
MapGridComponent? gridA = null,
MapGridComponent? gridB = null,
TransformComponent? xformA = null,
TransformComponent? xformB = null)
{
if (!Resolve(gridAUid, ref gridA, ref xformA))
return;
if (!Resolve(gridBUid, ref gridB, ref xformB))
return;
var sw = new Stopwatch();
var tiles = new List<(Vector2i Indices, Tile Tile)>();
var enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
while (enumerator.MoveNext(out var tileRef))
{
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
tiles.Add((offsetTile.Floored(), tileRef.Value.Tile));
}
_maps.SetTiles(gridAUid, gridA, tiles);
enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
var rotationDiff = matrix.Rotation();
while (enumerator.MoveNext(out var tileRef))
{
var chunkOrigin = SharedMapSystem.GetChunkIndices(tileRef.Value.GridIndices, gridB.ChunkSize);
if (!_maps.TryGetChunk(gridBUid, gridB, chunkOrigin, out var chunk))
{
continue;
}
var chunkLocalTile = SharedMapSystem.GetChunkRelative(tileRef.Value.GridIndices, gridB.ChunkSize);
var snapgrid = chunk.GetSnapGrid((ushort) chunkLocalTile.X, (ushort) chunkLocalTile.Y);
if (snapgrid == null || snapgrid.Count == 0)
continue;
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
var tileIndex = offsetTile.Floored();
for (var j = snapgrid.Count - 1; j >= 0; j--)
{
var ent = snapgrid[j];
var xform = _xformQuery.GetComponent(ent);
_xformSystem.ReAnchor(ent, xform,
gridB, gridA,
tileRef.Value.GridIndices, tileIndex,
gridBUid, gridAUid,
xformB, xformA,
rotationDiff);
DebugTools.Assert(xform.ParentUid == gridAUid);
}
DebugTools.Assert(snapgrid.Count == 0);
}
enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
while (enumerator.MoveNext(out var tileRef))
{
var bounds = _lookup.GetLocalBounds(tileRef.Value.GridIndices, gridB.TileSize);
_entSet.Clear();
_lookup.GetLocalEntitiesIntersecting(gridBUid, bounds, _entSet, LookupFlags.All | ~LookupFlags.Contained | LookupFlags.Approximate);
foreach (var ent in _entSet)
{
// Consider centre of entity position maybe?
var entXform = _xformQuery.GetComponent(ent);
if (entXform.ParentUid != gridBUid ||
!bounds.Contains(entXform.LocalPosition)) continue;
var newPos = matrix.Transform(entXform.LocalPosition);
_xformSystem.SetCoordinates(ent, entXform, new EntityCoordinates(gridAUid, newPos), entXform.LocalRotation + rotationDiff, oldParent: xformB, newParent: xformA);
}
}
DebugTools.Assert(xformB.ChildCount == 0);
Del(gridBUid);
Log.Debug($"Merged grids in {sw.Elapsed.TotalMilliseconds}ms");
}
}

View File

@@ -23,16 +23,16 @@ namespace Robust.Server.Physics
/// <summary>
/// Handles generating fixtures for MapGrids.
/// </summary>
public sealed class GridFixtureSystem : SharedGridFixtureSystem
public sealed partial class GridFixtureSystem : SharedGridFixtureSystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IConGroupController _conGroup = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
private ISawmill _logger = default!;
private readonly Dictionary<EntityUid, Dictionary<Vector2i, ChunkNodeGroup>> _nodes = new();
/// <summary>
@@ -47,10 +47,19 @@ namespace Robust.Server.Physics
internal bool SplitAllowed = true;
private HashSet<EntityUid> _entSet = new();
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<PhysicsComponent> _bodyQuery;
private EntityQuery<TransformComponent> _xformQuery;
public override void Initialize()
{
base.Initialize();
_logger = Logger.GetSawmill("gsplit");
_gridQuery = GetEntityQuery<MapGridComponent>();
_bodyQuery = GetEntityQuery<PhysicsComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoval);
SubscribeNetworkEvent<RequestGridNodesMessage>(OnDebugRequest);
SubscribeNetworkEvent<StopGridNodesMessage>(OnDebugStopRequest);
@@ -197,7 +206,7 @@ namespace Robust.Server.Physics
}
_isSplitting = true;
_logger.Debug($"Started split check for {ToPrettyString(uid)}");
Log.Debug($"Started split check for {ToPrettyString(uid)}");
var splitFrontier = new Queue<ChunkSplitNode>(4);
var grids = new List<HashSet<ChunkSplitNode>>(1);
@@ -234,7 +243,7 @@ namespace Robust.Server.Physics
// Split time
if (grids.Count > 1)
{
_logger.Info($"Splitting {ToPrettyString(uid)} into {grids.Count} grids.");
Log.Info($"Splitting {ToPrettyString(uid)} into {grids.Count} grids.");
var sw = new Stopwatch();
sw.Start();
@@ -244,13 +253,10 @@ namespace Robust.Server.Physics
x.Sum(o => o.Indices.Count)
.CompareTo(y.Sum(o => o.Indices.Count)));
var xformQuery = GetEntityQuery<TransformComponent>();
var bodyQuery = GetEntityQuery<PhysicsComponent>();
var gridQuery = GetEntityQuery<MapGridComponent>();
var oldGridXform = xformQuery.GetComponent(oldGridUid);
var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(oldGridXform, xformQuery);
var mapBody = bodyQuery.GetComponent(oldGridUid);
var oldGridComp = gridQuery.GetComponent(oldGridUid);
var oldGridXform = _xformQuery.GetComponent(oldGridUid);
var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(oldGridXform);
var mapBody = _bodyQuery.GetComponent(oldGridUid);
var oldGridComp = _gridQuery.GetComponent(oldGridUid);
var newGrids = new EntityUid[grids.Count - 1];
var mapId = oldGridXform.MapID;
@@ -259,17 +265,17 @@ namespace Robust.Server.Physics
var group = grids[i];
var newGrid = _mapManager.CreateGridEntity(mapId);
var newGridUid = newGrid.Owner;
var newGridXform = xformQuery.GetComponent(newGridUid);
var newGridXform = _xformQuery.GetComponent(newGridUid);
newGrids[i] = newGridUid;
// Keep same origin / velocity etc; this makes updating a lot faster and easier.
_xformSystem.SetWorldPosition(newGridXform, gridPos);
_xformSystem.SetWorldPositionRotation(newGridXform, gridPos, gridRot);
var splitBody = bodyQuery.GetComponent(newGridUid);
_xformSystem.SetWorldPositionRotation(newGridUid, gridPos, gridRot, newGridXform);
var splitBody = _bodyQuery.GetComponent(newGridUid);
_physics.SetLinearVelocity(newGridUid, mapBody.LinearVelocity, body: splitBody);
_physics.SetAngularVelocity(newGridUid, mapBody.AngularVelocity, body: splitBody);
var gridComp = gridQuery.GetComponent(newGridUid);
var gridComp = _gridQuery.GetComponent(newGridUid);
var tileData = new List<(Vector2i GridIndices, Tile Tile)>(group.Sum(o => o.Indices.Count));
// Gather all tiles up front and set once to minimise fixture change events
@@ -284,7 +290,7 @@ namespace Robust.Server.Physics
}
}
newGrid.Comp.SetTiles(tileData);
_maps.SetTiles(newGrid.Owner, newGrid.Comp, tileData);
DebugTools.Assert(_mapManager.IsGrid(newGridUid), "A split grid had no tiles?");
// Set tiles on new grid + update anchored entities
@@ -303,8 +309,13 @@ namespace Robust.Server.Physics
for (var j = snapgrid.Count - 1; j >= 0; j--)
{
var ent = snapgrid[j];
var xform = xformQuery.GetComponent(ent);
_xformSystem.ReAnchor(ent, xform, oldGridComp, gridComp, tilePos, oldGridUid, newGridUid, oldGridXform, newGridXform, xformQuery);
var xform = _xformQuery.GetComponent(ent);
_xformSystem.ReAnchor(ent, xform,
oldGridComp, gridComp,
tilePos, tilePos,
oldGridUid, newGridUid,
oldGridXform, newGridXform,
Angle.Zero);
DebugTools.Assert(xform.Anchored);
}
}
@@ -317,15 +328,18 @@ namespace Robust.Server.Physics
var tilePos = offset + tile;
var bounds = _lookup.GetLocalBounds(tilePos, oldGrid.TileSize);
foreach (var ent in _lookup.GetEntitiesIntersecting(oldGridUid, tilePos, 0f, LookupFlags.Dynamic | LookupFlags.Sundries))
_entSet.Clear();
_lookup.GetLocalEntitiesIntersecting(oldGridUid, tilePos, _entSet, 0f, LookupFlags.All | ~LookupFlags.Uncontained | LookupFlags.Approximate);
foreach (var ent in _entSet)
{
// Consider centre of entity position maybe?
var entXform = xformQuery.GetComponent(ent);
var entXform = _xformQuery.GetComponent(ent);
if (entXform.ParentUid != oldGridUid ||
!bounds.Contains(entXform.LocalPosition)) continue;
_xformSystem.SetParent(ent, entXform, newGridUid, xformQuery, newGridXform);
_xformSystem.SetParent(ent, entXform, newGridUid, _xformQuery, newGridXform);
}
}
@@ -365,10 +379,10 @@ namespace Robust.Server.Physics
var ev = new GridSplitEvent(newGrids, oldGridUid);
RaiseLocalEvent(uid, ref ev, true);
_logger.Debug($"Split {grids.Count} grids in {sw.Elapsed}");
Log.Debug($"Split {grids.Count} grids in {sw.Elapsed}");
}
_logger.Debug($"Stopped split check for {ToPrettyString(uid)}");
Log.Debug($"Stopped split check for {ToPrettyString(uid)}");
_isSplitting = false;
SendNodeDebug(oldGridUid);
}

View File

@@ -0,0 +1,69 @@
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Toolshed;
namespace Robust.Server.Physics;
public sealed class MergeGridsCommand : LocalizedCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
public override string Command => "merge_grids";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 4)
{
return;
}
if (!NetEntity.TryParse(args[0], out var gridANet) ||
!NetEntity.TryParse(args[1], out var gridBNet))
{
return;
}
var gridAUid = _entManager.GetEntity(gridANet);
var gridBUid = _entManager.GetEntity(gridBNet);
if (!_entManager.TryGetComponent<MapGridComponent>(gridAUid, out var gridA) ||
!_entManager.TryGetComponent<MapGridComponent>(gridBUid, out var gridB))
{
return;
}
if (!int.TryParse(args[2], out var x) ||
!int.TryParse(args[3], out var y))
{
return;
}
Angle rotation = Angle.Zero;
if (args.Length >= 5 && int.TryParse(args[4], out var rotationInt))
{
rotation = Angle.FromDegrees(rotationInt);
}
var offset = new Vector2i(x, y);
var fixtureSystem = _entManager.System<GridFixtureSystem>();
fixtureSystem.Merge(gridAUid, gridBUid, offset, rotation, gridA: gridA, gridB: gridB);
}
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
return args.Length switch
{
1 => CompletionResult.FromHintOptions(CompletionHelper.Components<MapGridComponent>(args[0], _entManager), Loc.GetString("cmd-merge_grids-hintA")),
2 => CompletionResult.FromHintOptions(CompletionHelper.Components<MapGridComponent>(args[1], _entManager), Loc.GetString("cmd-merge_grids-hintB")),
3 => CompletionResult.FromHint(Loc.GetString("cmd-merge_grids-xOffset")),
4 => CompletionResult.FromHint(Loc.GetString("cmd-merge_grids-yOffset")),
5 => CompletionResult.FromHint(Loc.GetString("cmd-merge_grids-angle")),
_ => CompletionResult.Empty
};
}
}

View File

@@ -32,8 +32,6 @@ namespace Robust.Server
throw new InvalidOperationException("Cannot start twice!");
}
GlibcBug.Check();
_hasStarted = true;
if (!CommandLineArgs.TryParse(args, out var parsed))

View File

@@ -10,27 +10,30 @@
<!-- Try to fix sporadic errors against Robust.Packaging, apparently?? -->
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<RobustILLink>true</RobustILLink>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
<PackageReference Include="SpaceWizards.HttpListener" Version="0.1.0" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="6.0.9" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.4" Condition="'$(UseSystemSqlite)' == 'True'" /> <!-- Cannot be private since Content.Server/Database/ServerDbManager.cs depends on SQLitePCL.raw -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.4" Condition="'$(UseSystemSqlite)' != 'True'" PrivateAssets="compile" />
<PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="Serilog.Sinks.Loki" Version="4.0.0-beta3" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="6.0.0" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.2" />
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.20348-rc2" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.2" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" Version="0.2.1" PrivateAssets="compile" />
<PackageReference Include="SharpZstd.Interop" Version="1.5.2-beta2" PrivateAssets="compile" />
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" Version="1.2.0" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" Version="8.0.0" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
<PackageReference Include="SpaceWizards.HttpListener" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Condition="'$(UseSystemSqlite)' == 'True'" /> <!-- Cannot be private since Content.Server/Database/ServerDbManager.cs depends on SQLitePCL.raw -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Condition="'$(UseSystemSqlite)' != 'True'" PrivateAssets="compile" />
<PackageReference Include="prometheus-net" />
<PackageReference Include="Serilog.Sinks.Loki" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Extensions.Primitives" />
<!-- Needed to pull-up the dependency from prometheus-net -->
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="prometheus-net.DotNetRuntime" />
<PackageReference Include="TerraFX.Interop.Windows" PrivateAssets="compile" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" PrivateAssets="compile" />
<PackageReference Include="SharpZstd.Interop" PrivateAssets="compile" />
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" />
<PackageReference Include="Microsoft.NET.ILLink.Tasks" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\Robust.Physics\Robust.Physics.csproj" />
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj" />
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />

View File

@@ -297,25 +297,20 @@ namespace Robust.Server.Scripting
var results = await (CompletionService
.GetService(document)?
.GetCompletionsAsync(document, message.Cursor) ?? Task.FromResult<CompletionList?>(null));
.GetCompletionsAsync(document, message.Cursor) ?? Task.FromResult(CompletionList.Empty));
if (results is not null)
{
var ires = ImmutableArray.CreateBuilder<LiteResult>();
foreach (var r in results.Items)
ires.Add(new LiteResult(
displayText: r.DisplayText,
displayTextPrefix: r.DisplayTextPrefix,
displayTextSuffix: r.DisplayTextSuffix,
inlineDescription: r.InlineDescription,
tags: r.Tags,
properties: r.Properties
));
var ires = ImmutableArray.CreateBuilder<LiteResult>();
foreach (var r in results.ItemsList)
ires.Add(new LiteResult(
displayText: r.DisplayText,
displayTextPrefix: r.DisplayTextPrefix,
displayTextSuffix: r.DisplayTextSuffix,
inlineDescription: r.InlineDescription,
tags: r.Tags,
properties: r.Properties
));
replyMessage.Results = ires.ToImmutable();
}
else
replyMessage.Results = ImmutableArray<LiteResult>.Empty;
replyMessage.Results = ires.ToImmutable();
_netManager.ServerSendMessage(replyMessage, message.MsgChannel);
}

View File

@@ -308,7 +308,7 @@ namespace Robust.Server.ServerStatus
private static bool RequestWantsZStd(IStatusHandlerContext context)
{
// Yeah this isn't a good parser for Accept-Encoding but who cares.
return context.RequestHeaders.TryGetValue("Accept-Encoding", out var ac) && ac.Count > 0 && ac[0].Contains("zstd");
return context.RequestHeaders.TryGetValue("Accept-Encoding", out var ac) && ac.Count > 0 && ac[0]?.Contains("zstd") == true;
}
// Only call this if the download URL is not available!

View File

@@ -97,7 +97,7 @@ namespace Robust.Server.ViewVariables
// Auto-dirty component. Only works when modifying a field that is directly on a component,
// Does not work for nested objects.
if (Object is Component comp)
if (Object is Component { NetSyncEnabled: true } comp)
EntityManager.Dirty(comp.Owner, comp);
}

View File

@@ -3,10 +3,11 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>9</LangVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using Robust.Shared.Utility;
@@ -258,7 +259,24 @@ namespace Robust.Shared.Maths
/// <param name="degrees">The angle in degrees.</param>
public static Angle FromDegrees(double degrees)
{
return new(MathHelper.DegreesToRadians(degrees));
// Avoid rounding issues with common use cases.
switch (degrees)
{
case -270:
return new Angle(Math.PI * -1.5);
case 90:
return new Angle(Math.PI / 2);
case -180:
return new Angle(-Math.PI);
case 180:
return new Angle(Math.PI);
case 270.0:
return new Angle(Math.PI * 1.5);
case -90:
return new Angle(Math.PI / -2);
default:
return new(MathHelper.DegreesToRadians(degrees));
}
}
/// <summary>

View File

@@ -6,7 +6,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />

View File

@@ -109,6 +109,11 @@ namespace Robust.Shared.Maths
}
}
public Vector2i Rotate(Angle angle)
{
return (Vector2i) angle.RotateVec(this);
}
public static Vector2i operator -(Vector2i a, Vector2i b)
{
return new(a.X - b.X, a.Y - b.Y);

View File

@@ -7,11 +7,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ILReader.Core" Version="1.0.0.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.0.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
<PackageReference Include="ILReader.Core" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
@@ -9,6 +10,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
using Robust.Shared.Utility;
@@ -84,11 +86,18 @@ public sealed class TeleportToCommand : LocalizedCommands
var target = args[0];
if (!TryGetTransformFromUidOrUsername(target, shell, out _, out var targetTransform))
if (!TryGetTransformFromUidOrUsername(target, shell, out var targetUid, out _))
return;
var transformSystem = _entities.System<SharedTransformSystem>();
var targetCoords = targetTransform.Coordinates;
var targetCoords = new EntityCoordinates(targetUid.Value, Vector2.Zero);
if (_entities.TryGetComponent(targetUid, out PhysicsComponent? targetPhysics))
{
targetCoords = targetCoords.Offset(targetPhysics.LocalCenter);
}
var victims = new List<(EntityUid Entity, TransformComponent Transform)>();
if (args.Length == 1)
{
@@ -100,8 +109,7 @@ public sealed class TeleportToCommand : LocalizedCommands
return;
}
transformSystem.SetCoordinates(ent.Value, targetCoords);
playerTransform.AttachToGridOrMap();
victims.Add((ent.Value, playerTransform));
}
else
{
@@ -111,12 +119,17 @@ public sealed class TeleportToCommand : LocalizedCommands
continue;
if (!TryGetTransformFromUidOrUsername(victim, shell, out var uid, out var victimTransform))
return;
continue;
transformSystem.SetCoordinates(uid.Value, targetCoords);
victimTransform.AttachToGridOrMap();
victims.Add((uid.Value, victimTransform));
}
}
foreach (var victim in victims)
{
transformSystem.SetCoordinates(victim.Entity, targetCoords);
transformSystem.AttachToGridOrMap(victim.Entity, victim.Transform);
}
}
private bool TryGetTransformFromUidOrUsername(
@@ -128,8 +141,7 @@ public sealed class TeleportToCommand : LocalizedCommands
if (NetEntity.TryParse(str, out var uidNet)
&& _entities.TryGetEntity(uidNet, out var uid)
&& _entities.TryGetComponent(uid, out transform)
&& !_entities.HasComponent<MapComponent>(uid)
&& !_entities.HasComponent<MapGridComponent>(uid))
&& !_entities.HasComponent<MapComponent>(uid))
{
victimUid = uid;
return true;

View File

@@ -25,6 +25,7 @@ namespace Robust.Shared.Containers
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedJointSystem _joint = default!;
private EntityQuery<ContainerManagerComponent> _managerQuery;
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<MapComponent> _mapQuery;
protected EntityQuery<MetaDataComponent> MetaQuery;
@@ -42,6 +43,7 @@ namespace Robust.Shared.Containers
SubscribeLocalEvent<ContainerManagerComponent, ComponentGetState>(OnContainerGetState);
SubscribeLocalEvent<ContainerManagerComponent, ComponentRemove>(OnContainerManagerRemove);
_managerQuery = GetEntityQuery<ContainerManagerComponent>();
_gridQuery = GetEntityQuery<MapGridComponent>();
_mapQuery = GetEntityQuery<MapComponent>();
MetaQuery = GetEntityQuery<MetaDataComponent>();
@@ -437,8 +439,7 @@ namespace Robust.Shared.Containers
/// </summary>
public bool TryGetOuterContainer(EntityUid uid, TransformComponent xform, [NotNullWhen(true)] out BaseContainer? container)
{
var xformQuery = GetEntityQuery<TransformComponent>();
return TryGetOuterContainer(uid, xform, out container, xformQuery);
return TryGetOuterContainer(uid, xform, out container, TransformQuery);
}
public bool TryGetOuterContainer(EntityUid uid, TransformComponent xform,
@@ -449,15 +450,13 @@ namespace Robust.Shared.Containers
if (!uid.IsValid())
return false;
var conQuery = GetEntityQuery<ContainerManagerComponent>();
var metaQuery = GetEntityQuery<MetaDataComponent>();
var child = uid;
var parent = xform.ParentUid;
while (parent.IsValid())
{
if (((metaQuery.GetComponent(child).Flags & MetaDataFlags.InContainer) == MetaDataFlags.InContainer) &&
conQuery.TryGetComponent(parent, out var conManager) &&
if (((MetaQuery.GetComponent(child).Flags & MetaDataFlags.InContainer) == MetaDataFlags.InContainer) &&
_managerQuery.TryGetComponent(parent, out var conManager) &&
TryGetContainingContainer(parent, child, out var parentContainer, conManager))
{
container = parentContainer;

View File

@@ -32,7 +32,7 @@ namespace Robust.Shared.ContentPack
String("short").ThenReturn(PrimitiveTypeCode.Int16);
private static readonly Parser<char, PrimitiveTypeCode> UInt16TypeParser =
String("ushort").ThenReturn(PrimitiveTypeCode.UInt32);
String("ushort").ThenReturn(PrimitiveTypeCode.UInt16);
private static readonly Parser<char, PrimitiveTypeCode> Int32TypeParser =
String("int").ThenReturn(PrimitiveTypeCode.Int32);

View File

@@ -913,9 +913,14 @@ namespace Robust.Shared.ContentPack
return null;
}
public PEReader? Resolve(string simpleName)
public PEReader? ResolveAssembly(AssemblyName assemblyName)
{
return _dictionary.GetOrAdd(simpleName, ResolveCore);
return _dictionary.GetOrAdd(assemblyName.Name!, ResolveCore);
}
public PEReader? ResolveModule(AssemblyName referencingAssembly, string fileName)
{
throw new NotSupportedException();
}
public void Dispose()

View File

@@ -325,19 +325,23 @@ namespace Robust.Shared.ContentPack
{
lock (_lock)
{
Sawmill.Debug("ResolvingAssembly {0}", name);
Sawmill.Verbose("ResolvingAssembly {0}", name);
// Try main modules.
foreach (var mod in Mods)
{
if (mod.GameAssembly.FullName == name.FullName)
{
Sawmill.Verbose($"Found assembly in modloader ALC: {mod.GameAssembly}");
return mod.GameAssembly;
}
}
if (TryLoadExtra(name) is { } asm)
{
Sawmill.Verbose($"Found assembly through extra loader: {asm}");
return asm;
}
// Do not allow sideloading when sandboxing is enabled.
// Side loaded assemblies would not be checked for sandboxing currently, so we can't have that.
@@ -347,18 +351,42 @@ namespace Robust.Shared.ContentPack
{
if (assembly.FullName == name.FullName)
{
Sawmill.Verbose($"Found assembly in existing side modules: {assembly}");
return assembly;
}
}
// Try to resolve assemblies in the default AssemblyLoadContext.
// If we don't do this manually, the sideloading code below could load assemblies from content,
// even if Robust provides its own versions.
// This can lead to:
// * Multiple copies of the same assembly being loaded.
// * Mismatching versions of dependencies being loaded.
// * e.g. Microsoft.Extensions.Primitives 6.0 with Microsoft.Extensions.DependencyInjection 7.0
//
// Now, to be clear, this is 100% an error in packaging. But it's also one that's really easy to make.
//
try
{
var defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(name.Name!));
Sawmill.Verbose($"Found assembly through default ALC (early): {defaultAssembly}");
return defaultAssembly;
}
catch
{
// Assume assembly not loadable from Robust's directory, proceed with loading from content.
}
if (_res.TryContentFileRead($"/Assemblies/{name.Name}.dll", out var dll))
{
var assembly = _loadContext.LoadFromStream(dll);
_sideModules.Add(assembly);
Sawmill.Verbose($"Found assembly in NEW side module: {assembly}");
return assembly;
}
}
Sawmill.Verbose("Did not find assembly directly. Should fall back to default ALC.");
return null;
}
}
@@ -381,7 +409,7 @@ namespace Robust.Shared.ContentPack
// Otherwise it would load the assemblies a second time which is an amazing way to have everything break.
if (_useLoadContext)
{
Sawmill.Debug($"RESOLVING DEFAULT: {name}");
Sawmill.Verbose($"RESOLVING DEFAULT: {name}");
foreach (var module in LoadedModules)
{
if (module.GetName().Name == name.Name)

View File

@@ -81,12 +81,146 @@ Types:
- "bool get_HasContents()"
Lidgren.Network:
NetBuffer:
All: True
Methods:
- "byte[] get_Data()"
- "void set_Data(byte[])"
- "int get_LengthBytes()"
- "void set_LengthBytes(int)"
- "int get_LengthBits()"
- "void set_LengthBits(int)"
- "long get_Position()"
- "void set_Position(long)"
- "int get_PositionInBytes()"
- "byte[] PeekDataBuffer()"
- "bool PeekBoolean()"
- "byte PeekByte()"
- "sbyte PeekSByte()"
- "byte PeekByte(int)"
- "System.Span`1<byte> PeekBytes(System.Span`1<byte>)"
- "byte[] PeekBytes(int)"
- "void PeekBytes(byte[], int, int)"
- "short PeekInt16()"
- "ushort PeekUInt16()"
- "int PeekInt32()"
- "int PeekInt32(int)"
- "uint PeekUInt32()"
- "uint PeekUInt32(int)"
- "ulong PeekUInt64()"
- "long PeekInt64()"
- "ulong PeekUInt64(int)"
- "long PeekInt64(int)"
- "float PeekFloat()"
- "System.Half PeekHalf()"
- "float PeekSingle()"
- "double PeekDouble()"
- "string PeekString()"
- "int PeekStringSize()"
- "bool ReadBoolean()"
- "byte ReadByte()"
- "bool ReadByte(ref byte)"
- "sbyte ReadSByte()"
- "byte ReadByte(int)"
- "System.Span`1<byte> ReadBytes(System.Span`1<byte>)"
- "byte[] ReadBytes(int)"
- "bool ReadBytes(int, ref byte[])"
- "bool TryReadBytes(System.Span`1<byte>)"
- "void ReadBytes(byte[], int, int)"
- "void ReadBits(System.Span`1<byte>, int)"
- "void ReadBits(byte[], int, int)"
- "short ReadInt16()"
- "ushort ReadUInt16()"
- "int ReadInt32()"
- "bool ReadInt32(ref int)"
- "int ReadInt32(int)"
- "uint ReadUInt32()"
- "bool ReadUInt32(ref uint)"
- "uint ReadUInt32(int)"
- "ulong ReadUInt64()"
- "long ReadInt64()"
- "ulong ReadUInt64(int)"
- "long ReadInt64(int)"
- "float ReadFloat()"
- "System.Half ReadHalf()"
- "float ReadSingle()"
- "bool ReadSingle(ref float)"
- "double ReadDouble()"
- "uint ReadVariableUInt32()"
- "bool ReadVariableUInt32(ref uint)"
- "int ReadVariableInt32()"
- "long ReadVariableInt64()"
- "ulong ReadVariableUInt64()"
- "float ReadSignedSingle(int)"
- "float ReadUnitSingle(int)"
- "float ReadRangedSingle(float, float, int)"
- "int ReadRangedInteger(int, int)"
- "long ReadRangedInteger(long, long)"
- "string ReadString()"
- "bool ReadString(ref string)"
- "double ReadTime(Lidgren.Network.NetConnection, bool)"
- "System.Net.IPEndPoint ReadIPEndPoint()"
- "void SkipPadBits()"
- "void ReadPadBits()"
- "void SkipPadBits(int)"
- "void EnsureBufferSize(int)"
- "void Write(bool)"
- "void Write(byte)"
- "void WriteAt(int, byte)"
- "void Write(sbyte)"
- "void Write(byte, int)"
- "void Write(byte[])"
- "void Write(System.ReadOnlySpan`1<byte>)"
- "void Write(byte[], int, int)"
- "void Write(ushort)"
- "void WriteAt(int, ushort)"
- "void Write(ushort, int)"
- "void Write(short)"
- "void WriteAt(int, short)"
- "void Write(int)"
- "void WriteAt(int, int)"
- "void Write(uint)"
- "void WriteAt(int, uint)"
- "void Write(uint, int)"
- "void Write(int, int)"
- "void Write(ulong)"
- "void WriteAt(int, ulong)"
- "void Write(ulong, int)"
- "void Write(long)"
- "void Write(long, int)"
- "void Write(System.Half)"
- "void Write(float)"
- "void Write(double)"
- "int WriteVariableUInt32(uint)"
- "int WriteVariableInt32(int)"
- "int WriteVariableInt64(long)"
- "int WriteVariableUInt64(ulong)"
- "void WriteSignedSingle(float, int)"
- "void WriteUnitSingle(float, int)"
- "void WriteRangedSingle(float, float, float, int)"
- "int WriteRangedInteger(int, int, int)"
- "int WriteRangedInteger(long, long, long)"
- "void Write(string)"
- "void Write(System.Net.IPEndPoint)"
- "void WriteTime(bool)"
- "void WriteTime(double, bool)"
- "void WritePadBits()"
- "void WritePadBits(int)"
- "void Write(Lidgren.Network.NetBuffer)"
- "void Zero(int)"
- "void .ctor()"
NetDeliveryMethod: { }
NetIncomingMessage:
All: True
Methods:
- "Lidgren.Network.NetIncomingMessageType get_MessageType()"
- "Lidgren.Network.NetDeliveryMethod get_DeliveryMethod()"
- "int get_SequenceChannel()"
- "System.Net.IPEndPoint get_SenderEndPoint()"
- "Lidgren.Network.NetConnection get_SenderConnection()"
- "double get_ReceiveTime()"
- "double ReadTime(bool)"
- "string ToString()"
NetOutgoingMessage:
All: True
Methods:
- "string ToString()"
Nett:
CommentLocation: { } # Enum
Toml:
@@ -1408,4 +1542,7 @@ Types:
# should be fine to do All: True, but this has some methods to read filestreams. So just in case this ever adds an extension method that directly opens a file:
Methods:
- "!!0 ParseOrThrow<>(Pidgin.Parser`2<char, !!0>, string, System.Func`3<char, Pidgin.SourcePos, Pidgin.SourcePos>)"
- "!!0 ParseOrThrow<>(Pidgin.Parser`2<char, !!0>, string, Pidgin.Configuration.IConfiguration`1<char>)"
SourcePos: { }
Pidgin.Configuration:
IConfiguration`1: { All: True }

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Robust.Shared.Utility;
namespace Robust.Shared.ContentPack
@@ -135,11 +136,37 @@ namespace Robust.Shared.ContentPack
path = path.Directory;
var fullPath = GetFullPath(path);
Process.Start(new ProcessStartInfo
if (OperatingSystem.IsWindows())
{
UseShellExecute = true,
FileName = fullPath,
});
Process.Start(new ProcessStartInfo
{
FileName = "explorer.exe",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else if (OperatingSystem.IsMacOS())
{
Process.Start(new ProcessStartInfo
{
FileName = "open",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
{
Process.Start(new ProcessStartInfo
{
FileName = "xdg-open",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else
{
throw new NotSupportedException("Opening OS windows not supported on this OS");
}
}
#endregion

View File

@@ -16,8 +16,13 @@ namespace Robust.Shared.GameObjects
[ViewVariables(VVAccess.ReadWrite)]
private bool _netSync { get; set; } = true;
[Obsolete("Do not use from content")]
public bool Networked { get; set; } = true;
internal bool Networked { get; set; } = true;
bool IComponent.Networked
{
get => Networked;
set => Networked = value;
}
/// <inheritdoc />
public bool NetSyncEnabled
@@ -31,9 +36,14 @@ namespace Robust.Shared.GameObjects
[Obsolete("Update your API to allow accessing Owner through other means")]
public EntityUid Owner { get; set; } = EntityUid.Invalid;
/// <inheritdoc />
[ViewVariables]
public ComponentLifeStage LifeStage { get; [Obsolete("Do not use from content")] set; } = ComponentLifeStage.PreAdd;
public ComponentLifeStage LifeStage { get; internal set; } = ComponentLifeStage.PreAdd;
ComponentLifeStage IComponent.LifeStage
{
get => LifeStage;
set => LifeStage = value;
}
public virtual bool SendOnlyToOwner => false;
@@ -51,13 +61,29 @@ namespace Robust.Shared.GameObjects
[ViewVariables]
public bool Deleted => LifeStage >= ComponentLifeStage.Removing;
/// <inheritdoc />
/// <summary>
/// This is the tick the component was created.
/// </summary>
[ViewVariables]
public GameTick CreationTick { get; [Obsolete("Do not use from content")] set; }
public GameTick CreationTick { get; internal set; }
/// <inheritdoc />
GameTick IComponent.CreationTick
{
get => CreationTick;
set => CreationTick = value;
}
/// <summary>
/// Marks the component as dirty so that the network will re-sync it with clients.
/// </summary>
[ViewVariables]
public GameTick LastModifiedTick { get; [Obsolete("Do not use from content")] set; }
public GameTick LastModifiedTick { get; internal set; }
GameTick IComponent.LastModifiedTick
{
get => LastModifiedTick;
set => LastModifiedTick = value;
}
/// <inheritdoc />
[Obsolete]
@@ -69,15 +95,23 @@ namespace Robust.Shared.GameObjects
// these two methods clear the LastModifiedTick/CreationTick to mark it as "not different from prototype load".
// This is used as optimization in the game state system to avoid sending redundant component data.
[Obsolete("Do not use from content")]
public virtual void ClearTicks()
void IComponent.ClearTicks()
{
ClearTicks();
}
private protected virtual void ClearTicks()
{
LastModifiedTick = GameTick.Zero;
ClearCreationTick();
}
[Obsolete("Do not use from content")]
public void ClearCreationTick()
void IComponent.ClearCreationTick()
{
ClearCreationTick();
}
private protected void ClearCreationTick()
{
CreationTick = GameTick.Zero;
}

View File

@@ -149,7 +149,6 @@ namespace Robust.Shared.GameObjects
[ViewVariables]
public EntityLifeStage EntityLifeStage { get; internal set; }
[DataField("flags")]
public MetaDataFlags Flags
{
get => _flags;
@@ -192,8 +191,7 @@ namespace Robust.Shared.GameObjects
[ViewVariables]
internal PvsChunkLocation? LastPvsLocation;
[Obsolete("Do not use from content")]
public override void ClearTicks()
private protected override void ClearTicks()
{
// Do not clear modified ticks.
// MetaDataComponent is used in the game state system to carry initial data like prototype ID.

View File

@@ -0,0 +1,93 @@
namespace Robust.Shared.GameObjects;
/// <summary>
/// Helper extension methods for working with Bound User Interface events.
/// </summary>
/// <seealso cref="BoundUserInterfaceMessage"/>
public static class BoundUserInterfaceRegisterExt
{
/// <summary>
/// Delegate that subscribes to actual BUI events.
/// Used as a lambda via <see cref="BoundUserInterfaceRegisterExt.BuiEvents{TComp}"/>.
/// </summary>
/// <typeparam name="TComp">The type of component that will receive the events.</typeparam>
public delegate void BuiEventSubscriber<TComp>(Subscriber<TComp> subscriber) where TComp : IComponent;
/// <summary>
/// Extension method to subscribe to one or more Bound User Interface events via a system,
/// sharing the same UI key and owning component.
/// </summary>
/// <param name="subs">
/// The entity system subscriptions.
/// Call this with <see cref="EntitySystem.Subscriptions"/>.
/// </param>
/// <param name="uiKey">
/// The UI key to filter these subscriptions. The handler will only receive events targeted for this UI key.
/// </param>
/// <param name="subscriber">The delegate that will subscribe to the actual events.</param>
/// <typeparam name="TComp">The type of component that will receive the events.</typeparam>
/// <seealso cref="Subscriber{TComp}"/>
public static void BuiEvents<TComp>(
this EntitySystem.Subscriptions subs,
object uiKey,
BuiEventSubscriber<TComp> subscriber)
where TComp : IComponent
{
subscriber(new Subscriber<TComp>(subs, uiKey));
}
/// <summary>
/// Helper class to register Bound User Interface subscriptions against.
/// Created by <see cref="BoundUserInterfaceRegisterExt.BuiEvents{TComp}"/>.
/// </summary>
/// <typeparam name="TComp">The type of component that will receive the events.</typeparam>
public sealed class Subscriber<TComp> where TComp : IComponent
{
private readonly EntitySystem.Subscriptions _subs;
private readonly object _uiKey;
internal Subscriber(EntitySystem.Subscriptions subs, object uiKey)
{
_subs = subs;
_uiKey = uiKey;
}
/// <summary>
/// Subscribe to a local event. This is effectively equivalent to <see cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.ComponentEventHandler{``0,``1},System.Type[],System.Type[])"/>,
/// but reduces repetition and automatically filters for the appropriate UI key.
/// </summary>
/// <param name="handler">The handler that will get executed whenever the appropriate event is raised.</param>
/// <typeparam name="TEvent">The type of event to handle with this subscription.</typeparam>
/// <seealso cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.ComponentEventHandler{``0,``1},System.Type[],System.Type[])"/>
public void Event<TEvent>(ComponentEventHandler<TComp, TEvent> handler)
where TEvent : BaseBoundUserInterfaceEvent
{
_subs.SubscribeLocalEvent<TComp, TEvent>((uid, component, args) =>
{
if (!_uiKey.Equals(args.UiKey))
return;
handler(uid, component, args);
});
}
/// <summary>
/// Subscribe to a local event. This is effectively equivalent to <see cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.ComponentEventHandler{``0,``1},System.Type[],System.Type[])"/>,
/// but reduces repetition and automatically filters for the appropriate UI key.
/// </summary>
/// <param name="handler">The handler that will get executed whenever the appropriate event is raised.</param>
/// <typeparam name="TEvent">The type of event to handle with this subscription.</typeparam>
/// <seealso cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.ComponentEventHandler{``0,``1},System.Type[],System.Type[])"/>
public void Event<TEvent>(EntityEventRefHandler<TComp, TEvent> handler)
where TEvent : BaseBoundUserInterfaceEvent
{
_subs.SubscribeLocalEvent((Entity<TComp> ent, ref TEvent args) =>
{
if (!_uiKey.Equals(args.UiKey))
return;
handler(ent, ref args);
});
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.Player;
using Robust.Shared.ViewVariables;
namespace Robust.Shared.GameObjects;
@@ -11,25 +12,34 @@ namespace Robust.Shared.GameObjects;
[PublicAPI]
public sealed class PlayerBoundUserInterface
{
[ViewVariables]
public float InteractionRange;
[ViewVariables]
public float InteractionRangeSqrd => InteractionRange * InteractionRange;
[ViewVariables]
public Enum UiKey { get; }
[ViewVariables]
public EntityUid Owner { get; }
internal readonly HashSet<ICommonSession> _subscribedSessions = new();
[ViewVariables]
internal BoundUIWrapMessage? LastStateMsg;
[ViewVariables(VVAccess.ReadWrite)]
public bool RequireInputValidation;
[ViewVariables]
internal bool StateDirty;
[ViewVariables]
internal readonly Dictionary<ICommonSession, BoundUIWrapMessage> PlayerStateOverrides =
new();
/// <summary>
/// All of the sessions currently subscribed to this UserInterface.
/// </summary>
[ViewVariables]
public IReadOnlySet<ICommonSession> SubscribedSessions => _subscribedSessions;
public PlayerBoundUserInterface(PrototypeData data, EntityUid owner)

View File

@@ -1,19 +1,23 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.Player;
using Robust.Shared.ViewVariables;
namespace Robust.Shared.GameObjects
{
[RegisterComponent]
public sealed partial class ActiveUserInterfaceComponent : Component
{
[ViewVariables]
public HashSet<PlayerBoundUserInterface> Interfaces = new();
}
[PublicAPI]
public sealed class ServerBoundUserInterfaceMessage
{
[ViewVariables]
public BoundUserInterfaceMessage Message { get; }
[ViewVariables]
public ICommonSession Session { get; }
public ServerBoundUserInterfaceMessage(BoundUserInterfaceMessage message, ICommonSession session)

View File

@@ -26,7 +26,7 @@ namespace Robust.Shared.GameObjects
/// <inheritdoc />
[Virtual]
public partial class EntityManager : IEntityManager
public abstract partial class EntityManager : IEntityManager
{
#region Dependencies
@@ -61,7 +61,7 @@ namespace Robust.Shared.GameObjects
public IEntitySystemManager EntitySysManager => _entitySystemManager;
/// <inheritdoc />
public virtual IEntityNetworkManager? EntityNetManager => null;
public abstract IEntityNetworkManager EntityNetManager { get; }
protected readonly Queue<EntityUid> QueuedDeletions = new();
protected readonly HashSet<EntityUid> QueuedDeletionsSet = new();

View File

@@ -206,6 +206,32 @@ namespace Robust.Shared.GameObjects
{
System.SubscribeLocalEvent(handler, before, after);
}
/// <summary>
/// Proxy to <see cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.ComponentEventRefHandler{``0,``1},System.Type[],System.Type[])" />
/// on the owning system.
/// </summary>
public void SubscribeLocalEvent<TComp, TEvent>(
ComponentEventRefHandler<TComp, TEvent> handler,
Type[]? before = null, Type[]? after = null)
where TComp : IComponent
where TEvent : EntityEventArgs
{
System.SubscribeLocalEvent(handler, before, after);
}
/// <summary>
/// Proxy to <see cref="M:Robust.Shared.GameObjects.EntitySystem.SubscribeLocalEvent``2(Robust.Shared.GameObjects.EntityEventRefHandler{``0,``1},System.Type[],System.Type[])" />
/// on the owning system.
/// </summary>
public void SubscribeLocalEvent<TComp, TEvent>(
EntityEventRefHandler<TComp, TEvent> handler,
Type[]? before = null, Type[]? after = null)
where TComp : IComponent
where TEvent : EntityEventArgs
{
System.SubscribeLocalEvent(handler, before, after);
}
}
private abstract class SubBase

View File

@@ -16,10 +16,9 @@ namespace Robust.Shared.GameObjects
/// The current lifetime stage of this component. You can use this to check
/// if the component is initialized or being deleted.
/// </summary>
ComponentLifeStage LifeStage { get; [Obsolete("Do not use from content")] set; }
ComponentLifeStage LifeStage { get; internal set; }
[Obsolete("Do not use from content")]
bool Networked { get; set; }
internal bool Networked { get; set; }
/// <summary>
/// Whether this component should be synchronized with clients when modified.
@@ -68,22 +67,21 @@ namespace Robust.Shared.GameObjects
/// <summary>
/// Marks the component as dirty so that the network will re-sync it with clients.
/// </summary>
[Obsolete]
void Dirty(IEntityManager? entManager = null);
/// <summary>
/// This is the tick the component was created.
/// </summary>
GameTick CreationTick { get; set; }
GameTick CreationTick { get; internal set; }
/// <summary>
/// This is the last game tick Dirty() was called.
/// </summary>
GameTick LastModifiedTick { get; set; }
GameTick LastModifiedTick { get; internal set; }
[Obsolete("Do not use from content")]
void ClearTicks();
internal void ClearTicks();
[Obsolete("Do not use from content")]
void ClearCreationTick();
internal void ClearCreationTick();
}
}

View File

@@ -164,7 +164,7 @@ namespace Robust.Shared.GameObjects
/// <typeparam name="T">Component reference type to check for.</typeparam>
/// <param name="uid">Entity UID to check.</param>
/// <returns>True if the entity has the component type, otherwise false.</returns>
bool HasComponent<T>(EntityUid? uid) where T : IComponent;
bool HasComponent<T>([NotNullWhen(true)] EntityUid? uid) where T : IComponent;
/// <summary>
/// Checks if the entity has a component type.
@@ -180,7 +180,7 @@ namespace Robust.Shared.GameObjects
/// <param name="uid">Entity UID to check.</param>
/// <param name="type">A trait or component type to check for.</param>
/// <returns>True if the entity has the component type, otherwise false.</returns>
bool HasComponent(EntityUid? uid, Type type);
bool HasComponent([NotNullWhen(true)] EntityUid? uid, Type type);
/// <summary>
/// Checks if the entity has a component with a given network ID. This does not check
@@ -198,7 +198,7 @@ namespace Robust.Shared.GameObjects
/// <param name="uid">Entity UID to check.</param>
/// <param name="netId">Network ID to check for.</param>
/// <returns>True if the entity has a component with the given network ID, otherwise false.</returns>
bool HasComponent(EntityUid? uid, ushort netId, MetaDataComponent? meta = null);
bool HasComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, MetaDataComponent? meta = null);
/// <summary>
/// This method will always return a component for a certain entity, adding it if it's not there already.

View File

@@ -46,7 +46,7 @@ namespace Robust.Shared.GameObjects
IComponentFactory ComponentFactory { get; }
IEntitySystemManager EntitySysManager { get; }
IEntityNetworkManager? EntityNetManager { get; }
IEntityNetworkManager EntityNetManager { get; }
IEventBus EventBus { get; }
#region Entity Management

View File

@@ -13,10 +13,10 @@ internal sealed class RobustMemoryManager
// Let's be real this is a bandaid for pooling bullshit at an engine level and I don't know what
// good memory management looks like for PVS or the RobustSerializer.
private static readonly RecyclableMemoryStreamManager MemStreamManager = new()
private static readonly RecyclableMemoryStreamManager MemStreamManager = new(new RecyclableMemoryStreamManager.Options
{
ThrowExceptionOnToArray = true,
};
});
public RobustMemoryManager()
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,11 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Dynamics;
namespace Robust.Shared.GameObjects;
@@ -10,6 +15,65 @@ public sealed partial class EntityLookupSystem
* Local AABB / Box2Rotated queries for broadphase entities.
*/
private void AddLocalEntitiesIntersecting(
EntityUid lookupUid,
HashSet<EntityUid> intersecting,
Box2 localAABB,
LookupFlags flags,
BroadphaseComponent? lookup = null)
{
if (!_broadQuery.Resolve(lookupUid, ref lookup))
return;
var lookupPoly = new PolygonShape();
lookupPoly.SetAsBox(localAABB);
var (lookupPos, lookupRot) = _transform.GetWorldPositionRotation(lookupUid);
var lookupTransform = new Transform(lookupPos, lookupRot);
AddEntitiesIntersecting(lookupUid, intersecting, lookupPoly, lookupTransform, flags, lookup);
}
private void AddLocalEntitiesIntersecting(
EntityUid lookupUid,
HashSet<EntityUid> intersecting,
Box2Rotated localBounds,
LookupFlags flags,
BroadphaseComponent? lookup = null)
{
if (!_broadQuery.Resolve(lookupUid, ref lookup))
return;
var shape = new PolygonShape();
shape.Set(localBounds);
var transform = _physics.GetPhysicsTransform(lookupUid);
AddEntitiesIntersecting(lookupUid, intersecting, shape, transform, flags);
}
public bool AnyLocalEntitiesIntersecting(EntityUid lookupUid,
Box2 localAABB,
LookupFlags flags,
EntityUid? ignored = null,
BroadphaseComponent? lookup = null)
{
if (!_broadQuery.Resolve(lookupUid, ref lookup))
return false;
var shape = new PolygonShape();
shape.SetAsBox(localAABB);
var transform = _physics.GetPhysicsTransform(lookupUid);
return AnyEntitiesIntersecting(lookupUid, shape, transform, flags, ignored, lookup);
}
public HashSet<EntityUid> GetLocalEntitiesIntersecting(EntityUid gridId, Vector2i gridIndices, float enlargement = TileEnlargementRadius, LookupFlags flags = DefaultFlags, MapGridComponent? gridComp = null)
{
// Technically this doesn't consider anything overlapping from outside the grid but is this an issue?
var intersecting = new HashSet<EntityUid>();
GetLocalEntitiesIntersecting(gridId, gridIndices, intersecting, enlargement, flags, gridComp);
return intersecting;
}
/// <summary>
/// Gets the entities intersecting the specified broadphase entity using a local AABB.
/// </summary>
@@ -25,8 +89,7 @@ public sealed partial class EntityLookupSystem
var localAABB = GetLocalBounds(localTile, tileSize);
localAABB = localAABB.Enlarged(TileEnlargementRadius);
AddLocalEntitiesIntersecting(gridUid, intersecting, localAABB, flags);
AddContained(intersecting, flags);
GetLocalEntitiesIntersecting(gridUid, localAABB, intersecting, flags);
}
/// <summary>
@@ -48,4 +111,40 @@ public sealed partial class EntityLookupSystem
AddLocalEntitiesIntersecting(gridUid, intersecting, localBounds, flags);
AddContained(intersecting, flags);
}
/// <summary>
/// Returns the entities intersecting any of the supplied tiles. Faster than doing each tile individually.
/// </summary>
public HashSet<EntityUid> GetLocalEntitiesIntersecting(EntityUid gridId, IEnumerable<Vector2i> gridIndices, LookupFlags flags = DefaultFlags)
{
var intersecting = new HashSet<EntityUid>();
// Technically this doesn't consider anything overlapping from outside the grid but is this an issue?
if (!_gridQuery.TryGetComponent(gridId, out var mapGrid))
return intersecting;
// TODO: You can probably decompose the indices into larger areas if you take in a hashset instead.
foreach (var index in gridIndices)
{
GetLocalEntitiesIntersecting(gridId, index, intersecting, flags: flags, gridComp: mapGrid);
}
return intersecting;
}
public HashSet<EntityUid> GetLocalEntitiesIntersecting(BroadphaseComponent lookup, Box2 localAABB, LookupFlags flags = DefaultFlags)
{
var intersecting = new HashSet<EntityUid>();
AddLocalEntitiesIntersecting(lookup.Owner, intersecting, localAABB, flags, lookup);
AddContained(intersecting, flags);
return intersecting;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IEnumerable<EntityUid> GetLocalEntitiesIntersecting(TileRef tileRef, float enlargement = TileEnlargementRadius, LookupFlags flags = DefaultFlags)
{
return GetLocalEntitiesIntersecting(tileRef.GridUid, tileRef.GridIndices, enlargement, flags);
}
}

View File

@@ -97,6 +97,11 @@ public sealed partial class EntityLookupSystem : EntitySystem
public const float TileEnlargementRadius = -PhysicsConstants.PolygonRadius * 4f;
/// <summary>
/// The minimum size an entity is assumed to be for point purposes.
/// </summary>
public const float LookupEpsilon = float.Epsilon * 10f;
/// <summary>
/// Returns all non-grid entities. Consider using your own flags if you wish for a faster query.
/// </summary>
@@ -121,12 +126,11 @@ public sealed partial class EntityLookupSystem : EntitySystem
SubscribeLocalEvent<MapChangedEvent>(OnMapChange);
_transform.OnGlobalMoveEvent += OnMove;
EntityManager.EntityInitialized += OnEntityInit;
SubscribeLocalEvent<TransformComponent, PhysicsBodyTypeChangedEvent>(OnBodyTypeChange);
SubscribeLocalEvent<PhysicsComponent, ComponentStartup>(OnBodyStartup);
SubscribeLocalEvent<CollisionChangeEvent>(OnPhysicsUpdate);
EntityManager.EntityInitialized += OnEntityInit;
}
private void OnBodyStartup(EntityUid uid, PhysicsComponent component, ComponentStartup args)
@@ -354,8 +358,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
private void AddPhysicsTree(EntityUid uid, EntityUid broadUid, BroadphaseComponent broadphase, TransformComponent xform, PhysicsComponent body, FixturesComponent fixtures)
{
var xformQuery = GetEntityQuery<TransformComponent>();
var broadphaseXform = xformQuery.GetComponent(broadUid);
var broadphaseXform = _xformQuery.GetComponent(broadUid);
if (broadphaseXform.MapID == MapId.Nullspace)
return;
@@ -363,7 +366,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
if (!_mapQuery.TryGetComponent(broadphaseXform.MapUid, out var physMap))
throw new InvalidOperationException($"Physics Broadphase is missing physics map. {ToPrettyString(broadUid)}");
AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physMap, xform, body, fixtures, xformQuery);
AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physMap, xform, body, fixtures);
}
private void AddOrUpdatePhysicsTree(
@@ -374,8 +377,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
PhysicsMapComponent physicsMap,
TransformComponent xform,
PhysicsComponent body,
FixturesComponent manager,
EntityQuery<TransformComponent> xformQuery)
FixturesComponent manager)
{
DebugTools.Assert(!_container.IsEntityOrParentInContainer(body.Owner, null, xform));
DebugTools.Assert(xform.Broadphase == null || xform.Broadphase == new BroadphaseData(broadphase.Owner, physicsMap.Owner, body.CanCollide, body.BodyType == BodyType.Static));
@@ -385,7 +387,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
var tree = body.BodyType == BodyType.Static ? broadphase.StaticTree : broadphase.DynamicTree;
// TOOD optimize this. This function iterates UP through parents, while we are currently iterating down.
var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform, xformQuery);
var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform);
var mapTransform = new Transform(worldPos, worldRot);
// TODO BROADPHASE PARENTING this just assumes local = world
@@ -486,9 +488,6 @@ public sealed partial class EntityLookupSystem : EntitySystem
return;
// We need to recursively update the cached data and remove children from the move buffer
var xformQuery = GetEntityQuery<TransformComponent>();
var fixturesQuery = GetEntityQuery<FixturesComponent>();
DebugTools.Assert(HasComp<MapGridComponent>(args.Sender));
DebugTools.Assert(!newMap.IsValid() || HasComp<MapComponent>(newMap));
DebugTools.Assert(!oldMap.IsValid() || HasComp<MapComponent>(oldMap));
@@ -498,7 +497,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
foreach (var child in args.Component._children)
{
RecursiveOnGridChangedMap(child, oldMap, newMap, oldBuffer, newBuffer, xformQuery, fixturesQuery);
RecursiveOnGridChangedMap(child, oldMap, newMap, oldBuffer, newBuffer);
}
}
@@ -507,17 +506,14 @@ public sealed partial class EntityLookupSystem : EntitySystem
EntityUid oldMap,
EntityUid newMap,
Dictionary<FixtureProxy, Box2>? oldBuffer,
Dictionary<FixtureProxy, Box2>? newBuffer,
EntityQuery<TransformComponent> xformQuery,
EntityQuery<FixturesComponent> fixturesQuery)
Dictionary<FixtureProxy, Box2>? newBuffer)
{
if (!xformQuery.TryGetComponent(uid, out var xform))
if (!_xformQuery.TryGetComponent(uid, out var xform))
return;
foreach (var child in xform._children)
{
RecursiveOnGridChangedMap(child, oldMap, newMap, oldBuffer, newBuffer, xformQuery, fixturesQuery);
RecursiveOnGridChangedMap(child, oldMap, newMap, oldBuffer, newBuffer);
}
if (xform.Broadphase == null || !xform.Broadphase.Value.CanCollide)
@@ -526,7 +522,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
DebugTools.Assert(_netMan.IsClient || !xform.Broadphase.Value.PhysicsMap.IsValid() || xform.Broadphase.Value.PhysicsMap == oldMap);
xform.Broadphase = xform.Broadphase.Value with { PhysicsMap = newMap };
if (!fixturesQuery.TryGetComponent(uid, out var fixtures))
if (!_fixturesQuery.TryGetComponent(uid, out var fixtures))
return;
if (oldBuffer != null)
@@ -543,15 +539,17 @@ public sealed partial class EntityLookupSystem : EntitySystem
// TODO PERFORMANCE
// track world position while recursively iterating down through children.
var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform, xformQuery);
var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform);
var mapTransform = new Transform(worldPos, worldRot);
foreach (var fixture in fixtures.Fixtures.Values)
{
for (var i = 0; i < fixture.ProxyCount; i++)
{
var proxy = fixture.Proxies[i];
newBuffer[proxy] = fixture.Shape.ComputeAABB(mapTransform, i);
}
}
}
private void UpdateParent(EntityUid uid, TransformComponent xform, EntityUid oldParent)
@@ -685,7 +683,7 @@ public sealed partial class EntityLookupSystem : EntitySystem
}
else
{
AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physicsMap, xform, body, _fixturesQuery.GetComponent(uid), _xformQuery);
AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physicsMap, xform, body, _fixturesQuery.GetComponent(uid));
}
if (xform.ChildCount == 0 || !recursive)

View File

@@ -722,6 +722,21 @@ public abstract partial class SharedMapSystem
return new GridTileEnumerator(uid, grid.Chunks.GetEnumerator(), grid.ChunkSize, ignoreEmpty);
}
public void SetTile(Entity<MapGridComponent> grid, EntityCoordinates coordinates, Tile tile)
{
SetTile(grid.Owner, grid.Comp, coordinates, tile);
}
public void SetTile(Entity<MapGridComponent> grid, Vector2i gridIndices, Tile tile)
{
SetTile(grid.Owner, grid.Comp, gridIndices, tile);
}
public void SetTiles(Entity<MapGridComponent> grid, List<(Vector2i GridIndices, Tile Tile)> tiles)
{
SetTiles(grid.Owner, grid.Comp, tiles);
}
public void SetTile(EntityUid uid, MapGridComponent grid, EntityCoordinates coords, Tile tile)
{
var localTile = CoordinatesToTile(uid, grid, coords);

View File

@@ -23,15 +23,16 @@ public abstract partial class SharedTransformSystem
TransformComponent xform,
MapGridComponent oldGrid,
MapGridComponent newGrid,
Vector2i oldTilePos,
Vector2i tilePos,
EntityUid oldGridUid,
EntityUid newGridUid,
TransformComponent oldGridXform,
TransformComponent newGridXform,
EntityQuery<TransformComponent> xformQuery)
Angle rotation)
{
// Bypass some of the expensive stuff in unanchoring / anchoring.
_map.RemoveFromSnapGridCell(oldGridUid, oldGrid, tilePos, uid);
_map.RemoveFromSnapGridCell(oldGridUid, oldGrid, oldTilePos, uid);
_map.AddToSnapGridCell(newGridUid, newGrid, tilePos, uid);
// TODO: Could do this re-parent way better.
// Unfortunately we don't want any anchoring events to go out hence... this.
@@ -40,21 +41,25 @@ public abstract partial class SharedTransformSystem
newGridXform._children.Add(uid);
xform._parent = newGridUid;
xform._anchored = true;
var oldPos = xform._localPosition;
var oldRot = xform._localRotation;
xform._localPosition = tilePos + newGrid.TileSizeHalfVector;
xform._localRotation += rotation;
SetGridId(uid, xform, newGridUid, xformQuery);
SetGridId(uid, xform, newGridUid, XformQuery);
var reParent = new EntParentChangedMessage(uid, oldGridUid, xform.MapID, xform);
RaiseLocalEvent(uid, ref reParent, true);
var meta = MetaData(uid);
var movEevee = new MoveEvent((uid, xform, meta),
new EntityCoordinates(oldGridUid, xform._localPosition),
new EntityCoordinates(oldGridUid, oldPos),
new EntityCoordinates(newGridUid, xform._localPosition),
xform.LocalRotation,
oldRot,
xform.LocalRotation,
_gameTiming.ApplyingState);
RaiseLocalEvent(uid, ref movEevee);
InvokeGlobalMoveEvent(ref movEevee);
DebugTools.Assert(xformQuery.GetComponent(oldGridUid).MapID == xformQuery.GetComponent(newGridUid).MapID);
DebugTools.Assert(XformQuery.GetComponent(oldGridUid).MapID == XformQuery.GetComponent(newGridUid).MapID);
DebugTools.Assert(xform._anchored);
Dirty(uid, xform, meta);

View File

@@ -91,7 +91,7 @@ namespace Robust.Shared.GameObjects
var aabb = _lookup.GetLocalBounds(tileIndices, grid.TileSize);
foreach (var entity in _lookup.GetEntitiesIntersecting(lookup, aabb, LookupFlags.Uncontained | LookupFlags.Approximate))
foreach (var entity in _lookup.GetLocalEntitiesIntersecting(lookup, aabb, LookupFlags.Uncontained | LookupFlags.Approximate))
{
if (!XformQuery.TryGetComponent(entity, out var xform) || xform.ParentUid != gridId)
continue;

View File

@@ -156,6 +156,13 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
OpenInterfaces.GetOrNew(session).Add(bui);
RaiseLocalEvent(bui.Owner, new BoundUIOpenedEvent(bui.UiKey, bui.Owner, session));
if (!bui._subscribedSessions.Contains(session))
{
// This can happen if Content closed a BUI from inside the event handler.
// This will already have caused a redundant close event to be sent to the client, but whatever.
// Just avoid doing the rest to avoid any state corruption shit.
return false;
}
RaiseNetworkEvent(new BoundUIWrapMessage(GetNetEntity(bui.Owner), new OpenBoundInterfaceMessage(), bui.UiKey), session.Channel);

View File

@@ -73,7 +73,9 @@ namespace Robust.Shared.Log
public void Log(LogLevel level, Exception? exception, string message, params object?[] args)
{
_sLogger.BindMessageTemplate(message, args, out var parsedTemplate, out var properties);
if (!_sLogger.BindMessageTemplate(message, args, out var parsedTemplate, out var properties))
return;
var msg = new LogEvent(DateTimeOffset.Now, level.ToSerilog(), exception, parsedTemplate, properties);
LogInternal(Name, msg);
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -42,7 +43,9 @@ namespace Robust.Shared.Map
var gridSearchBox = Box2.UnitCentered.Scale(searchBoxSize).Translated(mapCoords.Position);
// find grids in search box
var gridsInArea = mapManager.FindGridsIntersecting(mapCoords.MapId, gridSearchBox);
var gridsInArea = new List<Entity<MapGridComponent>>();
mapManager.FindGridsIntersecting(mapCoords.MapId, gridSearchBox, ref gridsInArea);
// find closest grid intersecting our search box.
gridUid = EntityUid.Invalid;
@@ -57,7 +60,7 @@ namespace Robust.Shared.Map
// TODO: Use CollisionManager to get nearest edge.
// figure out closest intersect
var gridIntersect = gridSearchBox.Intersect(gridXform.WorldMatrix.TransformBox(grid.LocalAABB));
var gridIntersect = gridSearchBox.Intersect(gridXform.WorldMatrix.TransformBox(grid.Comp.LocalAABB));
var gridDist = (gridIntersect.Center - mapCoords.Position).LengthSquared();
if (gridDist >= distance)

View File

@@ -6,6 +6,8 @@ using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
namespace Robust.Shared.Map
{
@@ -18,6 +20,9 @@ namespace Robust.Shared.Map
/// </summary>
public interface IMapManager
{
public const bool Approximate = false;
public const bool IncludeMap = true;
[Obsolete("Use EntityQuery<MapGridComponent>")]
IEnumerable<MapGridComponent> GetAllGrids();
@@ -102,82 +107,131 @@ namespace Robust.Shared.Map
IEnumerable<Entity<MapGridComponent>> GetAllGrids(MapId mapId);
#region MapId
public void FindGridsIntersecting(MapId mapId, IPhysShape shape, Transform transform,
ref List<Entity<MapGridComponent>> grids, bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(MapId mapId, PolygonShape shape, Transform transform, GridCallback callback,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, GridCallback callback, bool approx = Approximate,
bool includeMap = IncludeMap);
public void FindGridsIntersecting<TState>(MapId mapId, Box2 worldAABB, ref TState state,
GridCallback<TState> callback, bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, ref List<Entity<MapGridComponent>> grids,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, GridCallback callback,
bool approx = Approximate,
bool includeMap = IncludeMap);
public void FindGridsIntersecting<TState>(MapId mapId, Box2Rotated worldBounds, ref TState state,
GridCallback<TState> callback,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> grids,
bool approx = Approximate, bool includeMap = IncludeMap);
#endregion
#region MapEnt
public void FindGridsIntersecting(EntityUid mapEnt, PolygonShape shape, Transform transform, GridCallback callback,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting<TState>(EntityUid mapEnt, IPhysShape shape, Transform transform,
ref TState state, GridCallback<TState> callback, bool approx = Approximate, bool includeMap = IncludeMap);
/// <summary>
/// Attempts to find the map grid under the map location.
/// Returns true if any grids overlap the specified shapes.
/// </summary>
/// <remarks>
/// This method will never return the map's default grid.
/// </remarks>
/// <param name="mapId">Map to search.</param>
/// <param name="worldPos">Location on the map to check for a grid.</param>
/// <param name="grid">Grid that was found, if any.</param>
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(MapId mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
public void FindGridsIntersecting(EntityUid mapEnt, List<IPhysShape> shapes, Transform transform,
ref List<Entity<MapGridComponent>> entities, bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(EntityUid mapEnt, IPhysShape shape, Transform transform,
ref List<Entity<MapGridComponent>> grids, bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(EntityUid mapEnt, Box2 worldAABB, GridCallback callback,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting<TState>(EntityUid mapEnt, Box2 worldAABB, ref TState state,
GridCallback<TState> callback, bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(EntityUid mapEnt, Box2 worldAABB, ref List<Entity<MapGridComponent>> grids,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(EntityUid mapEnt, Box2Rotated worldBounds, GridCallback callback,
bool approx = Approximate,
bool includeMap = IncludeMap);
public void FindGridsIntersecting<TState>(EntityUid mapEnt, Box2Rotated worldBounds, ref TState state,
GridCallback<TState> callback,
bool approx = Approximate, bool includeMap = IncludeMap);
public void FindGridsIntersecting(EntityUid mapEnt, Box2Rotated worldBounds,
ref List<Entity<MapGridComponent>> grids,
bool approx = Approximate, bool includeMap = IncludeMap);
#endregion
#region TryFindGridAt
public bool TryFindGridAt(
EntityUid mapEnt,
Vector2 worldPos,
out EntityUid uid,
[NotNullWhen(true)] out MapGridComponent? grid);
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
/// <remarks>
/// This method will never return the map's default grid.
/// </remarks>
/// <param name="mapId">Map to search.</param>
/// <param name="worldPos">Location on the map to check for a grid.</param>
/// <param name="grid">Grid that was found, if any.</param>
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(EntityUid mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
public bool TryFindGridAt(MapId mapId, Vector2 worldPos, out EntityUid uid,
[NotNullWhen(true)] out MapGridComponent? grid);
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
/// <remarks>
/// This method will never return the map's default grid.
/// </remarks>
/// <param name="mapId">Map to search.</param>
/// <param name="worldPos">Location on the map to check for a grid.</param>
/// <param name="grid">Grid that was found, if any.</param>
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(MapId mapId, Vector2 worldPos, EntityQuery<TransformComponent> query, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
public bool TryFindGridAt(MapCoordinates mapCoordinates, out EntityUid uid,
[NotNullWhen(true)] out MapGridComponent? grid);
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
/// <remarks>
/// This method will never return the map's default grid.
/// </remarks>
/// <param name="mapCoordinates">Location on the map to check for a grid.</param>
/// <param name="grid">Grid that was found, if any.</param>
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(MapCoordinates mapCoordinates, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
#endregion
void FindGridsIntersecting(MapId mapId, Box2 worldAABB, GridCallback callback, bool approx = false, bool includeMap = true);
#region Obsolete
void FindGridsIntersecting<TState>(MapId mapId, Box2 worldAABB, ref TState state, GridCallback<TState> callback, bool approx = false, bool includeMap = true);
[Obsolete]
public bool TryFindGridAt(MapId mapId, Vector2 worldPos, EntityQuery<TransformComponent> query, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid)
{
return TryFindGridAt(mapId, worldPos, out uid, out grid);
}
void FindGridsIntersecting(MapId mapId, Box2 worldAABB, ref List<Entity<MapGridComponent>> state, bool approx = false, bool includeMap = true);
void FindGridsIntersecting(EntityUid map, Box2 worldAABB, ref List<Entity<MapGridComponent>> state, bool approx = false, bool includeMap = true);
[Obsolete]
public IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2 worldAabb, bool approx = false, bool includeMap = true)
{
var grids = new List<Entity<MapGridComponent>>();
FindGridsIntersecting(mapId, worldAabb, ref grids, approx, includeMap);
void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, GridCallback callback, bool approx = false, bool includeMap = true);
foreach (var grid in grids)
{
yield return grid.Comp;
}
}
void FindGridsIntersecting<TState>(MapId mapId, Box2Rotated worldBounds, ref TState state, GridCallback<TState> callback, bool approx = false, bool includeMap = true);
[Obsolete]
public IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2Rotated worldArea, bool approx = false, bool includeMap = true)
{
var grids = new List<Entity<MapGridComponent>>();
FindGridsIntersecting(mapId, worldArea, ref grids, approx, includeMap);
void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> state, bool approx = false, bool includeMap = true);
foreach (var grid in grids)
{
yield return grid.Comp;
}
}
/// <summary>
/// Returns the grids intersecting this AABB.
/// </summary>
/// <param name="mapId">The relevant MapID</param>
/// <param name="worldAabb">The AABB to intersect</param>
/// <param name="approx">Set to false if you wish to accurately get the grid bounds per-tile.</param>
/// <returns></returns>
IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2 worldAabb, bool approx = false, bool includeMap = true);
/// <summary>
/// Returns the grids intersecting this AABB.
/// </summary>
/// <param name="mapId">The relevant MapID</param>
/// <param name="worldArea">The AABB to intersect</param>
/// <param name="approx">Set to false if you wish to accurately get the grid bounds per-tile.</param>
IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2Rotated worldArea, bool approx = false, bool includeMap = true);
#endregion
void DeleteGrid(EntityUid euid);

View File

@@ -4,228 +4,284 @@ using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Robust.Shared.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Map.Enumerators;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
namespace Robust.Shared.Map;
internal partial class MapManager
{
[Obsolete("Use the FindGridsIntersecting callback")]
public IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2Rotated bounds, bool approx = false, bool includeMap = true)
{
var aabb = bounds.CalcBoundingBox();
// TODO: We can do slower GJK checks to check if 2 bounds actually intersect, but WYCI.
return FindGridsIntersecting(mapId, aabb, includeMap, approx);
}
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, GridCallback callback, bool approx = false, bool includeMap = true)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldAABB, callback, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapEnt, Box2 worldAABB, GridCallback callback, bool approx = false, bool includeMap = true)
{
if (!EntityManager.TryGetComponent<GridTreeComponent>(mapEnt, out var gridTree))
return;
var state = (worldAABB, gridTree.Tree, callback, approx, this, _transformSystem);
gridTree.Tree.Query(ref state,
static (ref (Box2 worldAABB,
B2DynamicTree<(EntityUid Uid, MapGridComponent Grid)> gridTree,
GridCallback callback,
bool approx,
MapManager mapManager,
SharedTransformSystem xformSystem) tuple,
DynamicTree.Proxy proxy) =>
{
var data = tuple.gridTree.GetUserData(proxy);
if (!tuple.approx && !tuple.mapManager.IsIntersecting(tuple.worldAABB, data.Uid, data.Grid))
{
return true;
}
return tuple.callback(data.Uid, data.Grid);
}, worldAABB); ;
if (includeMap && EntityManager.TryGetComponent<MapGridComponent>(mapEnt, out var grid))
{
callback(mapEnt, grid);
}
}
public void FindGridsIntersecting<TState>(MapId mapId, Box2 worldAABB, ref TState state, GridCallback<TState> callback, bool approx = false, bool includeMap = true)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldAABB, ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(EntityUid mapUid, Box2 worldAABB, ref TState state, GridCallback<TState> callback, bool approx = false, bool includeMap = true)
{
if (!EntityManager.TryGetComponent<GridTreeComponent>(mapUid, out var gridTree))
return;
if (includeMap && EntityManager.TryGetComponent<MapGridComponent>(mapUid, out var grid))
{
callback(mapUid, grid, ref state);
}
var state2 = (state, worldAABB, gridTree.Tree, callback, approx, this, _transformSystem);
gridTree.Tree.Query(ref state2, static (ref (
TState state,
Box2 worldAABB,
B2DynamicTree<(EntityUid Uid, MapGridComponent Grid)> gridTree,
GridCallback<TState> callback,
bool approx,
MapManager mapManager,
SharedTransformSystem xformSystem) tuple,
DynamicTree.Proxy proxy) =>
{
var data = tuple.gridTree.GetUserData(proxy);
if (!tuple.approx && !tuple.mapManager.IsIntersecting(tuple.worldAABB, data.Uid, data.Grid))
{
return true;
}
return tuple.callback(data.Uid, data.Grid, ref tuple.state);
}, worldAABB);
state = state2.state;
}
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, ref List<Entity<MapGridComponent>> state,
bool approx = false, bool includeMap = true)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldAABB, ref state, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid map, Box2 worldAABB, ref List<Entity<MapGridComponent>> state,
bool approx = false, bool includeMap = true)
{
FindGridsIntersecting(map, worldAABB, ref state, static (EntityUid uid, MapGridComponent grid,
ref List<Entity<MapGridComponent>> list) =>
{
list.Add((uid, grid));
return true;
}, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapId, Box2Rotated worldBounds, GridCallback callback, bool approx = false,
bool includeMap = true)
{
FindGridsIntersecting(mapId, worldBounds.CalcBoundingBox(), callback, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, GridCallback callback, bool approx = false,
bool includeMap = true)
{
FindGridsIntersecting(mapId, worldBounds.CalcBoundingBox(), callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(EntityUid mapId, Box2Rotated worldBounds, ref TState state, GridCallback<TState> callback,
bool approx = false, bool includeMap = true)
{
FindGridsIntersecting(mapId, worldBounds.CalcBoundingBox(), ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(MapId mapId, Box2Rotated worldBounds, ref TState state, GridCallback<TState> callback,
bool approx = false, bool includeMap = true)
{
FindGridsIntersecting(mapId, worldBounds.CalcBoundingBox(), ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> state,
bool approx = false, bool includeMap = true)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldBounds, ref state, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapId, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> state,
bool approx = false, bool includeMap = true)
{
FindGridsIntersecting(mapId, worldBounds, ref state, static (EntityUid uid, MapGridComponent grid,
ref List<Entity<MapGridComponent>> list) =>
{
list.Add((uid, grid));
return true;
}, approx, includeMap);
}
private bool IsIntersecting(
Box2 aabb,
EntityUid gridUid,
MapGridComponent grid)
ChunkEnumerator enumerator,
IPhysShape shape,
Transform shapeTransform,
EntityUid gridUid)
{
var (worldPos, worldRot, matrix, invMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridUid);
var overlap = matrix.TransformBox(grid.LocalAABB).Intersect(aabb);
var localAABB = invMatrix.TransformBox(overlap);
var gridTransform = _physics.GetPhysicsTransform(gridUid);
if (_physicsQuery.HasComponent(gridUid))
while (enumerator.MoveNext(out var chunk))
{
var enumerator = _mapSystem.GetLocalMapChunks(gridUid, grid, localAABB);
var transform = new Transform(worldPos, worldRot);
while (enumerator.MoveNext(out var chunk))
foreach (var fixture in chunk.Fixtures.Values)
{
foreach (var fixture in chunk.Fixtures.Values)
for (var j = 0; j < fixture.Shape.ChildCount; j++)
{
for (var j = 0; j < fixture.Shape.ChildCount; j++)
if (_manifolds.TestOverlap(shape, 0, fixture.Shape, j, shapeTransform, gridTransform))
{
// TODO: Should do shape intersects given this is supposed to be non-approx.
if (!fixture.Shape.ComputeAABB(transform, j).Intersects(aabb)) continue;
return true;
}
}
}
}
return grid.ChunkCount == 0 && aabb.Contains(worldPos);
}
[Obsolete("Use the FindGridsIntersecting callback")]
public IEnumerable<MapGridComponent> FindGridsIntersecting(MapId mapId, Box2 worldAabb, bool approx = false, bool includeMap = true)
{
var grids = new List<MapGridComponent>();
var state = grids;
FindGridsIntersecting(mapId, worldAabb, ref state,
(EntityUid _, MapGridComponent grid, ref List<MapGridComponent> list) =>
{
list.Add(grid);
return true;
}, approx);
return grids;
}
public bool TryFindGridAt(
MapId mapId,
Vector2 worldPos,
EntityQuery<TransformComponent> xformQuery,
out EntityUid uid,
[NotNullWhen(true)] out MapGridComponent? grid)
{
if (_mapEntities.TryGetValue(mapId, out var map))
return TryFindGridAt(map, worldPos, xformQuery, out uid, out grid);
uid = default;
grid = null;
return false;
}
#region MapId
public void FindGridsIntersecting(MapId mapId, IPhysShape shape, Transform transform,
ref List<Entity<MapGridComponent>> grids, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, shape, transform, ref grids, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, PolygonShape shape, Transform transform, GridCallback callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, shape, transform, callback, includeMap, approx);
}
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, GridCallback callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, worldAABB, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(MapId mapId, Box2 worldAABB, ref TState state, GridCallback<TState> callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldAABB, ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, Box2 worldAABB, ref List<Entity<MapGridComponent>> grids,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var map))
FindGridsIntersecting(map, worldAABB, ref grids, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, GridCallback callback, bool approx = IMapManager.Approximate,
bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, worldBounds, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(MapId mapId, Box2Rotated worldBounds, ref TState state, GridCallback<TState> callback,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, worldBounds, ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting(MapId mapId, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> grids,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (_mapEntities.TryGetValue(mapId, out var mapEnt))
FindGridsIntersecting(mapEnt, worldBounds, ref grids, approx, includeMap);
}
#endregion
#region MapEnt
public void FindGridsIntersecting(EntityUid mapEnt, PolygonShape shape, Transform transform, GridCallback callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (!_gridTreeQuery.TryGetComponent(mapEnt, out var gridTree))
return;
if (includeMap && _gridQuery.TryGetComponent(mapEnt, out var mapGrid))
{
callback(mapEnt, mapGrid);
}
var worldAABB = shape.ComputeAABB(transform, 0);
var gridState = new GridQueryState(
callback,
worldAABB,
shape,
transform,
gridTree.Tree,
_mapSystem,
this,
_transformSystem,
approx);
gridTree.Tree.Query(ref gridState, static (ref GridQueryState state, DynamicTree.Proxy proxy) =>
{
// Even for approximate we'll check if any chunks roughly overlap.
var data = state.Tree.GetUserData(proxy);
var gridInvMatrix = state.TransformSystem.GetInvWorldMatrix(data.Uid);
var localAABB = gridInvMatrix.TransformBox(state.WorldAABB);
var overlappingChunks = state.MapSystem.GetLocalMapChunks(data.Uid, data.Grid, localAABB);
if (state.Approximate)
{
if (!overlappingChunks.MoveNext(out _))
return true;
}
else if (!state.MapManager.IsIntersecting(overlappingChunks, state.Shape, state.Transform, data.Uid))
{
return true;
}
state.Callback(data.Uid, data.Grid);
return true;
}, worldAABB);
}
public void FindGridsIntersecting<TState>(EntityUid mapEnt, IPhysShape shape, Transform transform,
ref TState state, GridCallback<TState> callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
if (!_gridTreeQuery.TryGetComponent(mapEnt, out var gridTree))
return;
if (includeMap && _gridQuery.TryGetComponent(mapEnt, out var mapGrid))
{
callback(mapEnt, mapGrid, ref state);
}
var worldAABB = shape.ComputeAABB(transform, 0);
var gridState = new GridQueryState<TState>(
callback,
state,
worldAABB,
shape,
transform,
gridTree.Tree,
_mapSystem,
this,
_transformSystem,
approx);
gridTree.Tree.Query(ref gridState, static (ref GridQueryState<TState> state, DynamicTree.Proxy proxy) =>
{
// Even for approximate we'll check if any chunks roughly overlap.
var data = state.Tree.GetUserData(proxy);
var gridInvMatrix = state.TransformSystem.GetInvWorldMatrix(data.Uid);
var localAABB = gridInvMatrix.TransformBox(state.WorldAABB);
var overlappingChunks = state.MapSystem.GetLocalMapChunks(data.Uid, data.Grid, localAABB);
if (state.Approximate)
{
if (!overlappingChunks.MoveNext(out _))
return true;
}
else if (!state.MapManager.IsIntersecting(overlappingChunks, state.Shape, state.Transform, data.Uid))
{
return true;
}
var callbackState = state.State;
var result = state.Callback(data.Uid, data.Grid, ref callbackState);
state.State = callbackState;
return result;
}, worldAABB);
// By-ref things
state = gridState.State;
}
/// <summary>
/// Returns true if any grids overlap the specified shapes.
/// </summary>
public void FindGridsIntersecting(EntityUid mapEnt, List<IPhysShape> shapes, Transform transform, ref List<Entity<MapGridComponent>> entities, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
foreach (var shape in shapes)
{
FindGridsIntersecting(mapEnt, shape, transform, ref entities);
}
}
public void FindGridsIntersecting(EntityUid mapEnt, IPhysShape shape, Transform transform,
ref List<Entity<MapGridComponent>> grids, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var state = grids;
FindGridsIntersecting(mapEnt, shape, transform, ref state,
static (EntityUid uid, MapGridComponent grid, ref List<Entity<MapGridComponent>> list) =>
{
list.Add((uid, grid));
return true;
}, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapEnt, Box2 worldAABB, GridCallback callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.SetAsBox(worldAABB);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(EntityUid mapEnt, Box2 worldAABB, ref TState state, GridCallback<TState> callback, bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.SetAsBox(worldAABB);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapEnt, Box2 worldAABB, ref List<Entity<MapGridComponent>> grids,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.SetAsBox(worldAABB);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, ref grids, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapEnt, Box2Rotated worldBounds, GridCallback callback, bool approx = IMapManager.Approximate,
bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.Set(worldBounds);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, callback, approx, includeMap);
}
public void FindGridsIntersecting<TState>(EntityUid mapEnt, Box2Rotated worldBounds, ref TState state, GridCallback<TState> callback,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.Set(worldBounds);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, ref state, callback, approx, includeMap);
}
public void FindGridsIntersecting(EntityUid mapEnt, Box2Rotated worldBounds, ref List<Entity<MapGridComponent>> grids,
bool approx = IMapManager.Approximate, bool includeMap = IMapManager.IncludeMap)
{
var shape = new PolygonShape();
shape.Set(worldBounds);
FindGridsIntersecting(mapEnt, shape, Transform.Empty, ref grids, approx, includeMap);
}
#endregion
#region TryFindGridAt
public bool TryFindGridAt(
EntityUid mapId,
EntityUid mapEnt,
Vector2 worldPos,
EntityQuery<TransformComponent> xformQuery,
out EntityUid uid,
[NotNullWhen(true)] out MapGridComponent? grid)
{
@@ -238,7 +294,7 @@ internal partial class MapManager
grid = null;
var state = (uid, grid, worldPos, _mapSystem, _transformSystem);
FindGridsIntersecting(mapId, aabb, ref state, static (EntityUid iUid, MapGridComponent iGrid, ref (
FindGridsIntersecting(mapEnt, aabb, ref state, static (EntityUid iUid, MapGridComponent iGrid, ref (
EntityUid uid,
MapGridComponent? grid,
Vector2 worldPos,
@@ -270,11 +326,11 @@ internal partial class MapManager
tuple.uid = iUid;
tuple.grid = iGrid;
return false;
}, approx: true);
}, approx: true, includeMap: false);
if (state.grid == null && EntityManager.TryGetComponent<MapGridComponent>(mapId, out var mapGrid))
if (state.grid == null && _gridQuery.TryGetComponent(mapEnt, out var mapGrid))
{
uid = mapId;
uid = mapEnt;
grid = mapGrid;
return true;
}
@@ -284,21 +340,13 @@ internal partial class MapManager
return grid != null;
}
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
public bool TryFindGridAt(EntityUid mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid)
{
return TryFindGridAt(mapId, worldPos, _xformQuery, out uid, out grid);
}
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
public bool TryFindGridAt(MapId mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid)
{
if (_mapEntities.TryGetValue(mapId, out var map))
return TryFindGridAt(map, worldPos, _xformQuery, out uid, out grid);
return TryFindGridAt(map, worldPos, out uid, out grid);
uid = default;
grid = null;
@@ -312,4 +360,29 @@ internal partial class MapManager
{
return TryFindGridAt(mapCoordinates.MapId, mapCoordinates.Position, out uid, out grid);
}
#endregion
private readonly record struct GridQueryState(
GridCallback Callback,
Box2 WorldAABB,
IPhysShape Shape,
Transform Transform,
B2DynamicTree<(EntityUid Uid, MapGridComponent Grid)> Tree,
SharedMapSystem MapSystem,
MapManager MapManager,
SharedTransformSystem TransformSystem,
bool Approximate);
private record struct GridQueryState<TState>(
GridCallback<TState> Callback,
TState State,
Box2 WorldAABB,
IPhysShape Shape,
Transform Transform,
B2DynamicTree<(EntityUid Uid, MapGridComponent Grid)> Tree,
SharedMapSystem MapSystem,
MapManager MapManager,
SharedTransformSystem TransformSystem,
bool Approximate);
}

View File

@@ -4,7 +4,10 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -16,19 +19,29 @@ internal partial class MapManager : IMapManagerInternal, IEntityEventSubscriber
{
[field: Dependency] public IGameTiming GameTiming { get; } = default!;
[field: Dependency] public IEntityManager EntityManager { get; } = default!;
[Dependency] private readonly IManifoldManager _manifolds = default!;
[Dependency] private readonly IConsoleHost _conhost = default!;
private ISawmill _sawmill = default!;
private FixtureSystem _fixtureSystem = default!;
private SharedMapSystem _mapSystem = default!;
private SharedPhysicsSystem _physics = default!;
private SharedTransformSystem _transformSystem = default!;
private EntityQuery<FixturesComponent> _fixturesQuery;
private EntityQuery<GridTreeComponent> _gridTreeQuery;
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TransformComponent> _xformQuery;
/// <inheritdoc />
public void Initialize()
{
_fixturesQuery = EntityManager.GetEntityQuery<FixturesComponent>();
_gridTreeQuery = EntityManager.GetEntityQuery<GridTreeComponent>();
_gridQuery = EntityManager.GetEntityQuery<MapGridComponent>();
_physicsQuery = EntityManager.GetEntityQuery<PhysicsComponent>();
_xformQuery = EntityManager.GetEntityQuery<TransformComponent>();
@@ -45,6 +58,8 @@ internal partial class MapManager : IMapManagerInternal, IEntityEventSubscriber
/// <inheritdoc />
public void Startup()
{
_fixtureSystem = EntityManager.System<FixtureSystem>();
_physics = EntityManager.System<SharedPhysicsSystem>();
_transformSystem = EntityManager.System<SharedTransformSystem>();
_mapSystem = EntityManager.System<SharedMapSystem>();

View File

@@ -4,14 +4,12 @@ using Robust.Shared.Serialization;
namespace Robust.Shared.Network.Messages;
#nullable disable
public sealed class MsgConCompletionResp : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public int Seq { get; set; }
public CompletionResult Result { get; set; }
public CompletionResult Result { get; set; } = default!;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{

View File

@@ -71,7 +71,7 @@ public sealed class DynamicTreeBroadPhase : IBroadPhase
public IEnumerable<FixtureProxy> QueryAabb(List<FixtureProxy> proxies, Box2 aabb, bool approx = false)
{
QueryAabb(ref proxies, (ref List<FixtureProxy> lst, in FixtureProxy i) =>
QueryAabb(ref proxies, static (ref List<FixtureProxy> lst, in FixtureProxy i) =>
{
lst.Add(i);
return true;
@@ -89,7 +89,7 @@ public sealed class DynamicTreeBroadPhase : IBroadPhase
{
var tuple = (state, _tree, callback, point, approx, _extractAabb);
_tree.Query(ref tuple,
(ref (TState state, B2DynamicTree<FixtureProxy> tree, DynamicTree<FixtureProxy>.QueryCallbackDelegate<TState> callback, Vector2 point, bool approx, DynamicTree<FixtureProxy>.ExtractAabbDelegate extract) tuple,
static (ref (TState state, B2DynamicTree<FixtureProxy> tree, DynamicTree<FixtureProxy>.QueryCallbackDelegate<TState> callback, Vector2 point, bool approx, DynamicTree<FixtureProxy>.ExtractAabbDelegate extract) tuple,
DynamicTree.Proxy proxy) =>
{
var item = tuple.tree.GetUserData(proxy)!;
@@ -112,7 +112,7 @@ public sealed class DynamicTreeBroadPhase : IBroadPhase
{
var list = new List<FixtureProxy>();
QueryPoint(ref list, (ref List<FixtureProxy> list, in FixtureProxy i) =>
QueryPoint(ref list, static (ref List<FixtureProxy> list, in FixtureProxy i) =>
{
list.Add(i);
return true;

View File

@@ -188,6 +188,37 @@ namespace Robust.Shared.Physics.Collision.Shapes
Set(Vertices.AsSpan(), VertexCount);
}
public bool Set(Box2Rotated bounds)
{
Span<Vector2> vertices = stackalloc Vector2[]
{
bounds.BottomLeft,
bounds.BottomRight,
bounds.TopRight,
bounds.TopLeft,
};
return Set(vertices, 4);
}
public void SetAsBox(Box2 box)
{
Array.Resize(ref Vertices, 4);
Array.Resize(ref Normals, 4);
Vertices[0] = box.BottomLeft;
Vertices[1] = box.BottomRight;
Vertices[2] = box.TopRight;
Vertices[3] = box.TopLeft;
Normals[0] = new Vector2(0.0f, -1.0f);
Normals[1] = new Vector2(1.0f, 0.0f);
Normals[2] = new Vector2(0.0f, 1.0f);
Normals[3] = new Vector2(-1.0f, 0.0f);
Centroid = box.Center;
}
public void SetAsBox(float halfWidth, float halfHeight)
{
Array.Resize(ref Vertices, 4);

View File

@@ -222,7 +222,7 @@ namespace Robust.Shared.Physics
{
var list = new List<T>();
QueryAabb(ref list, (ref List<T> lst, in T i) =>
QueryAabb(ref list, static (ref List<T> lst, in T i) =>
{
lst.Add(i);
return true;

View File

@@ -248,7 +248,7 @@ namespace Robust.Shared.Physics.Systems
var computeProperties = false;
// Given a bunch of data isn't serialized need to sort of re-initialise it
var newFixtures = new Dictionary<string, Fixture>(state.Fixtures.Count());
var newFixtures = new Dictionary<string, Fixture>(state.Fixtures.Count);
foreach (var (id, fixture) in state.Fixtures)
{

View File

@@ -227,7 +227,7 @@ namespace Robust.Shared.Physics.Systems
ref var buffer = ref tuple.pairBuffer;
tuple.system.FindPairs(tuple.proxy, tuple.worldAABB, uid, buffer);
return true;
});
}, approx: true, includeMap: false);
// Struct ref moment, I have no idea what's fastest.
buffer = state.buffer;
@@ -287,7 +287,7 @@ namespace Robust.Shared.Physics.Systems
// TODO: Need to handle grids colliding with non-grid entities with the same layer
// (nothing in SS14 does this yet).
var transform = _physicsSystem.GetPhysicsTransform(gridUid, xformQuery: _xformQuery);
var transform = _physicsSystem.GetPhysicsTransform(gridUid);
var state = (gridUid, grid, transform, worldMatrix, invWorldMatrix, _map, _physicsSystem, _transform, _physicsQuery, _xformQuery);
_mapManager.FindGridsIntersecting(mapId, aabb, ref state,
@@ -311,7 +311,7 @@ namespace Robust.Shared.Physics.Systems
var (_, _, otherGridMatrix, otherGridInvMatrix) = tuple.xformSystem.GetWorldPositionRotationMatrixWithInv(collidingXform, tuple.xformQuery);
var otherGridBounds = otherGridMatrix.TransformBox(component.LocalAABB);
var otherTransform = tuple._physicsSystem.GetPhysicsTransform(uid, xformQuery: tuple.xformQuery);
var otherTransform = tuple._physicsSystem.GetPhysicsTransform(uid);
// Get Grid2 AABB in grid1 ref
var aabb1 = tuple.grid.LocalAABB.Intersect(tuple.invWorldMatrix.TransformBox(otherGridBounds));
@@ -360,7 +360,7 @@ namespace Robust.Shared.Physics.Systems
}
return true;
}, includeMap: false);
}, approx: true, includeMap: false);
}
}

View File

@@ -628,7 +628,7 @@ public partial class SharedPhysicsSystem
#endregion
public Transform GetPhysicsTransform(EntityUid uid, TransformComponent? xform = null, EntityQuery<TransformComponent>? xformQuery = null)
public Transform GetPhysicsTransform(EntityUid uid, TransformComponent? xform = null)
{
if (!_xformQuery.Resolve(uid, ref xform))
return Physics.Transform.Empty;

View File

@@ -436,8 +436,8 @@ public abstract partial class SharedPhysicsSystem
// Special-case grid contacts.
if ((contact.Flags & ContactFlags.Grid) != 0x0)
{
var gridABounds = fixtureA.Shape.ComputeAABB(GetPhysicsTransform(uidA, xformA, _xformQuery), 0);
var gridBBounds = fixtureB.Shape.ComputeAABB(GetPhysicsTransform(uidB, xformB, _xformQuery), 0);
var gridABounds = fixtureA.Shape.ComputeAABB(GetPhysicsTransform(uidA, xformA), 0);
var gridBBounds = fixtureB.Shape.ComputeAABB(GetPhysicsTransform(uidB, xformB), 0);
if (!gridABounds.Intersects(gridBBounds))
{

View File

@@ -54,7 +54,6 @@ namespace Robust.Shared.Physics.Systems
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedDebugPhysicsSystem _debugPhysics = default!;
[Dependency] private readonly SharedGridTraversalSystem _traversal = default!;
[Dependency] private readonly SharedJointSystem _joints = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly CollisionWakeSystem _wakeSystem = default!;

View File

@@ -32,7 +32,7 @@ namespace Robust.Shared.Physics
// TODO: Probably replace this internally with just the Vector2 and radians but I'd need to re-learn trig so yeah....
public struct Transform
{
public static readonly Transform Empty = new Transform();
public static readonly Transform Empty = new Transform(0f);
public Vector2 Position;
public Quaternion2D Quaternion2D;

View File

@@ -350,6 +350,30 @@ public interface IPrototypeManager
/// Get the yaml data for a given prototype.
/// </summary>
IReadOnlyDictionary<string, MappingDataNode> GetPrototypeData(EntityPrototype prototype);
/// <summary>
/// Forces all prototypes in the given file to be abstract.
/// This makes them be read as abstract prototypes (mappings) instead of regular prototype instances.
/// Calling this method will not retroactively abstract prototypes that have already been read.
/// </summary>
/// <param name="path">
/// The file to force prototypes to be abstract in.
/// This must start from the Resources-level directory, but not include Resources itself.
/// For example: /Prototypes/Guidebook/antagonist.yml
/// </param>
void AbstractFile(ResPath path);
/// <summary>
/// Forces all prototypes in files recursively within this directory to be abstract.
/// This makes them be read as abstract prototypes (mappings) instead of regular prototype instances.
/// Calling this method will not retroactively abstract prototypes that have already been read.
/// </summary>
/// <param name="path">
/// The directory to force prototypes to be abstract in.
/// This must start from the Resources-level directory, but not include Resources itself.
/// For example: /Prototypes/Guidebook
/// </param>
void AbstractDirectory(ResPath path);
}
internal interface IPrototypeManagerInternal : IPrototypeManager

View File

@@ -14,6 +14,16 @@ namespace Robust.Shared.Prototypes;
public partial class PrototypeManager
{
/// <summary>
/// Which files to force all prototypes within to be abstract.
/// </summary>
private readonly List<ResPath> _abstractFiles = new();
/// <summary>
/// Which directories to force all prototypes recursively within to be abstract.
/// </summary>
private readonly List<ResPath> _abstractDirectories = new();
public event Action<DataNodeDocument>? LoadedData;
/// <inheritdoc />
@@ -35,6 +45,7 @@ public partial class PrototypeManager
{
try
{
var ignored = IsFileAbstract(file);
using var reader = ReadFile(file, !overwrite);
if (reader == null)
@@ -50,7 +61,12 @@ public partial class PrototypeManager
{
var data = ExtractMapping((MappingDataNode)mapping);
if (data != null)
{
if (ignored)
AbstractPrototype(data.Data);
extractedList.Add(data);
}
}
}
@@ -114,6 +130,7 @@ public partial class PrototypeManager
{
try
{
var ignored = IsFileAbstract(file);
using var reader = ReadFile(file, !overwrite);
if (reader == null)
@@ -133,6 +150,9 @@ public partial class PrototypeManager
if (extracted == null)
continue;
if (ignored)
AbstractPrototype(extracted.Data);
MergeMapping(extracted, overwrite, changed);
}
}
@@ -282,6 +302,57 @@ public partial class PrototypeManager
Freeze(modified);
}
public void AbstractFile(ResPath path)
{
_abstractFiles.Add(path);
}
public void AbstractDirectory(ResPath path)
{
_abstractDirectories.Add(path);
}
private bool IsFileAbstract(ResPath file)
{
if (_abstractFiles.Count > 0)
{
foreach (var abstractFile in _abstractFiles)
{
if (file.TryRelativeTo(abstractFile, out _))
return true;
}
}
if (_abstractDirectories.Count > 0)
{
foreach (var abstractDirectory in _abstractDirectories)
{
if (file.TryRelativeTo(abstractDirectory, out _))
return true;
}
}
return false;
}
private void AbstractPrototype(MappingDataNode mapping)
{
if (mapping.TryGet(AbstractDataFieldAttribute.Name, out var abstractNode))
{
if (abstractNode is not ValueDataNode abstractValueNode)
{
mapping.Remove(abstractNode);
mapping.Add("abstract", "true");
return;
}
abstractValueNode.Value = "true";
return;
}
mapping.Add("abstract", "true");
}
// All these fields can be null in case the
private sealed record ExtractedMappingData(
Type Kind,

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using Robust.Shared.Collections;
using Robust.Shared.Maths;
using Robust.Shared.Toolshed.Commands.Generic;
namespace Robust.Shared.Random;

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Robust.Shared.Collections;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
@@ -47,7 +48,7 @@ namespace Robust.Shared.Random
}
}
throw new InvalidOperationException("This should be unreachable!");
throw new UnreachableException("This should be unreachable!");
}
public static T PickAndTake<T>(this IRobustRandom random, IList<T> list)
@@ -58,6 +59,36 @@ namespace Robust.Shared.Random
return element;
}
/// <summary>
/// Picks a random element from a set and returns it.
/// This is O(n) as it has to iterate the collection until the target index.
/// </summary>
public static T Pick<T>(this System.Random random, ICollection<T> collection)
{
var index = random.Next(collection.Count);
var i = 0;
foreach (var t in collection)
{
if (i++ == index)
{
return t;
}
}
throw new UnreachableException("This should be unreachable!");
}
/// <summary>
/// Picks a random from a collection then removes it and returns it.
/// This is O(n) as it has to iterate the collection until the target index.
/// </summary>
public static T PickAndTake<T>(this System.Random random, ICollection<T> set)
{
var tile = Pick(random, set);
set.Remove(tile);
return tile;
}
/// <summary>
/// Generate a random number from a normal (gaussian) distribution.
/// </summary>

View File

@@ -4,30 +4,30 @@
<IsPackable>false</IsPackable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.2" />
<PackageReference Include="Microsoft.ILVerification" Version="6.0.0" PrivateAssets="compile" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageReference Include="Nett" Version="0.15.0" PrivateAssets="compile" />
<PackageReference Include="VorbisPizza" Version="1.3.0" PrivateAssets="compile" />
<PackageReference Include="Pidgin" Version="2.5.0" />
<PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="Robust.Shared.AuthLib" Version="0.1.2" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="YamlDotNet" Version="12.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" PrivateAssets="compile" />
<PackageReference Include="Linguini.Bundle" Version="0.1.3" />
<PackageReference Include="SharpZstd.Interop" Version="1.5.2-beta2" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" Version="0.2.1" PrivateAssets="compile" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.20348-rc2" PrivateAssets="compile" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" />
<PackageReference Include="Microsoft.ILVerification" PrivateAssets="compile" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
<PackageReference Include="Nett" PrivateAssets="compile" />
<PackageReference Include="VorbisPizza" PrivateAssets="compile" />
<PackageReference Include="Pidgin" />
<PackageReference Include="prometheus-net" />
<PackageReference Include="Robust.Shared.AuthLib" />
<PackageReference Include="Serilog" />
<PackageReference Include="YamlDotNet" />
<PackageReference Include="Microsoft.Win32.Registry" PrivateAssets="compile" />
<PackageReference Include="Linguini.Bundle" />
<PackageReference Include="SharpZstd.Interop" PrivateAssets="compile" />
<PackageReference Include="SpaceWizards.Sodium" PrivateAssets="compile" />
<PackageReference Include="SixLabors.ImageSharp" />
<PackageReference Include="TerraFX.Interop.Windows" PrivateAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\NetSerializer\NetSerializer\NetSerializer.csproj" />
<ProjectReference Include="..\Robust.Physics\Robust.Physics.csproj" />
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
</ItemGroup>
<ItemGroup>

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