mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 11:40:52 +01:00
Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ef4ac7452 | ||
|
|
93bf1b09e7 | ||
|
|
a1e557e870 | ||
|
|
864adb7445 | ||
|
|
9e3f3f0c1c | ||
|
|
a40c4a435c | ||
|
|
17182dd0e8 | ||
|
|
d8b50044a2 | ||
|
|
4dc396e73d | ||
|
|
6ae0b0e892 | ||
|
|
7162ca3456 | ||
|
|
1b44c1a1b8 | ||
|
|
5b80b33e00 | ||
|
|
f05c1b2395 | ||
|
|
d9b2c73440 | ||
|
|
29a39f8e0a | ||
|
|
2d72a2bdb5 | ||
|
|
91da635631 | ||
|
|
68ab3d504a | ||
|
|
5187040a64 | ||
|
|
e0c63e7ce6 | ||
|
|
0ba2272cab | ||
|
|
2183cd7ca1 | ||
|
|
cbf01f0aa5 | ||
|
|
6973d43006 | ||
|
|
c5a961d9a0 | ||
|
|
b4f7d71ee7 | ||
|
|
cd3684e575 | ||
|
|
317b8ce965 | ||
|
|
ff96140afa | ||
|
|
bade95f6b7 | ||
|
|
69daaca399 | ||
|
|
5af7e60043 | ||
|
|
ab823dcd12 | ||
|
|
b3976eb8d7 | ||
|
|
91759cdd3c | ||
|
|
b000c3178b | ||
|
|
63b3ecdd13 | ||
|
|
a183a98f75 | ||
|
|
bded7ad228 | ||
|
|
75c4f48496 | ||
|
|
49fe2d59cf | ||
|
|
8a5b7f5146 | ||
|
|
ae4f470e1f | ||
|
|
18fcab6f71 | ||
|
|
1ae6c32c62 | ||
|
|
cf6925f19b | ||
|
|
b4c7ffe38a | ||
|
|
d5c2f45f14 | ||
|
|
dcc88d2d36 | ||
|
|
a274b8dfc2 | ||
|
|
f42c1379e0 | ||
|
|
c4fa7e98d4 | ||
|
|
8b9dadffb1 | ||
|
|
5e99c6d04d | ||
|
|
606d232dbb | ||
|
|
df877582a6 | ||
|
|
8ffdb090e6 | ||
|
|
033d6ffb22 | ||
|
|
3eb6e067f9 | ||
|
|
1f64f93ef4 | ||
|
|
7dd617b0d6 | ||
|
|
0567b70704 | ||
|
|
9963e89c14 | ||
|
|
29e0faed88 | ||
|
|
0ce6ff9870 | ||
|
|
dbe9a96dfa | ||
|
|
fc5e3ab69d | ||
|
|
ed4974141c | ||
|
|
3e5efd5ed0 | ||
|
|
e1110eadb4 | ||
|
|
06ace83a73 | ||
|
|
cd01ca924b | ||
|
|
38ad8ce132 | ||
|
|
ee440c2df9 | ||
|
|
32f3c863fb | ||
|
|
b00e0bef5a | ||
|
|
0a09b27918 | ||
|
|
c9f6a4e32a | ||
|
|
b205a14f69 | ||
|
|
d5f3292e0a | ||
|
|
561e4b330e | ||
|
|
36a5d102ff | ||
|
|
b9c39e0953 | ||
|
|
ad4c8be132 | ||
|
|
988cbf9a87 | ||
|
|
e26512001a | ||
|
|
8e97982f1e | ||
|
|
3ca686298e | ||
|
|
5e914cb13a | ||
|
|
a1bdfca8ba | ||
|
|
79deaca409 | ||
|
|
2eeb21431b | ||
|
|
c4062bcae9 | ||
|
|
cd3a85ea04 | ||
|
|
d15b5c7f22 | ||
|
|
18bbe2271d | ||
|
|
ee2b7a3a66 | ||
|
|
ca36671131 | ||
|
|
604a1a6960 | ||
|
|
2898f5396f | ||
|
|
39541639c5 | ||
|
|
50981ad1a1 | ||
|
|
0cbfbeffae | ||
|
|
e603153016 | ||
|
|
e7c417ca0c | ||
|
|
a3989f28eb | ||
|
|
38ace3c348 | ||
|
|
0e00170f45 | ||
|
|
261ee96cad | ||
|
|
2c851885db | ||
|
|
849be86455 | ||
|
|
ffd5c120be | ||
|
|
76b15dda70 | ||
|
|
0bf7f519ad | ||
|
|
f97f325a36 | ||
|
|
24315fa787 | ||
|
|
792179657b | ||
|
|
9b92bcf911 | ||
|
|
86e34ea27b | ||
|
|
62cf778958 | ||
|
|
5d667e44c3 | ||
|
|
6d84b8741c | ||
|
|
d08ca59b75 | ||
|
|
f06b046c1c | ||
|
|
bb412a6906 | ||
|
|
1baee3004c | ||
|
|
f18068c13a | ||
|
|
0ba00a1845 | ||
|
|
28caf0d74c | ||
|
|
ecbb32b70b | ||
|
|
8e2a9cc597 | ||
|
|
a7eb8201c9 | ||
|
|
1f95fe6782 | ||
|
|
07c1f9e1af | ||
|
|
826dce6659 | ||
|
|
cdf714f3ba | ||
|
|
671ca7959c | ||
|
|
b7a1345d3a | ||
|
|
835b6ebdba | ||
|
|
0ecabd6553 | ||
|
|
feaa69f825 | ||
|
|
857904a3d9 | ||
|
|
0b37418477 | ||
|
|
f234ecb2c3 | ||
|
|
b449959865 | ||
|
|
8f870403d2 | ||
|
|
d94f702601 | ||
|
|
e78ab8f922 | ||
|
|
6972000293 | ||
|
|
58560f589f | ||
|
|
6e931ac175 | ||
|
|
a7eb5e8115 | ||
|
|
712e4acc66 | ||
|
|
fdcfdffc0b | ||
|
|
74eb8e3e8d | ||
|
|
ae4c764e4f | ||
|
|
7ef2cec121 | ||
|
|
40bff81017 | ||
|
|
f7c28992f8 |
20
.github/workflows/codeql-analysis.yml
vendored
20
.github/workflows/codeql-analysis.yml
vendored
@@ -11,14 +11,14 @@
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '30 18 * * 6'
|
||||
#on:
|
||||
# push:
|
||||
# branches: [ master ]
|
||||
# pull_request:
|
||||
# # The branches below must be a subset of the branches above
|
||||
# branches: [ master ]
|
||||
# schedule:
|
||||
# - cron: '30 18 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@@ -38,12 +38,12 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 5.0.100
|
||||
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -4,6 +4,12 @@
|
||||
[submodule "Lidgren.Network"]
|
||||
path = Lidgren.Network/Lidgren.Network
|
||||
url = https://github.com/space-wizards/lidgren-network-gen3.git
|
||||
[submodule "XamlX"]
|
||||
path = XamlX
|
||||
url = https://github.com/space-wizards/XamlX
|
||||
[submodule "Robust.LoaderApi"]
|
||||
path = Robust.LoaderApi
|
||||
url = https://github.com/space-wizards/Robust.LoaderApi.git
|
||||
[submodule "ManagedHttpListener"]
|
||||
path = ManagedHttpListener
|
||||
url = https://github.com/space-wizards/ManagedHttpListener.git
|
||||
|
||||
Submodule Lidgren.Network/Lidgren.Network updated: 4a5cedacb2...73554e6061
5
MSBuild/Robust.Analyzers.targets
Normal file
5
MSBuild/Robust.Analyzers.targets
Normal file
@@ -0,0 +1,5 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Analyzers\Robust.Analyzers.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,2 +1,3 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<Import Project="Robust.Analyzers.targets" />
|
||||
</Project>
|
||||
|
||||
65
MSBuild/XamlIL.targets
Normal file
65
MSBuild/XamlIL.targets
Normal file
@@ -0,0 +1,65 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<PropertyGroup>
|
||||
<!-- Avoid MSBuild adding a None entry for XAML files because they'd show up TWICE in the project view. -->
|
||||
<DefaultItemExcludes>**/*.xaml</DefaultItemExcludes>
|
||||
<RobustUseExternalMSBuild>true</RobustUseExternalMSBuild>
|
||||
<_RobustUseExternalMSBuild>$(RobustUseExternalMSBuild)</_RobustUseExternalMSBuild>
|
||||
<_RobustUseExternalMSBuild Condition="'$(_RobustForceInternalMSBuild)' == 'true'">false</_RobustUseExternalMSBuild>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="**\*.xaml.cs">
|
||||
<DependentUpon>%(Filename)</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="**\*.xaml"/>
|
||||
<AdditionalFiles Include="**\*.xaml"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.NameGenerator\Robust.Client.NameGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\Robust.Client.Injectors.csproj" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
|
||||
<UsingTask
|
||||
Condition="'$(_RobustUseExternalMSBuild)' != 'true' And $(DesignTimeBuild) != true"
|
||||
TaskName="CompileRobustXamlTask"
|
||||
AssemblyFile="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\bin\$(Configuration)\netstandard2.0\Robust.Client.Injectors.dll"/>
|
||||
<Target
|
||||
Name="CompileRobustXaml"
|
||||
Condition="Exists('@(IntermediateAssembly)')"
|
||||
AfterTargets="AfterCompile"
|
||||
Inputs="@(IntermediateAssembly);@(ReferencePathWithRefAssemblies)"
|
||||
Outputs="$(IntermediateOutputPath)XAML/doot">
|
||||
<PropertyGroup>
|
||||
<RobustXamlReferencesTemporaryFilePath Condition="'$(RobustXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)XAML/references</RobustXamlReferencesTemporaryFilePath>
|
||||
<RobustXamlOriginalCopyFilePath Condition="'$(RobustXamlOriginalCopyFilePath)' == ''">$(IntermediateOutputPath)XAML/original.dll</RobustXamlOriginalCopyFilePath>
|
||||
</PropertyGroup>
|
||||
<WriteLinesToFile
|
||||
Condition="'$(_RobustForceInternalMSBuild)' != 'true'"
|
||||
File="$(RobustXamlReferencesTemporaryFilePath)"
|
||||
Lines="@(ReferencePathWithRefAssemblies)"
|
||||
Overwrite="true"/>
|
||||
|
||||
<!--
|
||||
UpdateBuildIndicator is done so that we can use MSBuild Inputs and Outputs on the target
|
||||
to avoid unecessary execution of this target
|
||||
Saves compile time if e.g. ONLY Robust.Client changes (Content.Client doesn't have to re-xaml).
|
||||
-->
|
||||
<CompileRobustXamlTask
|
||||
Condition="'$(_RobustUseExternalMSBuild)' != 'true'"
|
||||
AssemblyFile="@(IntermediateAssembly)"
|
||||
ReferencesFilePath="$(RobustXamlReferencesTemporaryFilePath)"
|
||||
OriginalCopyPath="$(RobustXamlOriginalCopyFilePath)"
|
||||
ProjectDirectory="$(MSBuildProjectDirectory)"
|
||||
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
|
||||
SignAssembly="$(SignAssembly)"
|
||||
DelaySign="$(DelaySign)"
|
||||
UpdateBuildIndicator="$(IntermediateOutputPath)XAML/doot"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
|
||||
</PropertyGroup>
|
||||
<Exec
|
||||
Condition="'$(_RobustUseExternalMSBuild)' == 'true'"
|
||||
Command=""$(DOTNET_HOST_PATH)" msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileRobustXaml /p:_RobustForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
|
||||
</Target>
|
||||
</Project>
|
||||
1
ManagedHttpListener
Submodule
1
ManagedHttpListener
Submodule
Submodule ManagedHttpListener added at f2aa590fec
Submodule NetSerializer updated: 60d23c01f9...1e103e8e29
@@ -17,6 +17,7 @@ namespace OpenToolkit.GraphicsLibraryFramework
|
||||
// On net472, we rely on Mono's DllMap for this. See the .dll.config file.
|
||||
NativeLibrary.SetDllImportResolver(typeof(GLFWNative).Assembly, (name, assembly, path) =>
|
||||
{
|
||||
// Please keep in sync with what Robust.Shared/DllMapHelper.cs does.
|
||||
if (name != "glfw3.dll")
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
|
||||
@@ -13,7 +13,7 @@ highp float createOcclusion(highp vec2 diff)
|
||||
// Change soft shadow size based on distance from primary occluder.
|
||||
highp float distRatio = (ourDist - occlDist.x) / occlDist.x / 2.0;
|
||||
|
||||
perpendicular *= distRatio;
|
||||
perpendicular *= distRatio * lightSoftness;
|
||||
|
||||
// Totally not hacky PCF on top of VSM.
|
||||
highp float occlusion = smoothstep(0.1, 1.0, ChebyshevUpperBound(occlDist, ourDist));
|
||||
|
||||
@@ -13,6 +13,7 @@ uniform highp vec4 lightColor;
|
||||
uniform highp vec2 lightCenter;
|
||||
uniform highp float lightRange;
|
||||
uniform highp float lightPower;
|
||||
uniform highp float lightSoftness;
|
||||
uniform highp float lightIndex;
|
||||
uniform sampler2D shadowMap;
|
||||
|
||||
|
||||
92
Robust.Analyzers/ExplicitInterfaceAnalyzer.cs
Normal file
92
Robust.Analyzers/ExplicitInterfaceAnalyzer.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Document = Microsoft.CodeAnalysis.Document;
|
||||
|
||||
namespace Robust.Analyzers
|
||||
{
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public class ExplicitInterfaceAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
public readonly SyntaxKind[] ExcludedModifiers =
|
||||
{
|
||||
SyntaxKind.VirtualKeyword,
|
||||
SyntaxKind.AbstractKeyword,
|
||||
SyntaxKind.OverrideKeyword
|
||||
};
|
||||
|
||||
public const string DiagnosticId = "RA0000";
|
||||
|
||||
private const string Title = "No explicit interface specified";
|
||||
private const string MessageFormat = "No explicit interface specified";
|
||||
private const string Description = "Make sure to specify the interface in your method-declaration.";
|
||||
private const string Category = "Usage";
|
||||
|
||||
[SuppressMessage("ReSharper", "RS2008")] private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
|
||||
|
||||
private const string RequiresExplicitImplementationAttributeMetadataName =
|
||||
"Robust.Shared.Analyzers.RequiresExplicitImplementationAttribute";
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.PropertyDeclaration);
|
||||
}
|
||||
|
||||
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
ISymbol symbol;
|
||||
Location location;
|
||||
switch (context.Node)
|
||||
{
|
||||
//we already have a explicit interface specified, no need to check further
|
||||
case MethodDeclarationSyntax methodDecl when methodDecl.ExplicitInterfaceSpecifier != null || methodDecl.Modifiers.Any(m => ExcludedModifiers.Contains(m.Kind())):
|
||||
return;
|
||||
case PropertyDeclarationSyntax propertyDecl when propertyDecl.ExplicitInterfaceSpecifier != null || propertyDecl.Modifiers.Any(m => ExcludedModifiers.Contains(m.Kind())):
|
||||
return;
|
||||
|
||||
case MethodDeclarationSyntax methodDecl:
|
||||
symbol = context.SemanticModel.GetDeclaredSymbol(methodDecl);
|
||||
location = methodDecl.Identifier.GetLocation();
|
||||
break;
|
||||
case PropertyDeclarationSyntax propertyDecl:
|
||||
symbol = context.SemanticModel.GetDeclaredSymbol(propertyDecl);
|
||||
location = propertyDecl.Identifier.GetLocation();
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
var attrSymbol = context.Compilation.GetTypeByMetadataName(RequiresExplicitImplementationAttributeMetadataName);
|
||||
|
||||
var isInterfaceMember = symbol?.ContainingType.AllInterfaces.Any(
|
||||
i =>
|
||||
i.GetMembers().Any(m => SymbolEqualityComparer.Default.Equals(symbol, symbol.ContainingType.FindImplementationForInterfaceMember(m)))
|
||||
&& i.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol))
|
||||
) ?? false;
|
||||
|
||||
if (isInterfaceMember)
|
||||
{
|
||||
//we do not have an explicit interface specified. bad!
|
||||
var diagnostic = Diagnostic.Create(
|
||||
Rule,
|
||||
location);
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Robust.Analyzers/Robust.Analyzers.csproj
Normal file
13
Robust.Analyzers/Robust.Analyzers.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="3.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
150
Robust.Analyzers/SerializableAnalyzer.cs
Normal file
150
Robust.Analyzers/SerializableAnalyzer.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers
|
||||
{
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public class SerializableAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
// Metadata of the analyzer
|
||||
public const string DiagnosticId = "RA0001";
|
||||
|
||||
// You could use LocalizedString but it's a little more complicated for this sample
|
||||
private const string Title = "Class not marked as (Net)Serializable";
|
||||
private const string MessageFormat = "Class not marked as (Net)Serializable";
|
||||
private const string Description = "The class should be marked as (Net)Serializable.";
|
||||
private const string Category = "Usage";
|
||||
|
||||
private const string RequiresSerializableAttributeMetadataName = "Robust.Shared.Analyzers.RequiresSerializableAttribute";
|
||||
private const string SerializableAttributeMetadataName = "System.SerializableAttribute";
|
||||
private const string NetSerializableAttributeMetadataName = "Robust.Shared.Serialization.NetSerializableAttribute";
|
||||
|
||||
[SuppressMessage("ReSharper", "RS2008")] private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
|
||||
}
|
||||
|
||||
private bool Marked(INamedTypeSymbol namedTypeSymbol, INamedTypeSymbol attrSymbol)
|
||||
{
|
||||
if (namedTypeSymbol == null) return false;
|
||||
if (namedTypeSymbol.GetAttributes()
|
||||
.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol))) return true;
|
||||
return Marked(namedTypeSymbol.BaseType, attrSymbol);
|
||||
}
|
||||
|
||||
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var attrSymbol = context.Compilation.GetTypeByMetadataName(RequiresSerializableAttributeMetadataName);
|
||||
var classDecl = (ClassDeclarationSyntax) context.Node;
|
||||
var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDecl);
|
||||
if (classSymbol == null) return;
|
||||
|
||||
if (Marked(classSymbol, attrSymbol))
|
||||
{
|
||||
var attributes = classSymbol.GetAttributes();
|
||||
var serAttr = context.Compilation.GetTypeByMetadataName(SerializableAttributeMetadataName);
|
||||
var netSerAttr = context.Compilation.GetTypeByMetadataName(NetSerializableAttributeMetadataName);
|
||||
|
||||
var hasSerAttr = attributes.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, serAttr));
|
||||
var hasNetSerAttr =
|
||||
attributes.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, netSerAttr));
|
||||
|
||||
if (!hasSerAttr || !hasNetSerAttr)
|
||||
{
|
||||
var requiredAttributes = new List<string>();
|
||||
if(!hasSerAttr) requiredAttributes.Add(SerializableAttributeMetadataName);
|
||||
if(!hasNetSerAttr) requiredAttributes.Add(NetSerializableAttributeMetadataName);
|
||||
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
Rule,
|
||||
classDecl.Identifier.GetLocation(),
|
||||
ImmutableDictionary.CreateRange(new Dictionary<string, string>()
|
||||
{
|
||||
{
|
||||
"requiredAttributes", string.Join(",", requiredAttributes)
|
||||
}
|
||||
})));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ExportCodeFixProvider(LanguageNames.CSharp)]
|
||||
public class SerializableCodeFixProvider : CodeFixProvider
|
||||
{
|
||||
private const string Title = "Annotate class as (Net)Serializable.";
|
||||
|
||||
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
|
||||
foreach (var diagnostic in context.Diagnostics)
|
||||
{
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var classDecl = root.FindToken(span.Start).Parent.AncestorsAndSelf().OfType<ClassDeclarationSyntax>().First();
|
||||
|
||||
if(!diagnostic.Properties.TryGetValue("requiredAttributes", out var requiredAttributes)) return;
|
||||
|
||||
context.RegisterCodeFix(
|
||||
CodeAction.Create(
|
||||
Title,
|
||||
c => FixAsync(context.Document, classDecl, requiredAttributes, c),
|
||||
Title),
|
||||
diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Document> FixAsync(Document document, ClassDeclarationSyntax classDecl,
|
||||
string requiredAttributes, CancellationToken cancellationToken)
|
||||
{
|
||||
var attributes = new List<AttributeSyntax>();
|
||||
var namespaces = new List<string>();
|
||||
foreach (var attribute in requiredAttributes.Split(','))
|
||||
{
|
||||
var tempSplit = attribute.Split('.');
|
||||
namespaces.Add(string.Join(".",tempSplit.Take(tempSplit.Length-1)));
|
||||
var @class = tempSplit.Last();
|
||||
@class = @class.Substring(0, @class.Length - 9); //cut out "Attribute" at the end
|
||||
attributes.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName(@class)));
|
||||
}
|
||||
|
||||
var newClassDecl =
|
||||
classDecl.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributes)));
|
||||
|
||||
var root = (CompilationUnitSyntax) await document.GetSyntaxRootAsync(cancellationToken);
|
||||
root = root.ReplaceNode(classDecl, newClassDecl);
|
||||
|
||||
foreach (var ns in namespaces)
|
||||
{
|
||||
if(root.Usings.Any(u => u.Name.ToString() == ns)) continue;
|
||||
root = root.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(ns)));
|
||||
}
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
|
||||
public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(SerializableAnalyzer.DiagnosticId);
|
||||
|
||||
public override FixAllProvider GetFixAllProvider()
|
||||
{
|
||||
return WellKnownFixAllProviders.BatchFixer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
101
Robust.Client.Injectors/CompileRobustXamlTask.cs
Normal file
101
Robust.Client.Injectors/CompileRobustXamlTask.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
|
||||
/// </summary>
|
||||
public class CompileRobustXamlTask : ITask
|
||||
{
|
||||
public bool Execute()
|
||||
{
|
||||
//Debugger.Launch();
|
||||
OutputPath = OutputPath ?? AssemblyFile;
|
||||
var outputPdb = GetPdbPath(OutputPath);
|
||||
var input = AssemblyFile;
|
||||
var inputPdb = GetPdbPath(input);
|
||||
// Make a copy and delete the original file to prevent MSBuild from thinking that everything is OK
|
||||
if (OriginalCopyPath != null)
|
||||
{
|
||||
File.Copy(AssemblyFile, OriginalCopyPath, true);
|
||||
input = OriginalCopyPath;
|
||||
File.Delete(AssemblyFile);
|
||||
|
||||
if (File.Exists(inputPdb))
|
||||
{
|
||||
var copyPdb = GetPdbPath(OriginalCopyPath);
|
||||
File.Copy(inputPdb, copyPdb, true);
|
||||
File.Delete(inputPdb);
|
||||
inputPdb = copyPdb;
|
||||
}
|
||||
}
|
||||
|
||||
var msg = $"CompileRobustXamlTask -> AssemblyFile:{AssemblyFile}, ProjectDirectory:{ProjectDirectory}, OutputPath:{OutputPath}";
|
||||
BuildEngine.LogMessage(msg, MessageImportance.High);
|
||||
|
||||
var res = XamlCompiler.Compile(BuildEngine, input,
|
||||
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
|
||||
ProjectDirectory, OutputPath,
|
||||
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null);
|
||||
if (!res.success)
|
||||
return false;
|
||||
if (!res.writtentofile)
|
||||
{
|
||||
File.Copy(input, OutputPath, true);
|
||||
if(File.Exists(inputPdb))
|
||||
File.Copy(inputPdb, outputPdb, true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(UpdateBuildIndicator))
|
||||
{
|
||||
if (!File.Exists(UpdateBuildIndicator))
|
||||
{
|
||||
File.Create(UpdateBuildIndicator).Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(UpdateBuildIndicator, DateTime.Now);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Required]
|
||||
public string ReferencesFilePath { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ProjectDirectory { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AssemblyFile { get; set; }
|
||||
|
||||
[Required]
|
||||
public string OriginalCopyPath { get; set; }
|
||||
|
||||
public string OutputPath { get; set; }
|
||||
public string UpdateBuildIndicator { get; set; }
|
||||
|
||||
public string AssemblyOriginatorKeyFile { get; set; }
|
||||
public bool SignAssembly { get; set; }
|
||||
public bool DelaySign { get; set; }
|
||||
|
||||
// shamelessly copied from avalonia
|
||||
string GetPdbPath(string p)
|
||||
{
|
||||
var d = Path.GetDirectoryName(p);
|
||||
var f = Path.GetFileNameWithoutExtension(p);
|
||||
var rv = f + ".pdb";
|
||||
if (d != null)
|
||||
rv = Path.Combine(d, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public IBuildEngine BuildEngine { get; set; }
|
||||
public ITaskHost HostObject { get; set; }
|
||||
}
|
||||
}
|
||||
16
Robust.Client.Injectors/Extensions.cs
Normal file
16
Robust.Client.Injectors/Extensions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Taken from https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/Extensions.cs
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
//shamefully copied from avalonia
|
||||
public static void LogMessage(this IBuildEngine engine, string message, MessageImportance imp)
|
||||
{
|
||||
engine.LogMessageEvent(new BuildMessageEventArgs(message, "", "Avalonia", imp));
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Robust.Client.Injectors/MathParsing.cs
Normal file
37
Robust.Client.Injectors/MathParsing.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Linq;
|
||||
using Pidgin;
|
||||
using static Pidgin.Parser;
|
||||
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
public static class MathParsing
|
||||
{
|
||||
public static Parser<char, float> Single { get; } = Real.Select(c => (float) c);
|
||||
|
||||
public static Parser<char, float> Single1 { get; }
|
||||
= Single.Between(SkipWhitespaces);
|
||||
|
||||
public static Parser<char, (float, float)> Single2 { get; }
|
||||
= Single.Before(SkipWhitespaces).Repeat(2).Select(e =>
|
||||
{
|
||||
var arr = e.ToArray();
|
||||
return (arr[0], arr[1]);
|
||||
});
|
||||
|
||||
public static Parser<char, (float, float, float, float)> Single4 { get; }
|
||||
= Single.Before(SkipWhitespaces).Repeat(4).Select(e =>
|
||||
{
|
||||
var arr = e.ToArray();
|
||||
return (arr[0], arr[1], arr[2], arr[3]);
|
||||
});
|
||||
|
||||
public static Parser<char, float[]> Thickness { get; }
|
||||
= SkipWhitespaces.Then(
|
||||
OneOf(
|
||||
Try(Single1.Select(c => new[] {c})),
|
||||
Try(Single2.Select(c => new[] {c.Item1, c.Item2})),
|
||||
Try(Single4.Select(c => new[] {c.Item1, c.Item2, c.Item3, c.Item4}))
|
||||
));
|
||||
}
|
||||
}
|
||||
62
Robust.Client.Injectors/Program.cs
Normal file
62
Robust.Client.Injectors/Program.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/Program.cs
|
||||
/// </summary>
|
||||
class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
if (args.Length != 3)
|
||||
{
|
||||
Console.Error.WriteLine("expected: input references output");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return new CompileRobustXamlTask
|
||||
{
|
||||
AssemblyFile = args[0],
|
||||
ReferencesFilePath = args[1],
|
||||
OutputPath = args[2],
|
||||
BuildEngine = new ConsoleBuildEngine(),
|
||||
ProjectDirectory = Directory.GetCurrentDirectory()
|
||||
}.Execute() ? 0 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
class ConsoleBuildEngine : IBuildEngine
|
||||
{
|
||||
public void LogErrorEvent(BuildErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"ERROR: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
}
|
||||
|
||||
public void LogWarningEvent(BuildWarningEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"WARNING: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
}
|
||||
|
||||
public void LogMessageEvent(BuildMessageEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"MESSAGE: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
}
|
||||
|
||||
public void LogCustomEvent(CustomBuildEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"CUSTOM: {e.Message}");
|
||||
}
|
||||
|
||||
public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties,
|
||||
IDictionary targetOutputs) => throw new NotSupportedException();
|
||||
|
||||
public bool ContinueOnError { get; }
|
||||
public int LineNumberOfTaskNode { get; }
|
||||
public int ColumnNumberOfTaskNode { get; }
|
||||
public string ProjectFileOfTaskNode { get; }
|
||||
}
|
||||
}
|
||||
93
Robust.Client.Injectors/RXamlVecLikeConstAstNode.cs
Normal file
93
Robust.Client.Injectors/RXamlVecLikeConstAstNode.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using XamlX.Ast;
|
||||
using XamlX.Emit;
|
||||
using XamlX.IL;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
public abstract class RXamlVecLikeConstAstNode<T>
|
||||
: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
|
||||
where T : unmanaged
|
||||
{
|
||||
private readonly IXamlConstructor _constructor;
|
||||
protected readonly T[] Values;
|
||||
|
||||
public RXamlVecLikeConstAstNode(
|
||||
IXamlLineInfo lineInfo,
|
||||
IXamlType type, IXamlConstructor constructor,
|
||||
IXamlType componentType, T[] values)
|
||||
: base(lineInfo)
|
||||
{
|
||||
_constructor = constructor;
|
||||
Values = values;
|
||||
|
||||
var @params = constructor.Parameters;
|
||||
|
||||
if (@params.Count != values.Length)
|
||||
throw new ArgumentException("Invalid amount of parameters");
|
||||
|
||||
if (@params.Any(c => c != componentType))
|
||||
throw new ArgumentException("Invalid constructor: not all parameters match component type");
|
||||
|
||||
Type = new XamlAstClrTypeReference(lineInfo, type, false);
|
||||
}
|
||||
|
||||
public IXamlAstTypeReference Type { get; }
|
||||
|
||||
public virtual XamlILNodeEmitResult Emit(
|
||||
XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
|
||||
IXamlILEmitter codeGen)
|
||||
{
|
||||
codeGen.Newobj(_constructor);
|
||||
|
||||
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RXamlSingleVecLikeConstAstNode : RXamlVecLikeConstAstNode<float>
|
||||
{
|
||||
public RXamlSingleVecLikeConstAstNode(
|
||||
IXamlLineInfo lineInfo,
|
||||
IXamlType type, IXamlConstructor constructor,
|
||||
IXamlType componentType, float[] values)
|
||||
: base(lineInfo, type, constructor, componentType, values)
|
||||
{
|
||||
}
|
||||
|
||||
public override XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
|
||||
IXamlILEmitter codeGen)
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
codeGen.Emit(OpCodes.Ldc_R4, value);
|
||||
}
|
||||
|
||||
return base.Emit(context, codeGen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RXamlInt32VecLikeConstAstNode : RXamlVecLikeConstAstNode<int>
|
||||
{
|
||||
public RXamlInt32VecLikeConstAstNode(
|
||||
IXamlLineInfo lineInfo,
|
||||
IXamlType type, IXamlConstructor constructor,
|
||||
IXamlType componentType, int[] values)
|
||||
: base(lineInfo, type, constructor, componentType, values)
|
||||
{
|
||||
}
|
||||
|
||||
public override XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
|
||||
IXamlILEmitter codeGen)
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
codeGen.Emit(OpCodes.Ldc_I4, value);
|
||||
}
|
||||
|
||||
return base.Emit(context, codeGen);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Robust.Client.Injectors/RXamlWellKnownTypes.cs
Normal file
47
Robust.Client.Injectors/RXamlWellKnownTypes.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Linq;
|
||||
using XamlX.Transform;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
class RXamlWellKnownTypes
|
||||
{
|
||||
public XamlTypeWellKnownTypes XamlIlTypes { get; }
|
||||
public IXamlType Single { get; }
|
||||
public IXamlType Int32 { get; }
|
||||
public IXamlType Vector2 { get; }
|
||||
public IXamlConstructor Vector2ConstructorFull { get; }
|
||||
public IXamlType Vector2i { get; }
|
||||
public IXamlConstructor Vector2iConstructorFull { get; }
|
||||
|
||||
public RXamlWellKnownTypes(TransformerConfiguration cfg)
|
||||
{
|
||||
var ts = cfg.TypeSystem;
|
||||
XamlIlTypes = cfg.WellKnownTypes;
|
||||
Single = ts.GetType("System.Single");
|
||||
Int32 = ts.GetType("System.Int32");
|
||||
|
||||
(Vector2, Vector2ConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2", Single, 2);
|
||||
(Vector2i, Vector2iConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2i", Int32, 2);
|
||||
|
||||
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
|
||||
{
|
||||
var type = cfg.TypeSystem.GetType(name);
|
||||
var ctor = type.GetConstructor(Enumerable.Repeat(componentType, componentCount).ToList());
|
||||
|
||||
return (type, ctor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class RXamlWellKnownTypesExtensions
|
||||
{
|
||||
public static RXamlWellKnownTypes GetRobustTypes(this AstTransformationContext ctx)
|
||||
{
|
||||
if (ctx.TryGetItem<RXamlWellKnownTypes>(out var rv))
|
||||
return rv;
|
||||
ctx.SetItem(rv = new RXamlWellKnownTypes(ctx.Configuration));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Robust.Client.Injectors/Robust.Client.Injectors.csproj
Normal file
17
Robust.Client.Injectors/Robust.Client.Injectors.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Framework" Version="16.8.0" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="Pidgin" Version="2.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\XamlX\src\XamlX.IL.Cecil\XamlX.IL.Cecil.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
201
Robust.Client.Injectors/RobustXamlILCompiler.cs
Normal file
201
Robust.Client.Injectors/RobustXamlILCompiler.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using System.Linq;
|
||||
using XamlX.Ast;
|
||||
using XamlX.Emit;
|
||||
using XamlX.IL;
|
||||
using XamlX.Transform;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Emitters & Transformers based on:
|
||||
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs
|
||||
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
|
||||
/// </summary>
|
||||
public class RobustXamlILCompiler : XamlILCompiler
|
||||
{
|
||||
public RobustXamlILCompiler(TransformerConfiguration configuration, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emitMappings, bool fillWithDefaults) : base(configuration, emitMappings, fillWithDefaults)
|
||||
{
|
||||
Transformers.Add(new AddNameScopeRegistration());
|
||||
Transformers.Add(new RobustMarkRootObjectScopeNode());
|
||||
|
||||
Emitters.Add(new AddNameScopeRegistration.Emitter());
|
||||
Emitters.Add(new RobustMarkRootObjectScopeNode.Emitter());
|
||||
}
|
||||
|
||||
class AddNameScopeRegistration : IXamlAstTransformer
|
||||
{
|
||||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
|
||||
{
|
||||
if (node is XamlPropertyAssignmentNode pa)
|
||||
{
|
||||
if (pa.Property.Name == "Name"
|
||||
&& pa.Property.DeclaringType.FullName == "Robust.Client.UserInterface.Control")
|
||||
{
|
||||
if (context.ParentNodes().FirstOrDefault() is XamlManipulationGroupNode mg
|
||||
&& mg.Children.OfType<RobustNameScopeRegistrationXamlIlNode>().Any())
|
||||
return node;
|
||||
|
||||
IXamlAstValueNode value = null;
|
||||
for (var c = 0; c < pa.Values.Count; c++)
|
||||
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
|
||||
{
|
||||
value = pa.Values[c];
|
||||
if (!(value is XamlAstTextNode))
|
||||
{
|
||||
var local = new XamlAstCompilerLocalNode(value);
|
||||
// Wrap original in local initialization
|
||||
pa.Values[c] = new XamlAstLocalInitializationNodeEmitter(value, value, local);
|
||||
// Use local
|
||||
value = local;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
var objectType = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault()?.Type.GetClrType();
|
||||
return new XamlManipulationGroupNode(pa)
|
||||
{
|
||||
Children =
|
||||
{
|
||||
pa,
|
||||
new RobustNameScopeRegistrationXamlIlNode(value, objectType)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
/*else if (pa.Property.CustomAttributes.Select(attr => attr.Type).Intersect(context.Configuration.TypeMappings.DeferredContentPropertyAttributes).Any())
|
||||
{
|
||||
pa.Values[pa.Values.Count - 1] =
|
||||
new NestedScopeMetadataNode(pa.Values[pa.Values.Count - 1]);
|
||||
}*/
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
class RobustNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode
|
||||
{
|
||||
public IXamlAstValueNode Name { get; set; }
|
||||
public IXamlType TargetType { get; }
|
||||
|
||||
public RobustNameScopeRegistrationXamlIlNode(IXamlAstValueNode name, IXamlType targetType) : base(name)
|
||||
{
|
||||
TargetType = targetType;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override void VisitChildren(IXamlAstVisitor visitor)
|
||||
=> Name = (IXamlAstValueNode)Name.Visit(visitor);
|
||||
}
|
||||
|
||||
internal class Emitter : IXamlAstLocalsNodeEmitter<IXamlILEmitter, XamlILNodeEmitResult>
|
||||
{
|
||||
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
|
||||
{
|
||||
if (node is RobustNameScopeRegistrationXamlIlNode registration)
|
||||
{
|
||||
|
||||
var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
|
||||
f.Name == XamlCompiler.ContextNameScopeFieldName);
|
||||
var namescopeRegisterFunction = context.Configuration.TypeSystem
|
||||
.FindType("Robust.Client.UserInterface.XAML.NameScope").Methods
|
||||
.First(m => m.Name == "Register");
|
||||
|
||||
using (var targetLoc = context.GetLocalOfType(context.Configuration.TypeSystem.FindType("Robust.Client.UserInterface.Control")))
|
||||
{
|
||||
|
||||
codeGen
|
||||
// var target = {pop}
|
||||
.Stloc(targetLoc.Local)
|
||||
// _context.NameScope.Register(Name, target)
|
||||
.Ldloc(context.ContextLocal)
|
||||
.Ldfld(scopeField);
|
||||
|
||||
context.Emit(registration.Name, codeGen, registration.Name.Type.GetClrType());
|
||||
|
||||
codeGen
|
||||
.Ldloc(targetLoc.Local)
|
||||
.EmitCall(namescopeRegisterFunction, true);
|
||||
}
|
||||
|
||||
return XamlILNodeEmitResult.Void(1);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RobustMarkRootObjectScopeNode : IXamlAstTransformer
|
||||
{
|
||||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
|
||||
{
|
||||
if (!context.ParentNodes().Any()
|
||||
&& node is XamlValueWithManipulationNode mnode)
|
||||
{
|
||||
mnode.Manipulation = new XamlManipulationGroupNode(mnode,
|
||||
new[]
|
||||
{
|
||||
mnode.Manipulation,
|
||||
new HandleRootObjectScopeNode(mnode)
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
class HandleRootObjectScopeNode : XamlAstNode, IXamlAstManipulationNode
|
||||
{
|
||||
public HandleRootObjectScopeNode(IXamlLineInfo lineInfo) : base(lineInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
internal class Emitter : IXamlILAstNodeEmitter
|
||||
{
|
||||
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
|
||||
{
|
||||
if (!(node is HandleRootObjectScopeNode))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var controlType = context.Configuration.TypeSystem.FindType("Robust.Client.UserInterface.Control");
|
||||
|
||||
var next = codeGen.DefineLabel();
|
||||
var dontAbsorb = codeGen.DefineLabel();
|
||||
var end = codeGen.DefineLabel();
|
||||
var contextScopeField = context.RuntimeContext.ContextType.Fields.First(f =>
|
||||
f.Name == XamlCompiler.ContextNameScopeFieldName);
|
||||
var controlNameScopeField = controlType.Fields.First(f => f.Name == "NameScope");
|
||||
var nameScopeType = context.Configuration.TypeSystem
|
||||
.FindType("Robust.Client.UserInterface.XAML.NameScope");
|
||||
var nameScopeCompleteMethod = nameScopeType.Methods.First(m => m.Name == "Complete");
|
||||
var nameScopeAbsorbMethod = nameScopeType.Methods.First(m => m.Name == "Absorb");
|
||||
using (var local = codeGen.LocalsPool.GetLocal(controlType))
|
||||
{
|
||||
codeGen
|
||||
.Isinst(controlType)
|
||||
.Dup()
|
||||
.Stloc(local.Local) //store control in local field
|
||||
.Brfalse(next) //if control is null, move to next (this should never happen but whatev, avalonia does it)
|
||||
.Ldloc(context.ContextLocal)
|
||||
.Ldfld(contextScopeField)
|
||||
.Ldloc(local.Local) //load control from local field
|
||||
.Ldfld(controlNameScopeField) //load namescope field from control
|
||||
.EmitCall(nameScopeAbsorbMethod, true)
|
||||
.Ldloc(local.Local) //load control
|
||||
.Ldloc(context.ContextLocal) //load contextObject
|
||||
.Ldfld(contextScopeField) //load namescope field from context obj
|
||||
.Stfld(controlNameScopeField) //store namescope field in control
|
||||
.MarkLabel(next)
|
||||
.Ldloc(context.ContextLocal)
|
||||
.Ldfld(contextScopeField)
|
||||
.EmitCall(nameScopeCompleteMethod, true); //set the namescope as complete
|
||||
}
|
||||
|
||||
return XamlILNodeEmitResult.Void(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Robust.Client.Injectors/XamlCompiler.Helpers.cs
Normal file
78
Robust.Client.Injectors/XamlCompiler.Helpers.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Collections.Generic;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpers taken from:
|
||||
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
|
||||
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
|
||||
/// </summary>
|
||||
public partial class XamlCompiler
|
||||
{
|
||||
static bool CheckXamlName(IResource r) => r.Name.ToLowerInvariant().EndsWith(".xaml")
|
||||
|| r.Name.ToLowerInvariant().EndsWith(".paml")
|
||||
|| r.Name.ToLowerInvariant().EndsWith(".axaml");
|
||||
|
||||
private static bool MatchThisCall(Collection<Instruction> instructions, int idx)
|
||||
{
|
||||
var i = instructions[idx];
|
||||
// A "normal" way of passing `this` to a static method:
|
||||
|
||||
// ldarg.0
|
||||
// call void [Avalonia.Markup.Xaml]Avalonia.Markup.Xaml.AvaloniaXamlLoader::Load(object)
|
||||
|
||||
return i.OpCode == OpCodes.Ldarg_0 || (i.OpCode == OpCodes.Ldarg && i.Operand?.Equals(0) == true);
|
||||
}
|
||||
|
||||
interface IResource : IFileSource
|
||||
{
|
||||
string Uri { get; }
|
||||
string Name { get; }
|
||||
void Remove();
|
||||
|
||||
}
|
||||
|
||||
interface IResourceGroup
|
||||
{
|
||||
string Name { get; }
|
||||
IEnumerable<IResource> Resources { get; }
|
||||
}
|
||||
|
||||
class EmbeddedResources : IResourceGroup
|
||||
{
|
||||
private readonly AssemblyDefinition _asm;
|
||||
public string Name => "EmbeddedResource";
|
||||
|
||||
public IEnumerable<IResource> Resources => _asm.MainModule.Resources.OfType<EmbeddedResource>()
|
||||
.Select(r => new WrappedResource(_asm, r)).ToList();
|
||||
|
||||
public EmbeddedResources(AssemblyDefinition asm)
|
||||
{
|
||||
_asm = asm;
|
||||
}
|
||||
class WrappedResource : IResource
|
||||
{
|
||||
private readonly AssemblyDefinition _asm;
|
||||
private readonly EmbeddedResource _res;
|
||||
|
||||
public WrappedResource(AssemblyDefinition asm, EmbeddedResource res)
|
||||
{
|
||||
_asm = asm;
|
||||
_res = res;
|
||||
}
|
||||
|
||||
public string Uri => $"resm:{Name}?assembly={_asm.Name.Name}";
|
||||
public string Name => _res.Name;
|
||||
public string FilePath => Name;
|
||||
public byte[] FileContents => _res.GetResourceData();
|
||||
|
||||
public void Remove() => _asm.MainModule.Resources.Remove(_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
363
Robust.Client.Injectors/XamlCompiler.cs
Normal file
363
Robust.Client.Injectors/XamlCompiler.cs
Normal file
@@ -0,0 +1,363 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Pidgin;
|
||||
using XamlX;
|
||||
using XamlX.Ast;
|
||||
using XamlX.Emit;
|
||||
using XamlX.IL;
|
||||
using XamlX.Parsers;
|
||||
using XamlX.Transform;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Build.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
|
||||
/// Adjusted for our UI-Framework
|
||||
/// </summary>
|
||||
public partial class XamlCompiler
|
||||
{
|
||||
public static (bool success, bool writtentofile) Compile(IBuildEngine engine, string input, string[] references,
|
||||
string projectDirectory, string output, string strongNameKey)
|
||||
{
|
||||
var typeSystem = new CecilTypeSystem(references
|
||||
.Where(r => !r.ToLowerInvariant().EndsWith("robust.build.tasks.dll"))
|
||||
.Concat(new[] { input }), input);
|
||||
|
||||
var asm = typeSystem.TargetAssemblyDefinition;
|
||||
|
||||
if (asm.MainModule.GetType("CompiledRobustXaml", "XamlIlContext") != null)
|
||||
{
|
||||
// If this type exists, the assembly has already been processed by us.
|
||||
// Do not run again, it would corrupt the file.
|
||||
// This *shouldn't* be possible due to Inputs/Outputs dependencies in the build system,
|
||||
// but better safe than sorry eh?
|
||||
engine.LogWarningEvent(new BuildWarningEventArgs("XAMLIL", "", "", 0, 0, 0, 0, "Ran twice on same assembly file; ignoring.", "", ""));
|
||||
return (true, false);
|
||||
}
|
||||
|
||||
var compileRes = CompileCore(engine, typeSystem);
|
||||
if (compileRes == null)
|
||||
return (true, false);
|
||||
if (compileRes == false)
|
||||
return (false, false);
|
||||
|
||||
var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
|
||||
if (!string.IsNullOrWhiteSpace(strongNameKey))
|
||||
writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
|
||||
|
||||
asm.Write(output, writerParameters);
|
||||
|
||||
return (true, true);
|
||||
|
||||
}
|
||||
|
||||
static bool? CompileCore(IBuildEngine engine, CecilTypeSystem typeSystem)
|
||||
{
|
||||
var asm = typeSystem.TargetAssemblyDefinition;
|
||||
var embrsc = new EmbeddedResources(asm);
|
||||
|
||||
if (embrsc.Resources.Count(CheckXamlName) == 0)
|
||||
// Nothing to do
|
||||
return null;
|
||||
|
||||
var xamlLanguage = new XamlLanguageTypeMappings(typeSystem)
|
||||
{
|
||||
XmlnsAttributes =
|
||||
{
|
||||
typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"),
|
||||
|
||||
},
|
||||
ContentAttributes =
|
||||
{
|
||||
typeSystem.GetType("Robust.Client.UserInterface.XAML.ContentAttribute")
|
||||
},
|
||||
UsableDuringInitializationAttributes =
|
||||
{
|
||||
typeSystem.GetType("Robust.Client.UserInterface.XAML.UsableDuringInitializationAttribute")
|
||||
},
|
||||
DeferredContentPropertyAttributes =
|
||||
{
|
||||
typeSystem.GetType("Robust.Client.UserInterface.XAML.DeferredContentAttribute")
|
||||
},
|
||||
RootObjectProvider = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestRootObjectProvider"),
|
||||
UriContextProvider = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestUriContext"),
|
||||
ProvideValueTarget = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestProvideValueTarget"),
|
||||
};
|
||||
var emitConfig = new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>
|
||||
{
|
||||
ContextTypeBuilderCallback = (b,c) => EmitNameScopeField(xamlLanguage, typeSystem, b, c)
|
||||
};
|
||||
|
||||
var transformerconfig = new TransformerConfiguration(
|
||||
typeSystem,
|
||||
typeSystem.TargetAssembly,
|
||||
xamlLanguage,
|
||||
XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage), CustomValueConverter);
|
||||
|
||||
var contextDef = new TypeDefinition("CompiledRobustXaml", "XamlIlContext",
|
||||
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
|
||||
asm.MainModule.Types.Add(contextDef);
|
||||
var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
|
||||
xamlLanguage, emitConfig);
|
||||
|
||||
var compiler =
|
||||
new RobustXamlILCompiler(transformerconfig, emitConfig, true);
|
||||
|
||||
var loaderDispatcherDef = new TypeDefinition("CompiledRobustXaml", "!XamlLoader",
|
||||
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
|
||||
|
||||
var loaderDispatcherMethod = new MethodDefinition("TryLoad",
|
||||
MethodAttributes.Static | MethodAttributes.Public,
|
||||
asm.MainModule.TypeSystem.Object)
|
||||
{
|
||||
Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)}
|
||||
};
|
||||
loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
|
||||
asm.MainModule.Types.Add(loaderDispatcherDef);
|
||||
|
||||
var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
|
||||
m =>
|
||||
m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 &&
|
||||
m.ReturnType.FullName == "System.Boolean"
|
||||
&& m.Parameters[0].ParameterType.FullName == "System.String"
|
||||
&& m.Parameters[1].ParameterType.FullName == "System.String"));
|
||||
|
||||
bool CompileGroup(IResourceGroup group)
|
||||
{
|
||||
var typeDef = new TypeDefinition("CompiledRobustXaml", "!" + group.Name, TypeAttributes.Class,
|
||||
asm.MainModule.TypeSystem.Object);
|
||||
|
||||
//typeDef.CustomAttributes.Add(new CustomAttribute(ed));
|
||||
asm.MainModule.Types.Add(typeDef);
|
||||
var builder = typeSystem.CreateTypeBuilder(typeDef);
|
||||
|
||||
foreach (var res in group.Resources.Where(CheckXamlName))
|
||||
{
|
||||
try
|
||||
{
|
||||
engine.LogMessage($"XAMLIL: {res.Name} -> {res.Uri}", MessageImportance.Low);
|
||||
|
||||
var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd();
|
||||
var parsed = XDocumentXamlParser.Parse(xaml);
|
||||
|
||||
var initialRoot = (XamlAstObjectNode) parsed.Root;
|
||||
|
||||
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
|
||||
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
|
||||
string classname;
|
||||
if (classDirective != null && classDirective.Values[0] is XamlAstTextNode tn)
|
||||
{
|
||||
classname = tn.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
classname = res.Name.Replace(".xaml","");
|
||||
}
|
||||
|
||||
var classType = typeSystem.TargetAssembly.FindType(classname);
|
||||
if (classType == null)
|
||||
throw new Exception($"Unable to find type '{classname}'");
|
||||
|
||||
compiler.Transform(parsed);
|
||||
|
||||
var populateName = $"Populate:{res.Name}";
|
||||
var buildName = $"Build:{res.Name}";
|
||||
|
||||
var classTypeDefinition = typeSystem.GetTypeReference(classType).Resolve();
|
||||
|
||||
var populateBuilder = typeSystem.CreateTypeBuilder(classTypeDefinition);
|
||||
|
||||
compiler.Compile(parsed, contextClass,
|
||||
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
|
||||
classTypeDefinition == null),
|
||||
compiler.DefineBuildMethod(builder, parsed, buildName, true),
|
||||
null,
|
||||
(closureName, closureBaseType) =>
|
||||
populateBuilder.DefineSubType(closureBaseType, closureName, false),
|
||||
res.Uri, res
|
||||
);
|
||||
|
||||
//add compiled populate method
|
||||
var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve().Methods
|
||||
.First(m => m.Name == populateName);
|
||||
|
||||
const string TrampolineName = "!XamlIlPopulateTrampoline";
|
||||
var trampoline = new MethodDefinition(TrampolineName,
|
||||
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
|
||||
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
|
||||
classTypeDefinition.Methods.Add(trampoline);
|
||||
|
||||
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
|
||||
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod));
|
||||
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
var foundXamlLoader = false;
|
||||
// Find RobustXamlLoader.Load(this) and replace it with !XamlIlPopulateTrampoline(this)
|
||||
foreach (var method in classTypeDefinition.Methods
|
||||
.Where(m => !m.Attributes.HasFlag(MethodAttributes.Static)))
|
||||
{
|
||||
var i = method.Body.Instructions;
|
||||
for (var c = 1; c < i.Count; c++)
|
||||
{
|
||||
if (i[c].OpCode == OpCodes.Call)
|
||||
{
|
||||
var op = i[c].Operand as MethodReference;
|
||||
|
||||
if (op != null
|
||||
&& op.Name == TrampolineName)
|
||||
{
|
||||
foundXamlLoader = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (op != null
|
||||
&& op.Name == "Load"
|
||||
&& op.Parameters.Count == 1
|
||||
&& op.Parameters[0].ParameterType.FullName == "System.Object"
|
||||
&& op.DeclaringType.FullName == "Robust.Client.UserInterface.XAML.RobustXamlLoader")
|
||||
{
|
||||
if (MatchThisCall(i, c - 1))
|
||||
{
|
||||
i[c].Operand = trampoline;
|
||||
foundXamlLoader = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundXamlLoader)
|
||||
{
|
||||
var ctors = classTypeDefinition.GetConstructors()
|
||||
.Where(c => !c.IsStatic).ToList();
|
||||
// We can inject xaml loader into default constructor
|
||||
if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode != OpCodes.Nop) == 3)
|
||||
{
|
||||
var i = ctors[0].Body.Instructions;
|
||||
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
|
||||
i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampoline));
|
||||
i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidProgramException(
|
||||
$"No call to RobustXamlLoader.Load(this) call found anywhere in the type {classType.FullName} and type seems to have custom constructors.");
|
||||
}
|
||||
}
|
||||
|
||||
//add compiled build method
|
||||
var compiledBuildMethod = typeSystem.GetTypeReference(builder).Resolve().Methods
|
||||
.First(m => m.Name == buildName);
|
||||
var parameterlessCtor = classTypeDefinition.GetConstructors()
|
||||
.FirstOrDefault(c => c.IsPublic && !c.IsStatic && !c.HasParameters);
|
||||
|
||||
if (compiledBuildMethod != null && parameterlessCtor != null)
|
||||
{
|
||||
var i = loaderDispatcherMethod.Body.Instructions;
|
||||
var nop = Instruction.Create(OpCodes.Nop);
|
||||
i.Add(Instruction.Create(OpCodes.Ldarg_0));
|
||||
i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri));
|
||||
i.Add(Instruction.Create(OpCodes.Call, stringEquals));
|
||||
i.Add(Instruction.Create(OpCodes.Brfalse, nop));
|
||||
if (parameterlessCtor != null)
|
||||
i.Add(Instruction.Create(OpCodes.Newobj, parameterlessCtor));
|
||||
else
|
||||
{
|
||||
i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
|
||||
}
|
||||
|
||||
i.Add(Instruction.Create(OpCodes.Ret));
|
||||
i.Add(nop);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
engine.LogWarningEvent(new BuildWarningEventArgs("XAMLIL", "", res.Uri, 0, 0, 0, 0,
|
||||
e.ToString(), "", "CompileRobustXaml"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (embrsc.Resources.Count(CheckXamlName) != 0)
|
||||
{
|
||||
if (!CompileGroup(embrsc))
|
||||
return false;
|
||||
}
|
||||
|
||||
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CustomValueConverter(
|
||||
AstTransformationContext context,
|
||||
IXamlAstValueNode node,
|
||||
IXamlType type,
|
||||
out IXamlAstValueNode result)
|
||||
{
|
||||
if (!(node is XamlAstTextNode textNode))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var text = textNode.Text;
|
||||
var types = context.GetRobustTypes();
|
||||
|
||||
if (type.Equals(types.Vector2))
|
||||
{
|
||||
var foo = MathParsing.Single2.Parse(text);
|
||||
|
||||
if (!foo.Success)
|
||||
throw new XamlLoadException($"Unable to parse \"{text}\" as a Vector2", node);
|
||||
|
||||
var (x, y) = foo.Value;
|
||||
|
||||
result = new RXamlSingleVecLikeConstAstNode(
|
||||
node,
|
||||
types.Vector2, types.Vector2ConstructorFull,
|
||||
types.Single, new[] {x, y});
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public const string ContextNameScopeFieldName = "RobustNameScope";
|
||||
|
||||
private static void EmitNameScopeField(XamlLanguageTypeMappings xamlLanguage, CecilTypeSystem typeSystem, IXamlTypeBuilder<IXamlILEmitter> typeBuilder, IXamlILEmitter constructor)
|
||||
{
|
||||
var nameScopeType = typeSystem.FindType("Robust.Client.UserInterface.XAML.NameScope");
|
||||
var field = typeBuilder.DefineField(nameScopeType,
|
||||
ContextNameScopeFieldName, true, false);
|
||||
constructor
|
||||
.Ldarg_0()
|
||||
.Newobj(nameScopeType.GetConstructor())
|
||||
.Stfld(field);
|
||||
}
|
||||
}
|
||||
|
||||
interface IResource : IFileSource
|
||||
{
|
||||
string Uri { get; }
|
||||
string Name { get; }
|
||||
void Remove();
|
||||
|
||||
}
|
||||
|
||||
interface IResourceGroup
|
||||
{
|
||||
string Name { get; }
|
||||
IEnumerable<IResource> Resources { get; }
|
||||
}
|
||||
}
|
||||
21
Robust.Client.NameGenerator/NameReferenceSyntaxReceiver.cs
Normal file
21
Robust.Client.NameGenerator/NameReferenceSyntaxReceiver.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Robust.Client.NameGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Taken from https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/NameReferenceSyntaxReceiver.cs
|
||||
/// </summary>
|
||||
internal class NameReferenceSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &&
|
||||
classDeclarationSyntax.AttributeLists.Count > 0)
|
||||
CandidateClasses.Add(classDeclarationSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Link="XamlX\filename" Include="../XamlX/src/XamlX/**/*.cs" />
|
||||
<Compile Remove="../XamlX/src/XamlX/**/SreTypeSystem.cs" />
|
||||
<Compile Remove="../XamlX/src/XamlX/obj/**" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
287
Robust.Client.NameGenerator/RoslynTypeSystem.cs
Normal file
287
Robust.Client.NameGenerator/RoslynTypeSystem.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Client.NameGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Taken from https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/Infrastructure/RoslynTypeSystem.cs
|
||||
/// </summary>
|
||||
public class RoslynTypeSystem : IXamlTypeSystem
|
||||
{
|
||||
private readonly List<IXamlAssembly> _assemblies = new List<IXamlAssembly>();
|
||||
|
||||
public RoslynTypeSystem(CSharpCompilation compilation)
|
||||
{
|
||||
_assemblies.Add(new RoslynAssembly(compilation.Assembly));
|
||||
|
||||
var assemblySymbols = compilation
|
||||
.References
|
||||
.Select(compilation.GetAssemblyOrModuleSymbol)
|
||||
.OfType<IAssemblySymbol>()
|
||||
.Select(assembly => new RoslynAssembly(assembly))
|
||||
.ToList();
|
||||
|
||||
_assemblies.AddRange(assemblySymbols);
|
||||
}
|
||||
|
||||
public IReadOnlyList<IXamlAssembly> Assemblies => _assemblies;
|
||||
|
||||
public IXamlAssembly FindAssembly(string substring) => _assemblies[0];
|
||||
|
||||
public IXamlType FindType(string name)
|
||||
{
|
||||
foreach (var assembly in _assemblies)
|
||||
{
|
||||
var type = assembly.FindType(name);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IXamlType FindType(string name, string assembly)
|
||||
{
|
||||
foreach (var assemblyInstance in _assemblies)
|
||||
{
|
||||
var type = assemblyInstance.FindType(name);
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class RoslynAssembly : IXamlAssembly
|
||||
{
|
||||
private readonly IAssemblySymbol _symbol;
|
||||
|
||||
public RoslynAssembly(IAssemblySymbol symbol) => _symbol = symbol;
|
||||
|
||||
public bool Equals(IXamlAssembly other) =>
|
||||
other is RoslynAssembly roslynAssembly &&
|
||||
SymbolEqualityComparer.Default.Equals(_symbol, roslynAssembly._symbol);
|
||||
|
||||
public string Name => _symbol.Name;
|
||||
|
||||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes =>
|
||||
_symbol.GetAttributes()
|
||||
.Select(data => new RoslynAttribute(data, this))
|
||||
.ToList();
|
||||
|
||||
public IXamlType FindType(string fullName)
|
||||
{
|
||||
var type = _symbol.GetTypeByMetadataName(fullName);
|
||||
return type is null ? null : new RoslynType(type, this);
|
||||
}
|
||||
}
|
||||
|
||||
public class RoslynAttribute : IXamlCustomAttribute
|
||||
{
|
||||
private readonly AttributeData _data;
|
||||
private readonly RoslynAssembly _assembly;
|
||||
|
||||
public RoslynAttribute(AttributeData data, RoslynAssembly assembly)
|
||||
{
|
||||
_data = data;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
public bool Equals(IXamlCustomAttribute other) =>
|
||||
other is RoslynAttribute attribute &&
|
||||
_data == attribute._data;
|
||||
|
||||
public IXamlType Type => new RoslynType(_data.AttributeClass, _assembly);
|
||||
|
||||
public List<object> Parameters =>
|
||||
_data.ConstructorArguments
|
||||
.Select(argument => argument.Value)
|
||||
.ToList();
|
||||
|
||||
public Dictionary<string, object> Properties =>
|
||||
_data.NamedArguments.ToDictionary(
|
||||
pair => pair.Key,
|
||||
pair => pair.Value.Value);
|
||||
}
|
||||
|
||||
public class RoslynType : IXamlType
|
||||
{
|
||||
private static readonly SymbolDisplayFormat SymbolDisplayFormat = new SymbolDisplayFormat(
|
||||
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
|
||||
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters |
|
||||
SymbolDisplayGenericsOptions.IncludeTypeConstraints |
|
||||
SymbolDisplayGenericsOptions.IncludeVariance);
|
||||
|
||||
private readonly RoslynAssembly _assembly;
|
||||
private readonly INamedTypeSymbol _symbol;
|
||||
|
||||
public RoslynType(INamedTypeSymbol symbol, RoslynAssembly assembly)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
public bool Equals(IXamlType other) =>
|
||||
other is RoslynType roslynType &&
|
||||
SymbolEqualityComparer.Default.Equals(_symbol, roslynType._symbol);
|
||||
|
||||
public object Id => _symbol;
|
||||
|
||||
public string Name => _symbol.Name;
|
||||
|
||||
public string Namespace => _symbol.ContainingNamespace.ToDisplayString(SymbolDisplayFormat);
|
||||
|
||||
public string FullName => $"{Namespace}.{Name}";
|
||||
|
||||
public IXamlAssembly Assembly => _assembly;
|
||||
|
||||
public IReadOnlyList<IXamlProperty> Properties =>
|
||||
_symbol.GetMembers()
|
||||
.Where(member => member.Kind == SymbolKind.Property)
|
||||
.OfType<IPropertySymbol>()
|
||||
.Select(property => new RoslynProperty(property, _assembly))
|
||||
.ToList();
|
||||
|
||||
public IReadOnlyList<IXamlEventInfo> Events { get; } = new List<IXamlEventInfo>();
|
||||
|
||||
public IReadOnlyList<IXamlField> Fields { get; } = new List<IXamlField>();
|
||||
|
||||
public IReadOnlyList<IXamlMethod> Methods { get; } = new List<IXamlMethod>();
|
||||
|
||||
public IReadOnlyList<IXamlConstructor> Constructors =>
|
||||
_symbol.Constructors
|
||||
.Select(method => new RoslynConstructor(method, _assembly))
|
||||
.ToList();
|
||||
|
||||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
||||
|
||||
public IReadOnlyList<IXamlType> GenericArguments { get; } = new List<IXamlType>();
|
||||
|
||||
public bool IsAssignableFrom(IXamlType type) => type == this;
|
||||
|
||||
public IXamlType MakeGenericType(IReadOnlyList<IXamlType> typeArguments) => this;
|
||||
|
||||
public IXamlType GenericTypeDefinition => this;
|
||||
|
||||
public bool IsArray => false;
|
||||
|
||||
public IXamlType ArrayElementType { get; } = null;
|
||||
|
||||
public IXamlType MakeArrayType(int dimensions) => null;
|
||||
|
||||
public IXamlType BaseType => _symbol.BaseType == null ? null : new RoslynType(_symbol.BaseType, _assembly);
|
||||
|
||||
public bool IsValueType { get; } = false;
|
||||
|
||||
public bool IsEnum { get; } = false;
|
||||
|
||||
public IReadOnlyList<IXamlType> Interfaces =>
|
||||
_symbol.AllInterfaces
|
||||
.Select(abstraction => new RoslynType(abstraction, _assembly))
|
||||
.ToList();
|
||||
|
||||
public bool IsInterface => _symbol.IsAbstract;
|
||||
|
||||
public IXamlType GetEnumUnderlyingType() => null;
|
||||
|
||||
public IReadOnlyList<IXamlType> GenericParameters { get; } = new List<IXamlType>();
|
||||
}
|
||||
|
||||
public class RoslynConstructor : IXamlConstructor
|
||||
{
|
||||
private readonly IMethodSymbol _symbol;
|
||||
private readonly RoslynAssembly _assembly;
|
||||
|
||||
public RoslynConstructor(IMethodSymbol symbol, RoslynAssembly assembly)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
public bool Equals(IXamlConstructor other) =>
|
||||
other is RoslynConstructor roslynConstructor &&
|
||||
SymbolEqualityComparer.Default.Equals(_symbol, roslynConstructor._symbol);
|
||||
|
||||
public bool IsPublic => true;
|
||||
|
||||
public bool IsStatic => false;
|
||||
|
||||
public IReadOnlyList<IXamlType> Parameters =>
|
||||
_symbol.Parameters
|
||||
.Select(parameter => parameter.Type)
|
||||
.OfType<INamedTypeSymbol>()
|
||||
.Select(type => new RoslynType(type, _assembly))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public class RoslynProperty : IXamlProperty
|
||||
{
|
||||
private readonly IPropertySymbol _symbol;
|
||||
private readonly RoslynAssembly _assembly;
|
||||
|
||||
public RoslynProperty(IPropertySymbol symbol, RoslynAssembly assembly)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
public bool Equals(IXamlProperty other) =>
|
||||
other is RoslynProperty roslynProperty &&
|
||||
SymbolEqualityComparer.Default.Equals(_symbol, roslynProperty._symbol);
|
||||
|
||||
public string Name => _symbol.Name;
|
||||
|
||||
public IXamlType PropertyType =>
|
||||
_symbol.Type is INamedTypeSymbol namedTypeSymbol
|
||||
? new RoslynType(namedTypeSymbol, _assembly)
|
||||
: null;
|
||||
|
||||
public IXamlMethod Getter => _symbol.GetMethod == null ? null : new RoslynMethod(_symbol.GetMethod, _assembly);
|
||||
|
||||
public IXamlMethod Setter => _symbol.SetMethod == null ? null : new RoslynMethod(_symbol.SetMethod, _assembly);
|
||||
|
||||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
||||
|
||||
public IReadOnlyList<IXamlType> IndexerParameters { get; } = new List<IXamlType>();
|
||||
}
|
||||
|
||||
public class RoslynMethod : IXamlMethod
|
||||
{
|
||||
private readonly IMethodSymbol _symbol;
|
||||
private readonly RoslynAssembly _assembly;
|
||||
|
||||
public RoslynMethod(IMethodSymbol symbol, RoslynAssembly assembly)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
public bool Equals(IXamlMethod other) =>
|
||||
other is RoslynMethod roslynMethod &&
|
||||
SymbolEqualityComparer.Default.Equals(roslynMethod._symbol, _symbol);
|
||||
|
||||
public string Name => _symbol.Name;
|
||||
|
||||
public bool IsPublic => true;
|
||||
|
||||
public bool IsStatic => false;
|
||||
|
||||
public IXamlType ReturnType => new RoslynType((INamedTypeSymbol) _symbol.ReturnType, _assembly);
|
||||
|
||||
public IReadOnlyList<IXamlType> Parameters =>
|
||||
_symbol.Parameters.Select(parameter => parameter.Type)
|
||||
.OfType<INamedTypeSymbol>()
|
||||
.Select(type => new RoslynType(type, _assembly))
|
||||
.ToList();
|
||||
|
||||
public IXamlType DeclaringType => new RoslynType((INamedTypeSymbol)_symbol.ReceiverType, _assembly);
|
||||
|
||||
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => null;
|
||||
|
||||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
|
||||
}
|
||||
}
|
||||
262
Robust.Client.NameGenerator/XamlUiPartialClassGenerator.cs
Normal file
262
Robust.Client.NameGenerator/XamlUiPartialClassGenerator.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using XamlX.Ast;
|
||||
using XamlX.Emit;
|
||||
using XamlX.IL;
|
||||
using XamlX.Parsers;
|
||||
using XamlX.Transform;
|
||||
using XamlX.Transform.Transformers;
|
||||
using XamlX.TypeSystem;
|
||||
|
||||
namespace Robust.Client.NameGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/NameReferenceGenerator.cs
|
||||
/// Adjusted for our UI-Framework & needs.
|
||||
/// </summary>
|
||||
[Generator]
|
||||
public class XamlUiPartialClassGenerator : ISourceGenerator
|
||||
{
|
||||
private const string AttributeName = "Robust.Client.AutoGenerated.GenerateTypedNameReferencesAttribute";
|
||||
private const string AttributeFile = "GenerateTypedNameReferencesAttribute";
|
||||
|
||||
private const string AttributeCode = @"// <auto-generated />
|
||||
using System;
|
||||
namespace Robust.Client.AutoGenerated
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class GenerateTypedNameReferencesAttribute : Attribute { }
|
||||
}
|
||||
";
|
||||
|
||||
class NameVisitor : IXamlAstVisitor
|
||||
{
|
||||
private List<(string name, string type)> _names = new List<(string name, string type)>();
|
||||
|
||||
public static List<(string name, string type)> GetNames(IXamlAstNode node)
|
||||
{
|
||||
var visitor = new NameVisitor();
|
||||
node.Visit(visitor);
|
||||
return visitor._names;
|
||||
}
|
||||
|
||||
private bool IsControl(IXamlType type) => type.FullName != "System.Object" &&
|
||||
(type.FullName == "Robust.Client.UserInterface.Control" ||
|
||||
IsControl(type.BaseType));
|
||||
|
||||
public IXamlAstNode Visit(IXamlAstNode node)
|
||||
{
|
||||
if (node is XamlAstObjectNode objectNode)
|
||||
{
|
||||
var clrtype = objectNode.Type.GetClrType();
|
||||
var isControl = IsControl(clrtype);
|
||||
//clrtype.Interfaces.Any(i =>
|
||||
//i.IsInterface && i.FullName == "Robust.Client.UserInterface.IControl");
|
||||
|
||||
if (!isControl)
|
||||
return node;
|
||||
|
||||
foreach (var child in objectNode.Children)
|
||||
{
|
||||
if (child is XamlAstXamlPropertyValueNode propertyValueNode &&
|
||||
propertyValueNode.Property is XamlAstNamePropertyReference namedProperty &&
|
||||
namedProperty.Name == "Name" &&
|
||||
propertyValueNode.Values.Count > 0 &&
|
||||
propertyValueNode.Values[0] is XamlAstTextNode text)
|
||||
{
|
||||
var reg = (text.Text, $@"{clrtype.Namespace}.{clrtype.Name}");
|
||||
if (!_names.Contains(reg))
|
||||
{
|
||||
_names.Add(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public void Push(IXamlAstNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public void Pop()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateSourceCode(
|
||||
INamedTypeSymbol classSymbol,
|
||||
string xamlFile,
|
||||
CSharpCompilation comp)
|
||||
{
|
||||
var className = classSymbol.Name;
|
||||
var nameSpace = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
var parsed = XDocumentXamlParser.Parse(xamlFile);
|
||||
var typeSystem = new RoslynTypeSystem(comp);
|
||||
var compiler =
|
||||
new XamlILCompiler(
|
||||
new TransformerConfiguration(typeSystem, typeSystem.Assemblies[0],
|
||||
new XamlLanguageTypeMappings(typeSystem)
|
||||
{
|
||||
XmlnsAttributes = {typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute")}
|
||||
}),
|
||||
new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>(), false);
|
||||
compiler.Transformers.Add(new TypeReferenceResolver());
|
||||
compiler.Transform(parsed);
|
||||
var initialRoot = (XamlAstObjectNode) parsed.Root;
|
||||
var names = NameVisitor.GetNames(initialRoot);
|
||||
var fieldAccess = classSymbol.IsSealed ? "private" : "protected";
|
||||
//var names = NameVisitor.GetNames((XamlAstObjectNode)XDocumentXamlParser.Parse(xamlFile).Root);
|
||||
var namedControls = names.Select(info => " " +
|
||||
$"{fieldAccess} global::{info.type} {info.name} => " +
|
||||
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
|
||||
return $@"// <auto-generated />
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
namespace {nameSpace}
|
||||
{{
|
||||
partial class {className}
|
||||
{{
|
||||
{string.Join("\n", namedControls)}
|
||||
}}
|
||||
}}
|
||||
";
|
||||
}
|
||||
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var comp = (CSharpCompilation) context.Compilation;
|
||||
if (comp.GetTypeByMetadataName(AttributeName) == null)
|
||||
context.AddSource(AttributeFile, SourceText.From(AttributeCode, Encoding.UTF8));
|
||||
if (!(context.SyntaxReceiver is NameReferenceSyntaxReceiver receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var symbols = UnpackAnnotatedTypes(context, comp, receiver);
|
||||
if (symbols == null)
|
||||
return;
|
||||
|
||||
foreach (var typeSymbol in symbols)
|
||||
{
|
||||
var xamlFileName = $"{typeSymbol.Name}.xaml";
|
||||
var relevantXamlFile = context.AdditionalFiles.FirstOrDefault(t => t.Path.EndsWith(xamlFileName));
|
||||
|
||||
if (relevantXamlFile == null)
|
||||
{
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
"RXN0001",
|
||||
$"Unable to discover the relevant Robust XAML file for {typeSymbol}.",
|
||||
"Unable to discover the relevant Robust XAML file " +
|
||||
$"expected at {xamlFileName}",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
typeSymbol.Locations[0]));
|
||||
continue;
|
||||
}
|
||||
|
||||
var txt = relevantXamlFile.GetText()?.ToString();
|
||||
if (txt == null)
|
||||
{
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
"RXN0002",
|
||||
$"Unexpected empty Xaml-File was found at {xamlFileName}",
|
||||
"Expected Content due to a Class with the same name being annotated with [GenerateTypedNameReferences].",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
Location.Create(xamlFileName, new TextSpan(0, 0),
|
||||
new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))));
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var sourceCode = GenerateSourceCode(typeSymbol, txt, comp);
|
||||
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
"AXN0003",
|
||||
"Unhandled exception occured while generating typed Name references.",
|
||||
$"Unhandled exception occured while generating typed Name references: {e}",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
typeSymbol.Locations[0]));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyList<INamedTypeSymbol> UnpackAnnotatedTypes(in GeneratorExecutionContext context,
|
||||
CSharpCompilation comp, NameReferenceSyntaxReceiver receiver)
|
||||
{
|
||||
var options = (CSharpParseOptions) comp.SyntaxTrees[0].Options;
|
||||
var compilation =
|
||||
comp.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(AttributeCode, Encoding.UTF8), options));
|
||||
var symbols = new List<INamedTypeSymbol>();
|
||||
var attributeSymbol = compilation.GetTypeByMetadataName(AttributeName);
|
||||
foreach (var candidateClass in receiver.CandidateClasses)
|
||||
{
|
||||
var model = compilation.GetSemanticModel(candidateClass.SyntaxTree);
|
||||
var typeSymbol = (INamedTypeSymbol) model.GetDeclaredSymbol(candidateClass);
|
||||
var relevantAttribute = typeSymbol.GetAttributes().FirstOrDefault(attr =>
|
||||
attr.AttributeClass != null &&
|
||||
attr.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
|
||||
|
||||
if (relevantAttribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isPartial = candidateClass.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword));
|
||||
|
||||
if (isPartial)
|
||||
{
|
||||
symbols.Add(typeSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
var missingPartialKeywordMessage =
|
||||
$"The type {typeSymbol.Name} should be declared with the 'partial' keyword " +
|
||||
"as it is annotated with the [GenerateTypedNameReferences] attribute.";
|
||||
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
"RXN0004",
|
||||
missingPartialKeywordMessage,
|
||||
missingPartialKeywordMessage,
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
Location.None));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new NameReferenceSyntaxReceiver());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Robust.Client.Animations
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.Animations
|
||||
{
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Shared.Animations;
|
||||
|
||||
namespace Content.Client.Animations
|
||||
namespace Robust.Client.Animations
|
||||
{
|
||||
public class AnimationTrackControlProperty : AnimationTrackProperty
|
||||
{
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.Animations
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Animations
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
|
||||
namespace Robust.Client.Audio
|
||||
{
|
||||
|
||||
@@ -4,16 +4,15 @@ using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using NFluidsynth;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Utility;
|
||||
using Logger = Robust.Shared.Log.Logger;
|
||||
|
||||
@@ -104,7 +103,7 @@ namespace Robust.Client.Audio.Midi
|
||||
private const string OsxSoundfont =
|
||||
"/System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls";
|
||||
|
||||
private const string FallbackSoundfont = "/Resources/Midi/fallback.sf2";
|
||||
private const string FallbackSoundfont = "/Midi/fallback.sf2";
|
||||
|
||||
private readonly ResourceLoaderCallbacks _soundfontLoaderCallbacks = new();
|
||||
|
||||
@@ -207,13 +206,10 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
var renderer = new MidiRenderer(_settings!, soundfontLoader);
|
||||
|
||||
foreach (var file in _resourceManager.ContentFindFiles(new ResourcePath("/Audio/MidiCustom/")))
|
||||
foreach (var file in _resourceManager.ContentFindFiles(("/Audio/MidiCustom/")))
|
||||
{
|
||||
if (file.Extension != "sf2" && file.Extension != "dls") continue;
|
||||
if (_resourceManager.TryGetDiskFilePath(file, out var path))
|
||||
{
|
||||
renderer.LoadSoundfont(path);
|
||||
}
|
||||
renderer.LoadSoundfont(file.ToString());
|
||||
}
|
||||
|
||||
// Since the last loaded soundfont takes priority, we load the fallback soundfont before the soundfont.
|
||||
@@ -382,10 +378,18 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
public override IntPtr Open(string filename)
|
||||
{
|
||||
Stream? stream;
|
||||
if (filename.StartsWith("/Resources/"))
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
if (!IoCManager.Resolve<IResourceCache>().TryContentFileRead(filename.Substring(10), out stream))
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Stream? stream;
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
var resourcePath = new ResourcePath(filename);
|
||||
|
||||
if (resourcePath.IsRooted && resourceCache.ContentFileExists(filename))
|
||||
{
|
||||
if (!resourceCache.TryContentFileRead(filename, out stream))
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
else if (File.Exists(filename))
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using NFluidsynth;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
@@ -72,9 +70,9 @@ namespace Robust.Client.Audio.Midi
|
||||
int PlayerTotalTick { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current tick of the MIDI player.
|
||||
/// Gets or sets (seeks) the current tick of the MIDI player.
|
||||
/// </summary>
|
||||
int PlayerTick { get; }
|
||||
int PlayerTick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current tick of the sequencer.
|
||||
@@ -235,7 +233,16 @@ namespace Robust.Client.Audio.Midi
|
||||
public bool DisableProgramChangeEvent { get; set; } = true;
|
||||
|
||||
public int PlayerTotalTick => _player?.GetTotalTicks ?? 0;
|
||||
public int PlayerTick => _player?.CurrentTick ?? 0;
|
||||
public int PlayerTick
|
||||
{
|
||||
get => _player?.CurrentTick ?? 0;
|
||||
set
|
||||
{
|
||||
lock (_playerStateLock)
|
||||
_player?.Seek(Math.Max(Math.Min(value, PlayerTotalTick), 0));
|
||||
}
|
||||
}
|
||||
|
||||
public uint SequencerTick => _sequencer?.Tick ?? 0;
|
||||
public double SequencerTimeScale => _sequencer?.TimeScale ?? 0;
|
||||
|
||||
@@ -310,9 +317,8 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
lock (_playerStateLock)
|
||||
{
|
||||
if (_player == null)
|
||||
_player = new NFluidsynth.Player(_synth);
|
||||
_player.Stop();
|
||||
_player?.Dispose();
|
||||
_player = new NFluidsynth.Player(_synth);
|
||||
_player.AddMem(buffer);
|
||||
_player.SetPlaybackCallback(MidiPlayerEventHandler);
|
||||
_player.Play();
|
||||
@@ -351,10 +357,7 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
public void StopAllNotes()
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
_synth.AllNotesOff(i);
|
||||
}
|
||||
_synth.AllNotesOff(-1);
|
||||
}
|
||||
|
||||
public void LoadSoundfont(string filename, bool resetPresets = false)
|
||||
@@ -475,12 +478,6 @@ namespace Robust.Client.Audio.Midi
|
||||
lock(_playerStateLock)
|
||||
switch (midiEvent.Type)
|
||||
{
|
||||
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
|
||||
case 1:
|
||||
case 5:
|
||||
case 81:
|
||||
break;
|
||||
|
||||
// Note On 0x80
|
||||
case 144:
|
||||
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
|
||||
@@ -503,8 +500,10 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
// Program Change - 0xC0
|
||||
case 192:
|
||||
if(!DisableProgramChangeEvent)
|
||||
if (!DisableProgramChangeEvent)
|
||||
_synth.ProgramChange(midiEvent.Channel, midiEvent.Program);
|
||||
else
|
||||
return;
|
||||
break;
|
||||
|
||||
// Channel Pressure - 0xD0
|
||||
@@ -517,13 +516,17 @@ namespace Robust.Client.Audio.Midi
|
||||
_synth.PitchBend(midiEvent.Channel, midiEvent.Pitch);
|
||||
break;
|
||||
|
||||
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
|
||||
case 1:
|
||||
case 5:
|
||||
case 81:
|
||||
// System Messages - 0xF0
|
||||
case 240:
|
||||
break;
|
||||
return;
|
||||
|
||||
default:
|
||||
_midiSawmill.Warning("Unhandled midi event of type {0}", midiEvent.Type, midiEvent);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (FluidSynthInteropException)
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Net;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.Interfaces.Utility;
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client
|
||||
@@ -25,7 +22,7 @@ namespace Robust.Client
|
||||
{
|
||||
[Dependency] private readonly IClientNetManager _net = default!;
|
||||
[Dependency] private readonly IPlayerManager _playMan = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly IClientEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IDiscordRichPresence _discord = default!;
|
||||
@@ -50,18 +47,28 @@ namespace Robust.Client
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgServerInfo>(MsgServerInfo.NAME, HandleServerInfo);
|
||||
_net.RegisterNetMessage<MsgSetTickRate>(MsgSetTickRate.NAME, HandleSetTickRate);
|
||||
_net.RegisterNetMessage<MsgServerInfoReq>(MsgServerInfoReq.NAME);
|
||||
_net.Connected += OnConnected;
|
||||
_net.ConnectFailed += OnConnectFailed;
|
||||
_net.Disconnect += OnNetDisconnect;
|
||||
|
||||
_configManager.OnValueChanged(CVars.NetTickrate, TickRateChanged, invokeImmediately: true);
|
||||
|
||||
_playMan.Initialize();
|
||||
_debugDrawMan.Initialize();
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void TickRateChanged(int tickrate)
|
||||
{
|
||||
if (GameInfo != null)
|
||||
{
|
||||
GameInfo.TickRate = (byte) tickrate;
|
||||
}
|
||||
|
||||
_timing.TickRate = (byte) tickrate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ConnectToServer(DnsEndPoint endPoint)
|
||||
{
|
||||
@@ -98,9 +105,39 @@ namespace Robust.Client
|
||||
|
||||
private void OnConnected(object? sender, NetChannelArgs args)
|
||||
{
|
||||
// request base info about the server
|
||||
var msgInfo = _net.CreateNetMessage<MsgServerInfoReq>();
|
||||
_net.ClientSendMessage(msgInfo);
|
||||
_configManager.SyncWithServer();
|
||||
_configManager.ReceivedInitialNwVars += OnReceivedClientData;
|
||||
}
|
||||
|
||||
private void OnReceivedClientData(object? sender, EventArgs e)
|
||||
{
|
||||
_configManager.ReceivedInitialNwVars -= OnReceivedClientData;
|
||||
|
||||
var info = GameInfo;
|
||||
|
||||
var serverName = _configManager.GetCVar<string>("game.hostname");
|
||||
if (info == null)
|
||||
{
|
||||
GameInfo = info = new ServerInfo(serverName);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.ServerName = serverName;
|
||||
}
|
||||
|
||||
var maxPlayers = _configManager.GetCVar<int>("game.maxplayers");
|
||||
info.ServerMaxPlayers = maxPlayers;
|
||||
|
||||
var userName = _net.ServerChannel!.UserName;
|
||||
var userId = _net.ServerChannel.UserId;
|
||||
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
|
||||
// start up player management
|
||||
_playMan.Startup(_net.ServerChannel!);
|
||||
|
||||
_playMan.LocalPlayer!.UserId = userId;
|
||||
_playMan.LocalPlayer.Name = userName;
|
||||
|
||||
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,6 +172,7 @@ namespace Robust.Client
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_configManager.ClearReceivedInitialNwVars();
|
||||
OnRunLevelChanged(ClientRunLevel.Initialize);
|
||||
}
|
||||
|
||||
@@ -152,6 +190,7 @@ namespace Robust.Client
|
||||
|
||||
LastDisconnectReason = args.Reason;
|
||||
|
||||
IoCManager.Resolve<INetConfigurationManager>().FlushMessages();
|
||||
_gameStates.Reset();
|
||||
_playMan.Shutdown();
|
||||
_entityManager.Shutdown();
|
||||
@@ -160,42 +199,6 @@ namespace Robust.Client
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void HandleServerInfo(MsgServerInfo msg)
|
||||
{
|
||||
var info = GameInfo;
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
GameInfo = info = new ServerInfo(msg.ServerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.ServerName = msg.ServerName;
|
||||
}
|
||||
|
||||
info.ServerMaxPlayers = msg.ServerMaxPlayers;
|
||||
info.TickRate = msg.TickRate;
|
||||
_timing.TickRate = msg.TickRate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {msg.TickRate}");
|
||||
|
||||
var userName = msg.MsgChannel.UserName;
|
||||
var userId = msg.MsgChannel.UserId;
|
||||
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
|
||||
// start up player management
|
||||
_playMan.Startup(_net.ServerChannel!);
|
||||
|
||||
_playMan.LocalPlayer!.UserId = userId;
|
||||
_playMan.LocalPlayer.Name = userName;
|
||||
|
||||
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
|
||||
}
|
||||
|
||||
private void HandleSetTickRate(MsgSetTickRate message)
|
||||
{
|
||||
_timing.TickRate = message.NewTickRate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
private void OnLocalStatusChanged(object? obj, StatusEventArgs eventArgs)
|
||||
{
|
||||
// player finished fully connecting to the server.
|
||||
|
||||
@@ -5,26 +5,8 @@ using Robust.Client.Debugging;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
using Robust.Client.Graphics.Lighting;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.Lighting;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.Map;
|
||||
using Robust.Client.Interfaces.Placement;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Interfaces.Utility;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.Player;
|
||||
@@ -35,15 +17,13 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Client.ViewVariables;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
|
||||
namespace Robust.Client
|
||||
{
|
||||
@@ -78,10 +58,11 @@ namespace Robust.Client
|
||||
IoCManager.Register<IDebugDrawingManager, DebugDrawingManager>();
|
||||
IoCManager.Register<ILightManager, LightManager>();
|
||||
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
|
||||
IoCManager.Register<IClientConsole, ClientConsole>();
|
||||
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
|
||||
IoCManager.Register<IFontManager, FontManager>();
|
||||
IoCManager.Register<IFontManagerInternal, FontManager>();
|
||||
IoCManager.Register<IMidiManager, MidiManager>();
|
||||
IoCManager.Register<IAuthManager, AuthManager>();
|
||||
switch (mode)
|
||||
{
|
||||
case GameController.DisplayMode.Headless:
|
||||
@@ -115,6 +96,7 @@ namespace Robust.Client
|
||||
IoCManager.Register<IViewVariablesManagerInternal, ViewVariablesManager>();
|
||||
IoCManager.Register<IClientConGroupController, ClientConGroupController>();
|
||||
IoCManager.Register<IScriptClient, ScriptClient>();
|
||||
//IoCManager.Register<IXamlCompiler, XamlCompiler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Log;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public class AddStringArgs : EventArgs
|
||||
{
|
||||
public string Text { get; }
|
||||
public Color Color { get; }
|
||||
|
||||
public AddStringArgs(string text, Color color)
|
||||
{
|
||||
Text = text;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
public class AddFormattedMessageArgs : EventArgs
|
||||
{
|
||||
public readonly FormattedMessage Message;
|
||||
|
||||
public AddFormattedMessageArgs(FormattedMessage message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ClientConsole : IClientConsole, IDebugConsole
|
||||
{
|
||||
private static readonly Color MsgColor = new Color(65, 105, 225);
|
||||
|
||||
[Dependency] private readonly IClientNetManager _network = default!;
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
[Dependency] private readonly ILogManager logManager = default!;
|
||||
|
||||
private readonly Dictionary<string, IConsoleCommand> _commands = new Dictionary<string, IConsoleCommand>();
|
||||
private bool _requestedCommands;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_network.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME, HandleConCmdReg);
|
||||
_network.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME, HandleConCmdAck);
|
||||
_network.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME);
|
||||
|
||||
Reset();
|
||||
logManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset()
|
||||
{
|
||||
_commands.Clear();
|
||||
_requestedCommands = false;
|
||||
_network.Connected += OnNetworkConnected;
|
||||
|
||||
InitializeCommands();
|
||||
SendServerCommandRequest();
|
||||
}
|
||||
|
||||
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)
|
||||
{
|
||||
SendServerCommandRequest();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
// We don't have anything to dispose.
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, IConsoleCommand> Commands => _commands;
|
||||
|
||||
public void AddLine(string text, Color color)
|
||||
{
|
||||
AddString?.Invoke(this, new AddStringArgs(text, color));
|
||||
}
|
||||
|
||||
public void AddLine(string text)
|
||||
{
|
||||
AddLine(text, Color.White);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ClearText?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler<AddStringArgs>? AddString;
|
||||
public event EventHandler? ClearText;
|
||||
public event EventHandler<AddFormattedMessageArgs>? AddFormatted;
|
||||
|
||||
private void HandleConCmdAck(MsgConCmdAck msg)
|
||||
{
|
||||
AddLine("< " + msg.Text, MsgColor);
|
||||
}
|
||||
|
||||
private void HandleConCmdReg(MsgConCmdReg msg)
|
||||
{
|
||||
foreach (var cmd in msg.Commands)
|
||||
{
|
||||
var commandName = cmd.Name;
|
||||
|
||||
// Do not do duplicate commands.
|
||||
if (_commands.ContainsKey(commandName))
|
||||
{
|
||||
Logger.DebugS("console", $"Server sent console command {commandName}, but we already have one with the same name. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var command = new ServerDummyCommand(commandName, cmd.Help, cmd.Description);
|
||||
_commands[commandName] = command;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes commands (chat messages starting with /)
|
||||
/// </summary>
|
||||
/// <param name="text">input text</param>
|
||||
public void ProcessCommand(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
// echo the command locally
|
||||
AddLine("> " + text, Color.Lime);
|
||||
|
||||
//Commands are processed locally and then sent to the server to be processed there again.
|
||||
var args = new List<string>();
|
||||
|
||||
CommandParsing.ParseArguments(text, args);
|
||||
|
||||
var commandname = args[0];
|
||||
|
||||
var forward = true;
|
||||
if (_commands.ContainsKey(commandname))
|
||||
{
|
||||
var command = _commands[commandname];
|
||||
args.RemoveAt(0);
|
||||
forward = command.Execute(this, args.ToArray());
|
||||
}
|
||||
else if (!_network.IsConnected)
|
||||
{
|
||||
AddLine("Unknown command: " + commandname, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (forward)
|
||||
SendServerConsoleCommand(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates and registeres all local commands.
|
||||
/// </summary>
|
||||
private void InitializeCommands()
|
||||
{
|
||||
foreach (var t in _reflectionManager.GetAllChildren<IConsoleCommand>())
|
||||
{
|
||||
var instance = (IConsoleCommand)Activator.CreateInstance(t)!;
|
||||
if (_commands.ContainsKey(instance.Command))
|
||||
throw new InvalidOperationException($"Command already registered: {instance.Command}");
|
||||
|
||||
_commands[instance.Command] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests remote commands from server.
|
||||
/// </summary>
|
||||
public void SendServerCommandRequest()
|
||||
{
|
||||
if (_requestedCommands)
|
||||
return;
|
||||
|
||||
if (!_network.IsConnected)
|
||||
return;
|
||||
|
||||
var msg = _network.CreateNetMessage<MsgConCmdReg>();
|
||||
_network.ClientSendMessage(msg);
|
||||
|
||||
_requestedCommands = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a command directly to the server.
|
||||
/// </summary>
|
||||
private void SendServerConsoleCommand(string text)
|
||||
{
|
||||
if (_network == null || !_network.IsConnected)
|
||||
return;
|
||||
|
||||
var msg = _network.CreateNetMessage<MsgConCmd>();
|
||||
msg.Text = text;
|
||||
_network.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void AddFormattedLine(FormattedMessage message)
|
||||
{
|
||||
// Why the hell does this class implement IDebugConsole.
|
||||
AddFormatted?.Invoke(this, new AddFormattedMessageArgs(message));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These dummies are made purely so list and help can list server-side commands.
|
||||
/// </summary>
|
||||
[Reflect(false)]
|
||||
internal class ServerDummyCommand : IConsoleCommand
|
||||
{
|
||||
internal ServerDummyCommand(string command, string help, string description)
|
||||
{
|
||||
Command = command;
|
||||
Help = help;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
|
||||
public string Help { get; }
|
||||
|
||||
public string Description { get; }
|
||||
|
||||
// Always forward to server.
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
218
Robust.Client/Console/ClientConsoleHost.cs
Normal file
218
Robust.Client/Console/ClientConsoleHost.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Log;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public class AddStringArgs : EventArgs
|
||||
{
|
||||
public string Text { get; }
|
||||
|
||||
public bool Local { get; }
|
||||
|
||||
public bool Error { get; }
|
||||
|
||||
public AddStringArgs(string text, bool local, bool error)
|
||||
{
|
||||
Text = text;
|
||||
Local = local;
|
||||
Error = error;
|
||||
}
|
||||
}
|
||||
|
||||
public class AddFormattedMessageArgs : EventArgs
|
||||
{
|
||||
public readonly FormattedMessage Message;
|
||||
|
||||
public AddFormattedMessageArgs(FormattedMessage message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IClientConsoleHost" />
|
||||
internal class ClientConsoleHost : ConsoleHost, IClientConsoleHost
|
||||
{
|
||||
private bool _requestedCommands;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
NetManager.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME, HandleConCmdReg);
|
||||
NetManager.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME, HandleConCmdAck);
|
||||
NetManager.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME, ProcessCommand);
|
||||
|
||||
Reset();
|
||||
LogManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
|
||||
}
|
||||
|
||||
private void ProcessCommand(MsgConCmd message)
|
||||
{
|
||||
string? text = message.Text;
|
||||
LogManager.GetSawmill(SawmillName).Info($"SERVER:{text}");
|
||||
|
||||
ExecuteCommand(null, text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset()
|
||||
{
|
||||
AvailableCommands.Clear();
|
||||
_requestedCommands = false;
|
||||
NetManager.Connected += OnNetworkConnected;
|
||||
|
||||
LoadConsoleCommands();
|
||||
SendServerCommandRequest();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<AddStringArgs>? AddString;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<AddFormattedMessageArgs>? AddFormatted;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddFormattedLine(FormattedMessage message)
|
||||
{
|
||||
AddFormatted?.Invoke(this, new AddFormattedMessageArgs(message));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteError(ICommonSession? session, string text)
|
||||
{
|
||||
OutputText(text, true, true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteCommand(ICommonSession? session, string command)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
return;
|
||||
|
||||
// echo the command locally
|
||||
WriteError(null, "> " + command);
|
||||
|
||||
//Commands are processed locally and then sent to the server to be processed there again.
|
||||
var args = new List<string>();
|
||||
|
||||
CommandParsing.ParseArguments(command, args);
|
||||
|
||||
var commandName = args[0];
|
||||
|
||||
if (AvailableCommands.ContainsKey(commandName))
|
||||
{
|
||||
var command1 = AvailableCommands[commandName];
|
||||
args.RemoveAt(0);
|
||||
command1.Execute(new ConsoleShell(this, null), command, args.ToArray());
|
||||
}
|
||||
else
|
||||
WriteError(null, "Unknown command: " + commandName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void RemoteExecuteCommand(ICommonSession? session, string command)
|
||||
{
|
||||
if (!NetManager.IsConnected) // we don't care about session on client
|
||||
return;
|
||||
|
||||
var msg = NetManager.CreateNetMessage<MsgConCmd>();
|
||||
msg.Text = command;
|
||||
NetManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteLine(ICommonSession? session, string text)
|
||||
{
|
||||
OutputText(text, true, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
// We don't have anything to dispose.
|
||||
}
|
||||
|
||||
private void OutputText(string text, bool local, bool error)
|
||||
{
|
||||
AddString?.Invoke(this, new AddStringArgs(text, local, error));
|
||||
}
|
||||
|
||||
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)
|
||||
{
|
||||
SendServerCommandRequest();
|
||||
}
|
||||
|
||||
private void HandleConCmdAck(MsgConCmdAck msg)
|
||||
{
|
||||
OutputText("< " + msg.Text, false, msg.Error);
|
||||
}
|
||||
|
||||
private void HandleConCmdReg(MsgConCmdReg msg)
|
||||
{
|
||||
foreach (var cmd in msg.Commands)
|
||||
{
|
||||
string? commandName = cmd.Name;
|
||||
|
||||
// Do not do duplicate commands.
|
||||
if (AvailableCommands.ContainsKey(commandName))
|
||||
{
|
||||
Logger.DebugS("console", $"Server sent console command {commandName}, but we already have one with the same name. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var command = new ServerDummyCommand(commandName, cmd.Help, cmd.Description);
|
||||
AvailableCommands[commandName] = command;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests remote commands from server.
|
||||
/// </summary>
|
||||
private void SendServerCommandRequest()
|
||||
{
|
||||
if (_requestedCommands)
|
||||
return;
|
||||
|
||||
if (!NetManager.IsConnected)
|
||||
return;
|
||||
|
||||
var msg = NetManager.CreateNetMessage<MsgConCmdReg>();
|
||||
NetManager.ClientSendMessage(msg);
|
||||
|
||||
_requestedCommands = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These dummies are made purely so list and help can list server-side commands.
|
||||
/// </summary>
|
||||
[Reflect(false)]
|
||||
internal class ServerDummyCommand : IConsoleCommand
|
||||
{
|
||||
internal ServerDummyCommand(string command, string help, string description)
|
||||
{
|
||||
Command = command;
|
||||
Help = help;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
|
||||
public string Description { get; }
|
||||
|
||||
public string Help { get; }
|
||||
|
||||
// Always forward to server.
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.RemoteExecuteCommand(argStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Robust.Client/Console/Commands/AddCompCommand.cs
Normal file
66
Robust.Client/Console/Commands/AddCompCommand.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class AddCompCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "addcompc";
|
||||
public string Description => "Adds a component to an entity on the client";
|
||||
public string Help => "addcompc <uid> <componentName>";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
|
||||
if (args.Length != 2)
|
||||
{
|
||||
shell.WriteLine("Wrong number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
var entityUid = EntityUid.Parse(args[0]);
|
||||
var componentName = args[1];
|
||||
|
||||
var compManager = IoCManager.Resolve<IComponentManager>();
|
||||
var compFactory = IoCManager.Resolve<IComponentFactory>();
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
var entity = entityManager.GetEntity(entityUid);
|
||||
var component = (Component) compFactory.GetComponent(componentName);
|
||||
|
||||
component.Owner = entity;
|
||||
|
||||
compManager.AddComponent(entity, component);
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
internal sealed class RemoveCompCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "rmcompc";
|
||||
public string Description => "Removes a component from an entity.";
|
||||
public string Help => "rmcompc <uid> <componentName>";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
shell.WriteLine("Wrong number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
var entityUid = EntityUid.Parse(args[0]);
|
||||
var componentName = args[1];
|
||||
|
||||
var compManager = IoCManager.Resolve<IComponentManager>();
|
||||
var compFactory = IoCManager.Resolve<IComponentFactory>();
|
||||
|
||||
var registration = compFactory.GetRegistration(componentName);
|
||||
|
||||
compManager.RemoveComponent(entityUid, registration.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
@@ -13,18 +13,17 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Spawns a client-side entity with specific type at your feet.";
|
||||
public string Help => "cspawn <entity type>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer;
|
||||
if (player?.ControlledEntity == null)
|
||||
{
|
||||
console.AddLine("You don't have an attached entity.");
|
||||
return false;
|
||||
shell.WriteLine("You don't have an attached entity.");
|
||||
return;
|
||||
}
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
entityManager.SpawnEntity(args[0], player.ControlledEntity.Transform.Coordinates);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class CVarCommand : SharedCVarCommand, IConsoleCommand
|
||||
{
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1 || args.Length > 2)
|
||||
{
|
||||
console.AddLine("Must provide exactly one or two arguments.", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Must provide exactly one or two arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
var configManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
@@ -26,21 +24,21 @@ namespace Robust.Client.Console.Commands
|
||||
if (name == "?")
|
||||
{
|
||||
var cvars = configManager.GetRegisteredCVars().OrderBy(c => c);
|
||||
console.AddLine(string.Join("\n", cvars));
|
||||
return false;
|
||||
shell.WriteLine(string.Join("\n", cvars));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configManager.IsCVarRegistered(name))
|
||||
{
|
||||
console.AddLine($"CVar '{name}' is not registered. Use 'cvar ?' to get a list of all registered CVars.", Color.Red);
|
||||
return false;
|
||||
shell.WriteError($"CVar '{name}' is not registered. Use 'cvar ?' to get a list of all registered CVars.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length == 1)
|
||||
{
|
||||
// Read CVar
|
||||
var value = configManager.GetCVar<object>(name);
|
||||
console.AddLine(value.ToString() ?? "");
|
||||
shell.WriteLine(value.ToString() ?? "");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,11 +52,9 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
console.AddLine($"Input value is in incorrect format for type {type}");
|
||||
shell.WriteLine($"Input value is in incorrect format for type {type}");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +65,9 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Saves the client configuration to the config file";
|
||||
public string Help => "saveconfig";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
IoCManager.Resolve<IConfigurationManager>().SaveToFile();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
// This file is for commands that do something to the console itself.
|
||||
// This file is for commands that do something to the console itself.
|
||||
// Not some generic console command type.
|
||||
// Couldn't think of a better name sorry.
|
||||
|
||||
using System;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -17,10 +12,9 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Clears the debug console of all messages.";
|
||||
public string Description => "Clears the console.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
console.Clear();
|
||||
return false;
|
||||
shell.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,15 +24,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Fills the console with some nonsense for debugging.";
|
||||
public string Description => "Fill up the console for debugging.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
Color[] colors = { Color.Green, Color.Blue, Color.Red };
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
for (int x = 0; x < 50; x++)
|
||||
{
|
||||
console.AddLine("filling...", colors[random.Next(0, colors.Length)]);
|
||||
shell.WriteLine("filling...");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,37 +6,25 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Robust.Client.Input;
|
||||
using System.Threading;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.Lighting;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement.ResourceTypes;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -49,16 +37,14 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Dump entity list";
|
||||
public string Description => "Dumps entity list of UIDs and prototype.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
foreach (var e in entityManager.GetEntities().OrderBy(e => e.Uid))
|
||||
{
|
||||
console.AddLine($"entity {e.Uid}, {e.Prototype?.ID}, {e.Transform.Coordinates}.", Color.White);
|
||||
shell.WriteLine($"entity {e.Uid}, {e.Prototype?.ID}, {e.Transform.Coordinates}.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,12 +54,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Usage: getcomponentregistration <componentName>";
|
||||
public string Description => "Gets component registration information";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
var componentFactory = IoCManager.Resolve<IComponentFactory>();
|
||||
@@ -94,19 +80,17 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
message.Append($", NSE: {registration.NetworkSynchronizeExistence}, references:");
|
||||
|
||||
console.AddLine(message.ToString(), Color.White);
|
||||
shell.WriteLine(message.ToString());
|
||||
|
||||
foreach (var type in registration.References)
|
||||
{
|
||||
console.AddLine($" {type}", Color.White);
|
||||
shell.WriteLine($" {type}");
|
||||
}
|
||||
}
|
||||
catch (UnknownComponentException)
|
||||
{
|
||||
console.AddLine($"No registration found for '{args[0]}'", Color.Red);
|
||||
shell.WriteError($"No registration found for '{args[0]}'");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,14 +103,14 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public string Description => "Toggles a debug monitor in the F3 menu.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var monitor = IoCManager.Resolve<IUserInterfaceManager>().DebugMonitors;
|
||||
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0])
|
||||
@@ -159,11 +143,9 @@ namespace Robust.Client.Console.Commands
|
||||
monitor.ShowInput ^= true;
|
||||
break;
|
||||
default:
|
||||
console.AddLine($"Invalid key: {args[0]}");
|
||||
shell.WriteLine($"Invalid key: {args[0]}");
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +155,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Throws an exception";
|
||||
public string Description => "Throws an exception";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
throw new InvalidOperationException("Fuck");
|
||||
}
|
||||
@@ -185,11 +167,10 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "";
|
||||
public string Description => "Enables debug drawing over all bounding boxes in the game, showing their size.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IDebugDrawing>();
|
||||
mgr.DebugColliders = !mgr.DebugColliders;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,11 +180,10 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "";
|
||||
public string Description => "Enables debug drawing over all entity positions in the game.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IDebugDrawing>();
|
||||
mgr.DebugPositions = !mgr.DebugPositions;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,25 +193,24 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "Usage: showrays <raylifetime>";
|
||||
public string Description => "Toggles debug drawing of physics rays. An integer for <raylifetime> must be provided";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[0], out var id))
|
||||
{
|
||||
console.AddLine($"{args[0]} is not a valid integer.",Color.Red);
|
||||
return false;
|
||||
shell.WriteError($"{args[0]} is not a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
var mgr = IoCManager.Resolve<IDebugDrawingManager>();
|
||||
mgr.DebugDrawRays = !mgr.DebugDrawRays;
|
||||
console.AddLine("Toggled showing rays to:" + mgr.DebugDrawRays.ToString(), Color.Green);
|
||||
shell.WriteError("Toggled showing rays to:" + mgr.DebugDrawRays.ToString());
|
||||
mgr.DebugRayLifetime = TimeSpan.FromSeconds((double)int.Parse(args[0], CultureInfo.InvariantCulture));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,10 +220,9 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "";
|
||||
public string Description => "Immediately disconnect from the server and go back to the main menu.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
IoCManager.Resolve<IClientNetManager>().ClientDisconnect("Disconnect command used.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,33 +235,33 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public string Description => "Displays verbose diagnostics for an entity.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!new Regex(@"^c?[0-9]+$").IsMatch(args[0])))
|
||||
{
|
||||
console.AddLine("Malformed UID", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Malformed UID");
|
||||
return;
|
||||
}
|
||||
|
||||
var uid = EntityUid.Parse(args[0]);
|
||||
var entmgr = IoCManager.Resolve<IEntityManager>();
|
||||
if (!entmgr.TryGetEntity(uid, out var entity))
|
||||
{
|
||||
console.AddLine("That entity does not exist. Sorry lad.", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("That entity does not exist. Sorry lad.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.AddLine($"{entity.Uid}: {entity.Prototype?.ID}/{entity.Name}");
|
||||
console.AddLine($"init/del/lmt: {entity.Initialized}/{entity.Deleted}/{entity.LastModifiedTick}");
|
||||
shell.WriteLine($"{entity.Uid}: {entity.Prototype?.ID}/{entity.Name}");
|
||||
shell.WriteLine($"init/del/lmt: {entity.Initialized}/{entity.Deleted}/{entity.LastModifiedTick}");
|
||||
foreach (var component in entity.GetAllComponents())
|
||||
{
|
||||
console.AddLine(component.ToString() ?? "");
|
||||
shell.WriteLine(component.ToString() ?? "");
|
||||
if (component is IComponentDebug debug)
|
||||
{
|
||||
foreach (var line in debug.GetDebugString().Split('\n'))
|
||||
@@ -293,12 +271,10 @@ namespace Robust.Client.Console.Commands
|
||||
continue;
|
||||
}
|
||||
|
||||
console.AddLine("\t" + line);
|
||||
shell.WriteLine("\t" + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,12 +284,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "sggcell <gridID> <vector2i> [offset]\nThat vector2i param is in the form x<int>,y<int>.";
|
||||
public string Description => "Lists entities on a snap grid cell.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 2 && args.Length != 3)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
string gridId = args[0];
|
||||
@@ -322,14 +298,14 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
if (!int.TryParse(args[0], out var id))
|
||||
{
|
||||
console.AddLine($"{args[0]} is not a valid integer.",Color.Red);
|
||||
return false;
|
||||
shell.WriteError($"{args[0]} is not a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!new Regex(@"^-?[0-9]+,-?[0-9]+$").IsMatch(indices))
|
||||
{
|
||||
console.AddLine("mapIndicies must be of form x<int>,y<int>", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("mapIndicies must be of form x<int>,y<int>");
|
||||
return;
|
||||
}
|
||||
|
||||
SnapGridOffset selectedOffset;
|
||||
@@ -339,8 +315,8 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
else
|
||||
{
|
||||
console.AddLine("given offset type is not defined", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("given offset type is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
@@ -354,16 +330,13 @@ namespace Robust.Client.Console.Commands
|
||||
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture)),
|
||||
selectedOffset))
|
||||
{
|
||||
console.AddLine(entity.Owner.Uid.ToString());
|
||||
shell.WriteLine(entity.Owner.Uid.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.AddLine("grid does not exist", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("grid does not exist");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,19 +346,17 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Changes the name used when attempting to connect to the server.";
|
||||
public string Help => Command + " <name>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
var client = IoCManager.Resolve<IBaseClient>();
|
||||
client.PlayerNameOverride = args[0];
|
||||
|
||||
console.AddLine($"Overriding player name to \"{args[0]}\".", Color.White);
|
||||
|
||||
return false;
|
||||
shell.WriteLine($"Overriding player name to \"{args[0]}\".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,12 +366,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Pre-caches a resource.";
|
||||
public string Help => "ldrsc <path> <type>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
var reflection = IoCManager.Resolve<IReflectionManager>();
|
||||
@@ -412,8 +383,8 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
console.AddLine("Unable to find type", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Unable to find type");
|
||||
return;
|
||||
}
|
||||
|
||||
var getResourceMethod =
|
||||
@@ -423,7 +394,6 @@ namespace Robust.Client.Console.Commands
|
||||
DebugTools.Assert(getResourceMethod != null);
|
||||
var generic = getResourceMethod!.MakeGenericMethod(type);
|
||||
generic.Invoke(resourceCache, new object[] { args[0], true });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,12 +403,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Reloads a resource.";
|
||||
public string Help => "rldrsc <path> <type>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
var reflection = IoCManager.Resolve<IReflectionManager>();
|
||||
@@ -450,15 +420,14 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
console.AddLine("Unable to find type", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Unable to find type");
|
||||
return;
|
||||
}
|
||||
|
||||
var getResourceMethod = resourceCache.GetType().GetMethod("ReloadResource", new[] { typeof(string) });
|
||||
DebugTools.Assert(getResourceMethod != null);
|
||||
var generic = getResourceMethod!.MakeGenericMethod(type);
|
||||
generic.Invoke(resourceCache, new object[] { args[0] });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,18 +437,18 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Gets the tile count of a grid";
|
||||
public string Help => "Usage: gridtc <gridId>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[0], out var id))
|
||||
{
|
||||
console.AddLine($"{args[0]} is not a valid integer.");
|
||||
return false;
|
||||
shell.WriteLine($"{args[0]} is not a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
var gridId = new GridId(int.Parse(args[0]));
|
||||
@@ -487,13 +456,11 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
if (mapManager.TryGetGrid(gridId, out var grid))
|
||||
{
|
||||
console.AddLine(mapManager.GetGrid(gridId).GetAllTiles().Count().ToString());
|
||||
return false;
|
||||
shell.WriteLine(mapManager.GetGrid(gridId).GetAllTiles().Count().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
console.AddLine($"No grid exists with id {id}",Color.Red);
|
||||
return false;
|
||||
shell.WriteError($"No grid exists with id {id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,7 +471,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Dump GUI tree to /guidump.txt in user data.";
|
||||
public string Help => "guidump";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var root = IoCManager.Resolve<IUserInterfaceManager>().RootControl;
|
||||
var res = IoCManager.Resolve<IResourceManager>();
|
||||
@@ -514,8 +481,6 @@ namespace Robust.Client.Console.Commands
|
||||
{
|
||||
_writeNode(root, 0, writer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void _writeNode(Control control, int indents, TextWriter writer)
|
||||
@@ -575,7 +540,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Open a dummy UI testing window";
|
||||
public string Help => "uitest";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var window = new SS14Window { CustomMinimumSize = (500, 400)};
|
||||
var tabContainer = new TabContainer();
|
||||
@@ -667,8 +632,6 @@ namespace Robust.Client.Console.Commands
|
||||
});
|
||||
|
||||
window.OpenCentered();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,11 +641,10 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Sets the system clipboard";
|
||||
public string Help => "setclipboard <text>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IClipboardManager>();
|
||||
mgr.SetText(args[0]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,11 +654,10 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Gets the system clipboard";
|
||||
public string Help => "getclipboard";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IClipboardManager>();
|
||||
console.AddLine(mgr.GetText());
|
||||
return false;
|
||||
shell.WriteLine(mgr.GetText());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,11 +667,11 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Toggles light rendering.";
|
||||
public string Help => "togglelight";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.Enabled = !mgr.Enabled;
|
||||
return false;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.Enabled = !mgr.Enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,12 +681,11 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Toggles fov for client.";
|
||||
public string Help => "togglefov";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IEyeManager>();
|
||||
if (mgr.CurrentEye != null)
|
||||
mgr.CurrentEye.DrawFov = !mgr.CurrentEye.DrawFov;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,11 +695,11 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Toggles hard fov for client (for debugging space-station-14#2353).";
|
||||
public string Help => "togglehardfov";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.DrawHardFov = !mgr.DrawHardFov;
|
||||
return false;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawHardFov = !mgr.DrawHardFov;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,11 +709,24 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Toggles shadow rendering.";
|
||||
public string Help => "toggleshadows";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.DrawShadows = !mgr.DrawShadows;
|
||||
return false;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawShadows = !mgr.DrawShadows;
|
||||
}
|
||||
}
|
||||
internal class ToggleLightBuf : IConsoleCommand
|
||||
{
|
||||
public string Command => "togglelightbuf";
|
||||
public string Description => "Toggles lighting rendering. This includes shadows but not FOV.";
|
||||
public string Help => "togglelightbuf";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawLighting = !mgr.DrawLighting;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +736,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Run the GC.";
|
||||
public string Help => "gc [generation]";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
@@ -774,10 +747,21 @@ namespace Robust.Client.Console.Commands
|
||||
if (int.TryParse(args[0], out int result))
|
||||
GC.Collect(result);
|
||||
else
|
||||
console.AddLine("Failed to parse argument.",Color.Red);
|
||||
shell.WriteError("Failed to parse argument.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
internal class GcFullCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "gcf";
|
||||
public string Description => "Run the GC, fully, compacting LOH and everything.";
|
||||
public string Help => "gcf";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||
GC.Collect(2, GCCollectionMode.Forced, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,16 +774,16 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public string Help => "gc_mode\nSee current GC Latencymode\ngc_mode [type]\n Change GC Latency mode to [type]";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var prevMode = GCSettings.LatencyMode;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
console.AddLine($"current gc latency mode: {(int) prevMode} ({prevMode})");
|
||||
console.AddLine("possible modes:");
|
||||
shell.WriteLine($"current gc latency mode: {(int) prevMode} ({prevMode})");
|
||||
shell.WriteLine("possible modes:");
|
||||
foreach (int mode in (int[]) Enum.GetValues(typeof(GCLatencyMode)))
|
||||
{
|
||||
console.AddLine($" {mode}: {Enum.GetName(typeof(GCLatencyMode), mode)}");
|
||||
shell.WriteLine($" {mode}: {Enum.GetName(typeof(GCLatencyMode), mode)}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -811,16 +795,14 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
else if (!Enum.TryParse(args[0], true, out mode))
|
||||
{
|
||||
console.AddLine($"unknown gc latency mode: {args[0]}");
|
||||
return false;
|
||||
shell.WriteLine($"unknown gc latency mode: {args[0]}");
|
||||
return;
|
||||
}
|
||||
|
||||
console.AddLine($"attempting gc latency mode change: {(int) prevMode} ({prevMode}) -> {(int) mode} ({mode})");
|
||||
shell.WriteLine($"attempting gc latency mode change: {(int) prevMode} ({prevMode}) -> {(int) mode} ({mode})");
|
||||
GCSettings.LatencyMode = mode;
|
||||
console.AddLine($"resulting gc latency mode: {(int) GCSettings.LatencyMode} ({GCSettings.LatencyMode})");
|
||||
shell.WriteLine($"resulting gc latency mode: {(int) GCSettings.LatencyMode} ({GCSettings.LatencyMode})");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -834,15 +816,13 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public string Help => "szr_stats";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
|
||||
console.AddLine($"serialized: {RobustSerializer.BytesSerialized} bytes, {RobustSerializer.ObjectsSerialized} objects");
|
||||
console.AddLine($"largest serialized: {RobustSerializer.LargestObjectSerializedBytes} bytes, {RobustSerializer.LargestObjectSerializedType} objects");
|
||||
console.AddLine($"deserialized: {RobustSerializer.BytesDeserialized} bytes, {RobustSerializer.ObjectsDeserialized} objects");
|
||||
console.AddLine($"largest serialized: {RobustSerializer.LargestObjectDeserializedBytes} bytes, {RobustSerializer.LargestObjectDeserializedType} objects");
|
||||
|
||||
return false;
|
||||
shell.WriteLine($"serialized: {RobustSerializer.BytesSerialized} bytes, {RobustSerializer.ObjectsSerialized} objects");
|
||||
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectSerializedBytes} bytes, {RobustSerializer.LargestObjectSerializedType} objects");
|
||||
shell.WriteLine($"deserialized: {RobustSerializer.BytesDeserialized} bytes, {RobustSerializer.ObjectsDeserialized} objects");
|
||||
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectDeserializedBytes} bytes, {RobustSerializer.LargestObjectDeserializedType} objects");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -853,7 +833,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Gets info about a chunk under your mouse cursor.";
|
||||
public string Help => Command;
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
var inputMan = IoCManager.Resolve<IInputManager>();
|
||||
@@ -863,8 +843,8 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
if (!mapMan.TryFindGridAt(mousePos, out var grid))
|
||||
{
|
||||
console.AddLine("No grid under your mouse cursor.");
|
||||
return false;
|
||||
shell.WriteLine("No grid under your mouse cursor.");
|
||||
return;
|
||||
}
|
||||
|
||||
var internalGrid = (IMapGridInternal)grid;
|
||||
@@ -872,8 +852,7 @@ namespace Robust.Client.Console.Commands
|
||||
var chunkIndex = grid.LocalToChunkIndices(grid.MapToGrid(mousePos));
|
||||
var chunk = internalGrid.GetChunk(chunkIndex);
|
||||
|
||||
console.AddLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
|
||||
return false;
|
||||
shell.WriteLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -890,7 +869,7 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public static ConcurrentDictionary<string, bool>? _reloadShadersQueued = new();
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
IResourceCacheInternal resC;
|
||||
if (args.Length == 1)
|
||||
@@ -899,8 +878,8 @@ namespace Robust.Client.Console.Commands
|
||||
{
|
||||
if (_watchers != null)
|
||||
{
|
||||
console.AddLine("Already watching.");
|
||||
return false;
|
||||
shell.WriteLine("Already watching.");
|
||||
return;
|
||||
}
|
||||
resC = IoCManager.Resolve<IResourceCacheInternal>();
|
||||
|
||||
@@ -969,11 +948,11 @@ namespace Robust.Client.Console.Commands
|
||||
{
|
||||
IoCManager.Resolve<IResourceCache>()
|
||||
.ReloadResource<ShaderSourceResource>(resPath);
|
||||
console.AddLine($"Reloaded shader: {resPath}");
|
||||
shell.WriteLine($"Reloaded shader: {resPath}");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
console.AddLine($"Failed to reload shader: {resPath}");
|
||||
shell.WriteLine($"Failed to reload shader: {resPath}");
|
||||
}
|
||||
|
||||
_reloadShadersQueued.TryRemove(ev.FullPath, out var _);
|
||||
@@ -993,17 +972,17 @@ namespace Robust.Client.Console.Commands
|
||||
++created;
|
||||
}
|
||||
|
||||
console.AddLine($"Created {created} shader directory watchers for {shaderCount} shaders.");
|
||||
shell.WriteLine($"Created {created} shader directory watchers for {shaderCount} shaders.");
|
||||
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0] == "-watch")
|
||||
{
|
||||
if (_watchers == null)
|
||||
{
|
||||
console.AddLine("No shader directory watchers active.");
|
||||
return false;
|
||||
shell.WriteLine("No shader directory watchers active.");
|
||||
return;
|
||||
}
|
||||
|
||||
var disposed = 0;
|
||||
@@ -1015,19 +994,19 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
_watchers = null;
|
||||
|
||||
console.AddLine($"Disposed of {disposed} shader directory watchers.");
|
||||
shell.WriteLine($"Disposed of {disposed} shader directory watchers.");
|
||||
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.Length > 1)
|
||||
{
|
||||
console.AddLine("Not implemented.");
|
||||
return false;
|
||||
shell.WriteLine("Not implemented.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.AddLine("Reloading content shader resources...");
|
||||
shell.WriteLine("Reloading content shader resources...");
|
||||
|
||||
resC = IoCManager.Resolve<IResourceCacheInternal>();
|
||||
|
||||
@@ -1039,13 +1018,11 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
console.AddLine($"Failed to reload shader: {path}");
|
||||
shell.WriteLine($"Failed to reload shader: {path}");
|
||||
}
|
||||
}
|
||||
|
||||
console.AddLine("Done.");
|
||||
|
||||
return false;
|
||||
shell.WriteLine("Done.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1056,14 +1033,14 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Toggle fov and light debug layers";
|
||||
public string Help => "cldbglyr <layer>: Toggle <layer>\ncldbglyr: Turn all Layers off";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var clyde = IoCManager.Resolve<IClydeInternal>();
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
clyde.DebugLayers = ClydeDebugLayers.None;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
clyde.DebugLayers = args[0] switch
|
||||
@@ -1072,8 +1049,6 @@ namespace Robust.Client.Console.Commands
|
||||
"light" => ClydeDebugLayers.Light,
|
||||
_ => ClydeDebugLayers.None
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1083,12 +1058,12 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Keys key info for a key";
|
||||
public string Help => "keyinfo <Key>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
console.AddLine(Help);
|
||||
return false;
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
var clyde = IoCManager.Resolve<IClydeInternal>();
|
||||
@@ -1101,15 +1076,13 @@ namespace Robust.Client.Console.Commands
|
||||
var scanCode = clyde.GetKeyScanCode(key);
|
||||
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
|
||||
|
||||
console.AddLine($"name: '{name}' scan code: '{scanCode}' name via scan code: '{nameScanCode}'");
|
||||
shell.WriteLine($"name: '{name}' scan code: '{scanCode}' name via scan code: '{nameScanCode}'");
|
||||
}
|
||||
else if (int.TryParse(args[0], out var scanCode))
|
||||
{
|
||||
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
|
||||
console.AddLine($"name via scan code: '{nameScanCode}'");
|
||||
shell.WriteLine($"name via scan code: '{nameScanCode}'");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -12,23 +11,21 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Dumps a type's members in a format suitable for the sandbox configuration file.";
|
||||
public string Help => "Usage: dmetamem <type>";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var type = Type.GetType(args[0]);
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
console.AddLine("That type does not exist", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("That type does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var sig in AssemblyTypeChecker.DumpMetaMembers(type))
|
||||
{
|
||||
System.Console.WriteLine(@$"- ""{sig}""");
|
||||
console.AddLine(sig);
|
||||
shell.WriteLine(sig);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -12,37 +11,36 @@ namespace Robust.Client.Console.Commands
|
||||
public string Help => "When no arguments are provided, displays a generic help text. When an argument is passed, display the help text for the command with that name.";
|
||||
public string Description => "Display help text.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
switch (args.Length)
|
||||
{
|
||||
case 0:
|
||||
console.AddLine("To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'.");
|
||||
shell.WriteLine("To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'.");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
string commandname = args[0];
|
||||
if (!console.Commands.ContainsKey(commandname))
|
||||
if (!shell.ConsoleHost.RegisteredCommands.ContainsKey(commandname))
|
||||
{
|
||||
if (!IoCManager.Resolve<IClientNetManager>().IsConnected)
|
||||
{
|
||||
// No server so nothing to respond with unknown command.
|
||||
console.AddLine("Unknown command: " + commandname, Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Unknown command: " + commandname);
|
||||
return;
|
||||
}
|
||||
// TODO: Maybe have a server side help?
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
IConsoleCommand command = console.Commands[commandname];
|
||||
console.AddLine(string.Format("{0} - {1}", command.Command, command.Description));
|
||||
console.AddLine(command.Help);
|
||||
IConsoleCommand command = shell.ConsoleHost.RegisteredCommands[commandname];
|
||||
shell.WriteLine(string.Format("{0} - {1}", command.Command, command.Description));
|
||||
shell.WriteLine(command.Help);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.AddLine("Invalid amount of arguments.", Color.Red);
|
||||
shell.WriteError("Invalid amount of arguments.");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +53,7 @@ namespace Robust.Client.Console.Commands
|
||||
"only commands that contain the given string in their name will be listed.";
|
||||
public string Description => "List all commands, optionally with a filter.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var filter = "";
|
||||
if (args.Length == 1)
|
||||
@@ -64,14 +62,12 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
|
||||
var conGroup = IoCManager.Resolve<IClientConGroupController>();
|
||||
foreach (var command in console.Commands.Values
|
||||
foreach (var command in shell.ConsoleHost.RegisteredCommands.Values
|
||||
.Where(p => p.Command.Contains(filter) && conGroup.CanCommand(p.Command))
|
||||
.OrderBy(c => c.Command))
|
||||
{
|
||||
console.AddLine(command.Command + ": " + command.Description);
|
||||
shell.WriteLine(command.Command + ": " + command.Description);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
Robust.Client/Console/Commands/LauncherAuthCommand.cs
Normal file
67
Robust.Client/Console/Commands/LauncherAuthCommand.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
#if !FULL_RELEASE
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
internal sealed class LauncherAuthCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "launchauth";
|
||||
public string Description => "Load authentication tokens from launcher data to aid in testing of live servers";
|
||||
public string Help => "launchauth [account name]";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var wantName = args.Length > 0 ? args[0] : null;
|
||||
|
||||
var basePath = Path.GetDirectoryName(UserDataDir.GetUserDataDir())!;
|
||||
var cfgPath = Path.Combine(basePath, "launcher", "launcher_config.json");
|
||||
|
||||
var data = JsonSerializer.Deserialize<LauncherConfig>(File.ReadAllText(cfgPath))!;
|
||||
|
||||
var login = wantName != null
|
||||
? data.Logins.FirstOrDefault(p => p.Username == wantName)
|
||||
: data.Logins.FirstOrDefault();
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
shell.WriteLine("Unable to find a matching login");
|
||||
return;
|
||||
}
|
||||
|
||||
var token = login.Token.Token;
|
||||
var userId = login.UserId;
|
||||
|
||||
var cfg = IoCManager.Resolve<IAuthManager>();
|
||||
cfg.Token = token;
|
||||
cfg.UserId = new NetUserId(Guid.Parse(userId));
|
||||
}
|
||||
|
||||
private sealed class LauncherConfig
|
||||
{
|
||||
[JsonInclude] [JsonPropertyName("logins")]
|
||||
public LauncherLogin[] Logins = default!;
|
||||
}
|
||||
|
||||
private sealed class LauncherLogin
|
||||
{
|
||||
[JsonInclude] public string Username = default!;
|
||||
[JsonInclude] public string UserId = default!;
|
||||
[JsonInclude] public LauncherToken Token = default!;
|
||||
}
|
||||
|
||||
private sealed class LauncherToken
|
||||
{
|
||||
[JsonInclude] public string Token = default!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -13,18 +12,16 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Lists loaded assemblies by load context.";
|
||||
public string Help => Command;
|
||||
|
||||
public bool Execute(IDebugConsole console, string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
foreach (var context in AssemblyLoadContext.All)
|
||||
{
|
||||
console.AddLine($"{context.Name}:");
|
||||
shell.WriteLine($"{context.Name}:");
|
||||
foreach (var assembly in context.Assemblies.OrderBy(a => a.FullName))
|
||||
{
|
||||
console.AddLine($" {assembly.FullName}");
|
||||
shell.WriteLine($" {assembly.FullName}");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Log;
|
||||
using System;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -13,12 +12,12 @@ namespace Robust.Client.Console.Commands
|
||||
+ "\n sawmill: A label prefixing log messages. This is the one you're setting the level for."
|
||||
+ "\n level: The log level. Must match one of the values of the LogLevel enum.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
console.AddLine("Invalid argument amount. Expected 2 arguments.", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Invalid argument amount. Expected 2 arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
@@ -32,13 +31,12 @@ namespace Robust.Client.Console.Commands
|
||||
{
|
||||
if (!Enum.TryParse<LogLevel>(levelname, out var result))
|
||||
{
|
||||
console.AddLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
|
||||
return false;
|
||||
shell.WriteLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
|
||||
return;
|
||||
}
|
||||
level = result;
|
||||
}
|
||||
Logger.GetSawmill(name).Level = level;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +49,12 @@ namespace Robust.Client.Console.Commands
|
||||
+ "\n level: The log level. Must match one of the values of the LogLevel enum."
|
||||
+ "\n message: The message to be logged. Wrap this in double quotes if you want to use spaces.";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 3)
|
||||
{
|
||||
console.AddLine("Invalid argument amount. Expected 3 arguments.", Color.Red);
|
||||
return false;
|
||||
shell.WriteError("Invalid argument amount. Expected 3 arguments.");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
@@ -64,13 +62,12 @@ namespace Robust.Client.Console.Commands
|
||||
var message = args[2]; // yes this doesn't support spaces idgaf.
|
||||
if (!Enum.TryParse<LogLevel>(levelname, out var result))
|
||||
{
|
||||
console.AddLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
|
||||
return false;
|
||||
shell.WriteLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
|
||||
return;
|
||||
}
|
||||
var level = result;
|
||||
|
||||
Logger.LogS(level, name, message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using System;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -9,10 +9,9 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Kills the game client instantly.";
|
||||
public string Help => "Kills the game client instantly, leaving no traces. No telling the server goodbye";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
#if CLIENT_SCRIPTING
|
||||
internal sealed class ScriptConsoleCommand : IConsoleCommand
|
||||
internal sealed class ScriptCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "csi";
|
||||
public string Description => "Opens a C# interactive console.";
|
||||
public string Help => "csi";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
new ScriptConsoleClient().OpenCentered();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,33 +23,29 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Opens a variable watch window.";
|
||||
public string Help => "watch";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
new WatchWindow().OpenCentered();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal sealed class ServerScriptConsoleCommand : IConsoleCommand
|
||||
internal sealed class ServerScriptCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "scsi";
|
||||
public string Description => "Opens a C# interactive console on the server.";
|
||||
public string Help => "scsi";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IScriptClient>();
|
||||
if (!mgr.CanScript)
|
||||
{
|
||||
console.AddLine(Loc.GetString("You do not have server side scripting permission."), Color.Red);
|
||||
return false;
|
||||
shell.WriteError(Loc.GetString("You do not have server side scripting permission."));
|
||||
return;
|
||||
}
|
||||
|
||||
mgr.StartSession();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
@@ -11,7 +10,7 @@ namespace Robust.Client.Console.Commands
|
||||
public string Description => "Sends garbage to the server.";
|
||||
public string Help => "The server will reply with 'no u'";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
// MsgStringTableEntries is registered as NetMessageAccept.Client so the server will immediately deny it.
|
||||
// And kick us.
|
||||
@@ -19,8 +18,6 @@ namespace Robust.Client.Console.Commands
|
||||
var msg = net.CreateNetMessage<MsgStringTableEntries>();
|
||||
msg.Entries = new MsgStringTableEntries.Entry[0];
|
||||
net.ClientSendMessage(msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
Robust.Client/Console/Commands/SetInputContextCommand.cs
Normal file
34
Robust.Client/Console/Commands/SetInputContextCommand.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class SetInputContextCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "setinputcontext";
|
||||
public string Description => "Sets the active input context.";
|
||||
public string Help => "setinputcontext <context>";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteLine("Invalid number of arguments!");
|
||||
return;
|
||||
}
|
||||
|
||||
var inputMan = IoCManager.Resolve<IInputManager>();
|
||||
|
||||
if (!inputMan.Contexts.Exists(args[0]))
|
||||
{
|
||||
shell.WriteLine("Context not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
inputMan.Contexts.SetActiveContext(args[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public interface IClientConGroupController : IClientConGroupImplementation
|
||||
{
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public interface IClientConsole : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the console into a useable state.
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the console to a post-initialized state.
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
|
||||
event EventHandler<AddStringArgs> AddString;
|
||||
event EventHandler<AddFormattedMessageArgs> AddFormatted;
|
||||
event EventHandler ClearText;
|
||||
|
||||
IReadOnlyDictionary<string, IConsoleCommand> Commands { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parses console commands (verbs).
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
void ProcessCommand(string text);
|
||||
|
||||
void SendServerCommandRequest();
|
||||
}
|
||||
}
|
||||
24
Robust.Client/Console/IClientConsoleHost.cs
Normal file
24
Robust.Client/Console/IClientConsoleHost.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
public interface IClientConsoleHost : IConsoleHost, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the console into a useable state.
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the console to a post-initialized state.
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
event EventHandler<AddStringArgs> AddString;
|
||||
event EventHandler<AddFormattedMessageArgs> AddFormatted;
|
||||
|
||||
void AddFormattedLine(FormattedMessage message);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
|
||||
@@ -10,10 +10,10 @@ using Microsoft.CodeAnalysis.Scripting;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.ViewVariables;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Scripting;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ using Microsoft.CodeAnalysis.Scripting;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Scripting;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
@@ -26,6 +18,7 @@ namespace Robust.Client.Debugging
|
||||
[Dependency] private readonly IComponentManager _componentManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPhysicsManager _physicsManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
|
||||
@@ -48,7 +41,7 @@ namespace Robust.Client.Debugging
|
||||
if (value)
|
||||
{
|
||||
_overlayManager.AddOverlay(new PhysicsOverlay(_componentManager, _eyeManager,
|
||||
_prototypeManager, _inputManager));
|
||||
_prototypeManager, _inputManager, _physicsManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -86,6 +79,7 @@ namespace Robust.Client.Debugging
|
||||
private readonly IComponentManager _componentManager;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
private readonly IInputManager _inputManager;
|
||||
private readonly IPhysicsManager _physicsManager;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace;
|
||||
private readonly ShaderInstance _shader;
|
||||
@@ -94,12 +88,13 @@ namespace Robust.Client.Debugging
|
||||
private Vector2 _hoverStartScreen = Vector2.Zero;
|
||||
private List<IPhysBody> _hoverBodies = new();
|
||||
|
||||
public PhysicsOverlay(IComponentManager compMan, IEyeManager eyeMan, IPrototypeManager protoMan, IInputManager inputManager)
|
||||
public PhysicsOverlay(IComponentManager compMan, IEyeManager eyeMan, IPrototypeManager protoMan, IInputManager inputManager, IPhysicsManager physicsManager)
|
||||
: base(nameof(PhysicsOverlay))
|
||||
{
|
||||
_componentManager = compMan;
|
||||
_eyeManager = eyeMan;
|
||||
_inputManager = inputManager;
|
||||
_physicsManager = physicsManager;
|
||||
|
||||
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
@@ -158,23 +153,20 @@ namespace Robust.Client.Debugging
|
||||
_hoverStartScreen = mouseScreenPos;
|
||||
|
||||
var viewport = _eyeManager.GetWorldViewport();
|
||||
foreach (var boundingBox in _componentManager.EntityQuery<IPhysicsComponent>())
|
||||
{
|
||||
var physBody = (IPhysBody) boundingBox;
|
||||
|
||||
if (viewport.IsEmpty()) return;
|
||||
|
||||
var mapId = _eyeManager.CurrentMap;
|
||||
|
||||
foreach (var physBody in _physicsManager.GetCollidingEntities(mapId, viewport))
|
||||
{
|
||||
// all entities have a TransformComponent
|
||||
var transform = physBody.Entity.Transform;
|
||||
|
||||
// if not on the same map, continue
|
||||
if (transform.MapID != _eyeManager.CurrentMap || !transform.IsMapTransform)
|
||||
continue;
|
||||
|
||||
var worldBox = physBody.WorldAABB;
|
||||
var colorEdge = Color.Red.WithAlpha(0.33f);
|
||||
if (worldBox.IsEmpty()) continue;
|
||||
|
||||
// if not on screen, or too small, continue
|
||||
if (!worldBox.Intersects(in viewport) || worldBox.IsEmpty())
|
||||
continue;
|
||||
var colorEdge = Color.Red.WithAlpha(0.33f);
|
||||
|
||||
foreach (var shape in physBody.PhysicsShapes)
|
||||
{
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Client.Debugging
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Robust.Client.Interfaces.Debugging
|
||||
namespace Robust.Client.Debugging
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of visual debug overlays for the client game.
|
||||
@@ -1,11 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.Interfaces.Debugging
|
||||
namespace Robust.Client.Debugging
|
||||
{
|
||||
public interface IDebugDrawingManager
|
||||
{
|
||||
@@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.Placement;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Interfaces.Utility;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Client.ViewVariables;
|
||||
using Robust.LoaderApi;
|
||||
@@ -22,16 +19,14 @@ using Robust.Shared;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Interfaces.Timers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -49,7 +44,7 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IUserInterfaceManagerInternal _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IClientConsole _console = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly ITimerManager _timerManager = default!;
|
||||
[Dependency] private readonly IClientEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlacementManager _placementManager = default!;
|
||||
@@ -65,6 +60,8 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IScriptClient _scriptClient = default!;
|
||||
[Dependency] private readonly IComponentManager _componentManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IRobustMappedStringSerializer _stringSerializer = default!;
|
||||
[Dependency] private readonly IAuthManager _authManager = default!;
|
||||
|
||||
private CommandLineArgs? _commandLineArgs;
|
||||
private bool _disableAssemblyLoadContext;
|
||||
@@ -125,6 +122,7 @@ namespace Robust.Client
|
||||
ProgramShared.DoMounts(_resourceCache, _commandLineArgs?.MountOptions, "Content.Client", _loaderArgs != null);
|
||||
if (_loaderArgs != null)
|
||||
{
|
||||
_stringSerializer.EnableCaching = false;
|
||||
_resourceCache.MountLoaderApi(_loaderArgs.FileApi, "Resources/");
|
||||
_modLoader.VerifierExtraLoadHandler = VerifierExtraLoadHandler;
|
||||
}
|
||||
@@ -161,9 +159,10 @@ namespace Robust.Client
|
||||
|
||||
_userInterfaceManager.Initialize();
|
||||
_networkManager.Initialize(false);
|
||||
IoCManager.Resolve<INetConfigurationManager>().SetupNetworking();
|
||||
_serializer.Initialize();
|
||||
_inputManager.Initialize();
|
||||
_console.Initialize();
|
||||
_consoleHost.Initialize();
|
||||
_prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes/"));
|
||||
_prototypeManager.Resync();
|
||||
_mapManager.Initialize();
|
||||
@@ -182,6 +181,8 @@ namespace Robust.Client
|
||||
_client.PlayerNameOverride = _commandLineArgs.Username;
|
||||
}
|
||||
|
||||
_authManager.LoadFromEnv();
|
||||
|
||||
_clyde.Ready();
|
||||
|
||||
if ((_commandLineArgs?.Connect == true || _commandLineArgs?.Launcher == true)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Input;
|
||||
|
||||
namespace Robust.Client
|
||||
{
|
||||
|
||||
@@ -1,67 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics.Lighting;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Debugging;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.Lighting;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.Map;
|
||||
using Robust.Client.Interfaces.Placement;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Interfaces.Utility;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.Reflection;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Client.ViewVariables;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Interfaces.Timers;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Reflection;
|
||||
|
||||
namespace Robust.Client
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client;
|
||||
using Robust.Client;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
[assembly: LoaderEntryPoint(typeof(GameController.LoaderEntryPoint))]
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client
|
||||
{
|
||||
public void Main(IMainArgs args)
|
||||
{
|
||||
GameController.Start(args.Args, contentStart: false, args);
|
||||
Start(args.Args, contentStart: false, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using Robust.Client.Interfaces;
|
||||
using System;
|
||||
using Robust.LoaderApi;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
3
Robust.Client/GameObjects/!NO_FOLDER_NAMESPACES
Normal file
3
Robust.Client/GameObjects/!NO_FOLDER_NAMESPACES
Normal file
@@ -0,0 +1,3 @@
|
||||
Everything in this folder and subfolders needs to be in:
|
||||
|
||||
Robust.Client.GameObjects
|
||||
@@ -1,18 +1,4 @@
|
||||
using Robust.Client.GameObjects.Components;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Client.GameObjects.Components.Containers;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Components.Appearance;
|
||||
using Robust.Shared.GameObjects.Components.Eye;
|
||||
using Robust.Shared.GameObjects.Components.Map;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.GameObjects.Components.Timers;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
@@ -55,15 +41,13 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
Register<AppearanceComponent>();
|
||||
RegisterReference<AppearanceComponent, SharedAppearanceComponent>();
|
||||
|
||||
|
||||
Register<AppearanceTestComponent>();
|
||||
Register<SnapGridComponent>();
|
||||
|
||||
Register<ClientUserInterfaceComponent>();
|
||||
RegisterReference<ClientUserInterfaceComponent, SharedUserInterfaceComponent>();
|
||||
|
||||
RegisterIgnore("IgnorePause");
|
||||
|
||||
Register<AnimationPlayerComponent>();
|
||||
|
||||
Register<ContainerManagerComponent>();
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
|
||||
@@ -5,7 +5,7 @@ using Robust.Client.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using static Robust.Client.Animations.AnimationPlaybackShared;
|
||||
|
||||
namespace Robust.Client.GameObjects.Components.Animations
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Plays back <see cref="Animation"/>s on entities.
|
||||
@@ -48,11 +48,21 @@ namespace Robust.Client.GameObjects.Components.Animations
|
||||
return;
|
||||
}
|
||||
|
||||
List<string>? toRemove = null;
|
||||
// TODO: Get rid of this ToArray() allocation.
|
||||
foreach (var (key, playback) in _playingAnimations.ToArray())
|
||||
{
|
||||
var keep = UpdatePlayback(Owner, playback, frameTime);
|
||||
if (!keep)
|
||||
{
|
||||
toRemove ??= new List<string>();
|
||||
toRemove.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove != null)
|
||||
{
|
||||
foreach (var key in toRemove)
|
||||
{
|
||||
_playingAnimations.Remove(key);
|
||||
AnimationCompleted?.Invoke(key);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Appearance;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -54,17 +50,17 @@ namespace Robust.Client.GameObjects
|
||||
return (T) data[key];
|
||||
}
|
||||
|
||||
public override bool TryGetData<T>(Enum key, [MaybeNullWhen(false)] out T data)
|
||||
public override bool TryGetData<T>(Enum key, [NotNullWhen(true)] out T data)
|
||||
{
|
||||
return TryGetData(key, out data);
|
||||
}
|
||||
|
||||
public override bool TryGetData<T>(string key, [MaybeNullWhen(false)] out T data)
|
||||
public override bool TryGetData<T>(string key, [NotNullWhen(true)] out T data)
|
||||
{
|
||||
return TryGetData(key, out data);
|
||||
}
|
||||
|
||||
internal bool TryGetData<T>(object key, [MaybeNullWhen(false)] out T data)
|
||||
internal bool TryGetData<T>(object key, [NotNullWhen(true)] out T data)
|
||||
{
|
||||
if (this.data.TryGetValue(key, out var dat))
|
||||
{
|
||||
@@ -72,12 +68,14 @@ namespace Robust.Client.GameObjects
|
||||
return true;
|
||||
}
|
||||
|
||||
data = default;
|
||||
data = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetData(object key, object value)
|
||||
{
|
||||
if (data.TryGetValue(key, out var existing) && existing.Equals(value)) return;
|
||||
|
||||
data[key] = value;
|
||||
|
||||
MarkDirty();
|
||||
@@ -85,10 +83,9 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
if (curState == null)
|
||||
if (curState is not AppearanceComponentState actualState)
|
||||
return;
|
||||
|
||||
var actualState = (AppearanceComponentState) curState;
|
||||
data = actualState.Data;
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects.Components.Containers
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public sealed partial class ContainerManagerComponent
|
||||
{
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Containers;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects.Components.Containers
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public sealed partial class ContainerManagerComponent : SharedContainerManagerComponent
|
||||
{
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Eye;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -31,11 +31,11 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
private static IDirectionalTextureProvider TextureForConfig(ObjectSerializer serializer, IResourceCache resourceCache)
|
||||
private static IRsiStateLike TextureForConfig(ObjectSerializer serializer, IResourceCache resourceCache)
|
||||
{
|
||||
DebugTools.Assert(serializer.Reading);
|
||||
|
||||
if (serializer.TryGetCacheData<IDirectionalTextureProvider>(SerializationCache, out var dirTex))
|
||||
if (serializer.TryGetCacheData<IRsiStateLike>(SerializationCache, out var dirTex))
|
||||
{
|
||||
return dirTex;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public static IDirectionalTextureProvider? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
|
||||
public static IRsiStateLike? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
|
||||
{
|
||||
if (!prototype.Components.TryGetValue("Icon", out var mapping))
|
||||
{
|
||||
|
||||
11
Robust.Client/GameObjects/Components/IgnorePauseComponent.cs
Normal file
11
Robust.Client/GameObjects/Components/IgnorePauseComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedIgnorePauseComponent))]
|
||||
public sealed class IgnorePauseComponent : SharedIgnorePauseComponent
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects.Components
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines data fields used in the <see cref="InputSystem"/>.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
@@ -83,6 +80,18 @@ namespace Robust.Client.GameObjects
|
||||
set => _energy = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Soft shadow strength multiplier.
|
||||
/// Has no effect if soft shadows are not enabled.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[Animatable]
|
||||
public float Softness
|
||||
{
|
||||
get => _softness;
|
||||
set => _softness = value;
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool VisibleNested
|
||||
{
|
||||
@@ -115,6 +124,7 @@ namespace Robust.Client.GameObjects
|
||||
private bool _maskAutoRotate;
|
||||
private Angle _rotation;
|
||||
private float _energy;
|
||||
private float _softness;
|
||||
|
||||
/// <summary>
|
||||
/// Radius, in meters.
|
||||
@@ -167,6 +177,7 @@ namespace Robust.Client.GameObjects
|
||||
serializer.DataFieldCached(ref _color, "color", Color.White);
|
||||
serializer.DataFieldCached(ref _enabled, "enabled", true);
|
||||
serializer.DataFieldCached(ref _energy, "energy", 1f);
|
||||
serializer.DataFieldCached(ref _softness, "softness", 1f);
|
||||
serializer.DataFieldCached(ref _maskAutoRotate, "autoRot", false);
|
||||
serializer.DataFieldCached(ref _visibleNested, "nestedvisible", true);
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Interfaces.GameObjects
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface IRenderableComponent : IComponent
|
||||
{
|
||||
@@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Interfaces.GameObjects.Components
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface ISpriteComponent : IComponent, IAnimationProperties
|
||||
{
|
||||
@@ -205,29 +203,4 @@ namespace Robust.Client.Interfaces.GameObjects.Components
|
||||
|
||||
IEnumerable<ISpriteLayer> AllLayers { get; }
|
||||
}
|
||||
|
||||
public interface ISpriteLayer
|
||||
{
|
||||
SpriteComponent.DirectionOffset DirOffset { get; set; }
|
||||
|
||||
RSI? Rsi { get; set; }
|
||||
RSI.StateId RsiState { get; set; }
|
||||
RSI? ActualRsi { get; }
|
||||
|
||||
Texture? Texture { get; set; }
|
||||
|
||||
Angle Rotation { get; set; }
|
||||
Vector2 Scale { get; set; }
|
||||
|
||||
bool Visible { get; set; }
|
||||
Color Color { get; set; }
|
||||
|
||||
float AnimationTime { get; set; }
|
||||
int AnimationFrame { get; }
|
||||
bool AutoAnimated { get; set; }
|
||||
|
||||
RSI.State.Direction EffectiveDirection(Angle worldRotation);
|
||||
|
||||
Vector2 LocalToLayer(Vector2 localPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface ISpriteLayer
|
||||
{
|
||||
SpriteComponent.DirectionOffset DirOffset { get; set; }
|
||||
|
||||
RSI? Rsi { get; set; }
|
||||
RSI.StateId RsiState { get; set; }
|
||||
RSI? ActualRsi { get; }
|
||||
|
||||
Texture? Texture { get; set; }
|
||||
|
||||
Angle Rotation { get; set; }
|
||||
Vector2 Scale { get; set; }
|
||||
|
||||
bool Visible { get; set; }
|
||||
Color Color { get; set; }
|
||||
|
||||
float AnimationTime { get; set; }
|
||||
int AnimationFrame { get; }
|
||||
bool AutoAnimated { get; set; }
|
||||
|
||||
RSI.State.Direction EffectiveDirection(Angle worldRotation);
|
||||
|
||||
Vector2 LocalToLayer(Vector2 localPos);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,24 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
|
||||
|
||||
@@ -197,34 +188,34 @@ namespace Robust.Client.GameObjects
|
||||
public void CopyFrom(SpriteComponent other)
|
||||
{
|
||||
//deep copying things to avoid entanglement
|
||||
this._baseRsi = other._baseRsi;
|
||||
this._directional = other._directional;
|
||||
this._visible = other._visible;
|
||||
this._layerMapShared = other._layerMapShared;
|
||||
this.color = other.color;
|
||||
this.offset = other.offset;
|
||||
this.rotation = other.rotation;
|
||||
this.scale = other.scale;
|
||||
this.drawDepth = other.drawDepth;
|
||||
this.Layers = new List<Layer>(other.Layers.Count);
|
||||
_baseRsi = other._baseRsi;
|
||||
_directional = other._directional;
|
||||
_visible = other._visible;
|
||||
_layerMapShared = other._layerMapShared;
|
||||
color = other.color;
|
||||
offset = other.offset;
|
||||
rotation = other.rotation;
|
||||
scale = other.scale;
|
||||
drawDepth = other.drawDepth;
|
||||
Layers = new List<Layer>(other.Layers.Count);
|
||||
foreach (var otherLayer in other.Layers)
|
||||
{
|
||||
this.Layers.Add(new Layer(otherLayer, this));
|
||||
Layers.Add(new Layer(otherLayer, this));
|
||||
}
|
||||
this.IsInert = other.IsInert;
|
||||
this.LayerMap = other.LayerMap.ToDictionary(entry => entry.Key,
|
||||
IsInert = other.IsInert;
|
||||
LayerMap = other.LayerMap.ToDictionary(entry => entry.Key,
|
||||
entry => entry.Value);
|
||||
if (other.PostShader != null)
|
||||
{
|
||||
// only need to copy the shader if it's mutable
|
||||
this.PostShader = other.PostShader.Mutable ? other.PostShader.Duplicate() : other.PostShader;
|
||||
PostShader = other.PostShader.Mutable ? other.PostShader.Duplicate() : other.PostShader;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PostShader = null;
|
||||
PostShader = null;
|
||||
}
|
||||
|
||||
this.RenderOrder = other.RenderOrder;
|
||||
RenderOrder = other.RenderOrder;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -991,6 +982,9 @@ namespace Robust.Client.GameObjects
|
||||
var mRotation = Matrix3.CreateRotation(angle);
|
||||
Matrix3.Multiply(ref mRotation, ref mOffset, out var transform);
|
||||
|
||||
// Only apply scale if needed.
|
||||
if(!Scale.EqualsApprox(Vector2.One)) transform.Multiply(Matrix3.CreateScale(Scale));
|
||||
|
||||
transform.Multiply(worldTransform);
|
||||
|
||||
RenderInternal(drawingHandle, worldRotation, overrideDirection, transform);
|
||||
@@ -1043,7 +1037,7 @@ namespace Robust.Client.GameObjects
|
||||
var rsi = layer.RSI ?? BaseRSI;
|
||||
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
|
||||
{
|
||||
state = GetFallbackState();
|
||||
state = GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
var layerSpecificDir = layer.EffectiveDirection(state, worldRotation, overrideDirection);
|
||||
@@ -1276,7 +1270,7 @@ namespace Robust.Client.GameObjects
|
||||
var rsi = layer.RSI ?? BaseRSI;
|
||||
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
|
||||
{
|
||||
state = GetFallbackState();
|
||||
state = GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
if (!state.IsAnimated)
|
||||
@@ -1404,7 +1398,7 @@ namespace Robust.Client.GameObjects
|
||||
var rsi = layer.RSI ?? BaseRSI;
|
||||
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
|
||||
{
|
||||
state = GetFallbackState();
|
||||
state = GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
if (state.IsAnimated)
|
||||
@@ -1415,9 +1409,9 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
private RSI.State GetFallbackState()
|
||||
internal static RSI.State GetFallbackState(IResourceCache cache)
|
||||
{
|
||||
var rsi = resourceCache.GetResource<RSIResource>("/Textures/error.rsi").RSI;
|
||||
var rsi = cache.GetResource<RSIResource>("/Textures/error.rsi").RSI;
|
||||
return rsi["error"];
|
||||
}
|
||||
|
||||
@@ -1735,14 +1729,14 @@ namespace Robust.Client.GameObjects
|
||||
var rsi = ActualRsi;
|
||||
if (rsi == null)
|
||||
{
|
||||
state = _parent.GetFallbackState();
|
||||
state = GetFallbackState(_parent.resourceCache);
|
||||
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rsi.TryGetState(stateId, out state))
|
||||
{
|
||||
state = _parent.GetFallbackState();
|
||||
state = GetFallbackState(_parent.resourceCache);
|
||||
Logger.ErrorS(LogCategory, "State '{0}' does not exist in RSI. Trace:\n{1}", stateId,
|
||||
Environment.StackTrace);
|
||||
}
|
||||
@@ -1793,7 +1787,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public IDirectionalTextureProvider? Icon
|
||||
public IRsiStateLike? Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -1803,13 +1797,13 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
var texture = layer.Texture;
|
||||
|
||||
if (!layer.State.IsValid) return null;
|
||||
if (!layer.State.IsValid) return texture;
|
||||
|
||||
// Pull texture from RSI state instead.
|
||||
var rsi = layer.RSI ?? BaseRSI;
|
||||
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
|
||||
{
|
||||
state = GetFallbackState();
|
||||
state = GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
return state;
|
||||
@@ -1867,21 +1861,21 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
}
|
||||
|
||||
public static IDirectionalTextureProvider? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
|
||||
public static IRsiStateLike GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
|
||||
{
|
||||
var icon = IconComponent.GetPrototypeIcon(prototype, resourceCache);
|
||||
if (icon != null) return icon;
|
||||
|
||||
if (!prototype.Components.TryGetValue("Sprite", out var spriteNode))
|
||||
if (!prototype.Components.ContainsKey("Sprite"))
|
||||
{
|
||||
return resourceCache.GetFallback<TextureResource>().Texture;
|
||||
return GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
var dummy = new DummyIconEntity() {Prototype = prototype};
|
||||
var dummy = new DummyIconEntity {Prototype = prototype};
|
||||
var spriteComponent = dummy.AddComponent<SpriteComponent>();
|
||||
dummy.Delete();
|
||||
|
||||
return spriteComponent?.Icon ?? resourceCache.GetFallback<TextureResource>().Texture;
|
||||
return spriteComponent.Icon ?? GetFallbackState(resourceCache);
|
||||
}
|
||||
|
||||
#region DummyIconEntity
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using IComponent = Robust.Shared.Interfaces.GameObjects.IComponent;
|
||||
|
||||
namespace Robust.Client.GameObjects.Components.UserInterface
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class ClientUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
internal sealed class AnimationPlayerSystem : EntitySystem
|
||||
{
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
foreach (var animationPlayerComponent in EntityManager.ComponentManager.EntityQuery<AnimationPlayerComponent>())
|
||||
foreach (var animationPlayerComponent in EntityManager.ComponentManager.EntityQuery<AnimationPlayerComponent>(true))
|
||||
{
|
||||
animationPlayerComponent.Update(frameTime);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
internal sealed class AppearanceSystem : EntitySystem
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
class AppearanceTestSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var appearanceTestComponent in EntityManager.ComponentManager.EntityQuery<AppearanceTestComponent>())
|
||||
foreach (var appearanceTestComponent in EntityManager.ComponentManager.EntityQuery<AppearanceTestComponent>(true))
|
||||
{
|
||||
appearanceTestComponent.OnUpdate(frameTime);
|
||||
}
|
||||
|
||||
@@ -2,23 +2,18 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class AudioSystem : EntitySystem
|
||||
@@ -56,12 +51,12 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
|
||||
private void PlayAudioPositionalHandler(PlayAudioPositionalMessage ev)
|
||||
{
|
||||
var gridId = ev.Coordinates.GetGridId(_entityManager);
|
||||
|
||||
if (!_mapManager.GridExists(gridId))
|
||||
var mapId = ev.Coordinates.GetMapId(_entityManager);
|
||||
|
||||
if (!_mapManager.MapExists(mapId))
|
||||
{
|
||||
Logger.Error(
|
||||
$"Server tried to play sound on grid {gridId}, which does not exist. Ignoring.");
|
||||
$"Server tried to play sound on map {mapId}, which does not exist. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,13 +106,13 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
if (stream.TrackingCoordinates != null)
|
||||
{
|
||||
var coords = stream.TrackingCoordinates.Value;
|
||||
if (_mapManager.GridExists(coords.GetGridId(_entityManager)))
|
||||
if (_mapManager.MapExists(coords.GetMapId(_entityManager)))
|
||||
{
|
||||
mapPos = stream.TrackingCoordinates.Value.ToMap(_entityManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Grid no longer exists, delete stream.
|
||||
// Map no longer exists, delete stream.
|
||||
StreamDone(stream);
|
||||
continue;
|
||||
}
|
||||
@@ -356,4 +351,76 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
|
||||
event Action PlaybackDone;
|
||||
}
|
||||
|
||||
public static class AudioSystemExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Play an audio file following an entity.
|
||||
/// </summary>
|
||||
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
|
||||
/// <param name="entity">The entity "emitting" the audio.</param>
|
||||
/// <param name="audioParams"></param>
|
||||
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
|
||||
public static IPlayingAudioStream? Play(
|
||||
this IEntity entity,
|
||||
string filename,
|
||||
AudioParams? audioParams,
|
||||
AudioSystem? audioSystem = null)
|
||||
{
|
||||
audioSystem ??= EntitySystem.Get<AudioSystem>();
|
||||
return audioSystem.Play(filename, entity, audioParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play an audio stream following an entity.
|
||||
/// </summary>
|
||||
/// <param name="stream">The audio stream to play.</param>
|
||||
/// <param name="entity">The entity "emitting" the audio.</param>
|
||||
/// <param name="audioParams"></param>
|
||||
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
|
||||
public static IPlayingAudioStream? Play(
|
||||
this IEntity entity,
|
||||
AudioStream stream,
|
||||
AudioParams? audioParams = null,
|
||||
AudioSystem? audioSystem = null)
|
||||
{
|
||||
audioSystem ??= EntitySystem.Get<AudioSystem>();
|
||||
return audioSystem.Play(stream, entity, audioParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play an audio file at a static position.
|
||||
/// </summary>
|
||||
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
|
||||
/// <param name="coordinates">The coordinates at which to play the audio.</param>
|
||||
/// <param name="audioParams"></param>
|
||||
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
|
||||
public static IPlayingAudioStream? Play(
|
||||
this EntityCoordinates coordinates,
|
||||
string filename,
|
||||
AudioParams? audioParams = null,
|
||||
AudioSystem? audioSystem = null)
|
||||
{
|
||||
audioSystem ??= EntitySystem.Get<AudioSystem>();
|
||||
return audioSystem.Play(filename, coordinates, audioParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play an audio stream at a static position.
|
||||
/// </summary>
|
||||
/// <param name="stream">The audio stream to play.</param>
|
||||
/// <param name="coordinates">The coordinates at which to play the audio.</param>
|
||||
/// <param name="audioParams"></param>
|
||||
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
|
||||
public static IPlayingAudioStream? Play(
|
||||
this EntityCoordinates coordinates,
|
||||
AudioStream stream,
|
||||
AudioParams? audioParams = null,
|
||||
AudioSystem? audioSystem = null)
|
||||
{
|
||||
audioSystem ??= EntitySystem.Get<AudioSystem>();
|
||||
return audioSystem.Play(stream, coordinates, audioParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,11 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Physics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
// NOTE: this class handles both snap grid updates of occluders, as well as occluder tree updates (via its parent).
|
||||
// This seems like it's doing somewhat double work because it already has an update queue for occluders but...
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class ContainerSystem : EntitySystem
|
||||
{
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects.EntitySystemMessages;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
@@ -57,47 +47,54 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public void CreateEffect(EffectSystemMessage message)
|
||||
{
|
||||
// The source of effects is either local actions during FirstTimePredicted, or the network at LastServerTick
|
||||
// When replaying predicted input, don't spam effects.
|
||||
if(gameTiming.InPrediction && !gameTiming.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (message.AttachedEntityUid != null && message.Coordinates != default)
|
||||
{
|
||||
Logger.Warning("Set both an AttachedEntityUid and EntityCoordinates on an EffectSystemMessage for sprite {0} which is not supported!", message.EffectSprite);
|
||||
}
|
||||
|
||||
var gameTime = gameTiming.CurTime;
|
||||
if (gameTime > message.DeathTime) //Did we already die in transit? That's pretty troubling isn't it
|
||||
if (message.LifeTime <= TimeSpan.Zero)
|
||||
{
|
||||
Logger.Warning("Effect using sprite {0} died in transit to the client", message.EffectSprite);
|
||||
Logger.Warning("Effect using sprite {0} had zero lifetime.", message.EffectSprite);
|
||||
return;
|
||||
}
|
||||
|
||||
//Create effect from creation message
|
||||
var effect = new Effect(message, resourceCache, _mapManager, _entityManager);
|
||||
effect.Deathtime = gameTiming.CurTime + message.LifeTime;
|
||||
if (effect.AttachedEntityUid != null)
|
||||
{
|
||||
effect.AttachedEntity = _entityManager.GetEntity(effect.AttachedEntityUid.Value);
|
||||
}
|
||||
|
||||
//Age the effect through a single update to the previous update tick of the effect system
|
||||
//effect.Update((float)((lasttimeprocessed - effect.Age).TotalSeconds));
|
||||
|
||||
_Effects.Add(effect);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
var curTime = gameTiming.CurTime;
|
||||
for (int i = 0; i < _Effects.Count; i++)
|
||||
{
|
||||
var effect = _Effects[i];
|
||||
|
||||
//Update variables of the effect via its deltas
|
||||
effect.Update(frameTime);
|
||||
|
||||
//These effects have died
|
||||
if (effect.Age > effect.Deathtime)
|
||||
// Effects are purely visual, so they don't need to be ran through prediction.
|
||||
// once CurTime ever passes DeathTime (clients render the top at IsFirstTimePredicted, where this happens) just remove them.
|
||||
if (curTime > effect.Deathtime)
|
||||
{
|
||||
//Remove from the effects list and decrement the iterator
|
||||
_Effects.Remove(effect);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Update variables of the effect via its deltas
|
||||
effect.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,14 +202,9 @@ namespace Robust.Client.GameObjects
|
||||
public bool Shaded = true;
|
||||
|
||||
/// <summary>
|
||||
/// Effect's age -- from 0f
|
||||
/// CurTime after which the effect will "die"
|
||||
/// </summary>
|
||||
public TimeSpan Age = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Time after which the effect will "die"
|
||||
/// </summary>
|
||||
public TimeSpan Deathtime = TimeSpan.FromSeconds(1);
|
||||
public TimeSpan Deathtime;
|
||||
|
||||
private readonly IMapManager _mapManager;
|
||||
private readonly IEntityManager _entityManager;
|
||||
@@ -245,8 +237,6 @@ namespace Robust.Client.GameObjects
|
||||
RadialAcceleration = effectcreation.RadialAcceleration;
|
||||
TangentialVelocity = effectcreation.TangentialVelocity;
|
||||
TangentialAcceleration = effectcreation.TangentialAcceleration;
|
||||
Age = effectcreation.Born;
|
||||
Deathtime = effectcreation.DeathTime;
|
||||
Rotation = effectcreation.Rotation;
|
||||
RotationRate = effectcreation.RotationRate;
|
||||
Size = effectcreation.Size;
|
||||
@@ -260,10 +250,6 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
Age += TimeSpan.FromSeconds(frameTime);
|
||||
if (Age >= Deathtime)
|
||||
return;
|
||||
|
||||
Velocity += Acceleration * frameTime;
|
||||
RadialVelocity += RadialAcceleration * frameTime;
|
||||
TangentialVelocity += TangentialAcceleration * frameTime;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Physics;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -10,7 +10,7 @@ using Robust.Shared.Maths;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the position of every Eye every frame, so that the camera follows the player around.
|
||||
@@ -87,7 +87,7 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var eyeComponent in EntityManager.ComponentManager.EntityQuery<EyeComponent>())
|
||||
foreach (var eyeComponent in EntityManager.ComponentManager.EntityQuery<EyeComponent>(true))
|
||||
{
|
||||
eyeComponent.UpdateEyePosition();
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
using System;
|
||||
using Robust.Client.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.GameStates;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side processing of all input commands through the simulation.
|
||||
@@ -44,7 +40,7 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
/// <param name="message">Arguments for this event.</param>
|
||||
/// <param name="replay">if true, current cmd state will not be checked or updated - use this for "replaying" an
|
||||
/// old input that was saved or buffered until further processing could be done</param>
|
||||
public bool HandleInputCommand(ICommonSession session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
|
||||
public bool HandleInputCommand(ICommonSession? session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
@@ -128,7 +124,8 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
|
||||
if (!entity.TryGetComponent(out InputComponent? inputComp))
|
||||
{
|
||||
Logger.DebugS("input.context", $"AttachedEnt has no InputComponent: entId={entity.Uid}, entProto={entity.Prototype}");
|
||||
Logger.DebugS("input.context", $"AttachedEnt has no InputComponent: entId={entity.Uid}, entProto={entity.Prototype}. Setting default \"{InputContextContainer.DefaultContextName}\" context...");
|
||||
inputMan.Contexts.SetActiveContext(InputContextContainer.DefaultContextName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,7 +135,8 @@ namespace Robust.Client.GameObjects.EntitySystems
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS("input.context", $"Unknown context: entId={entity.Uid}, entProto={entity.Prototype}, context={inputComp.ContextName}");
|
||||
Logger.ErrorS("input.context", $"Unknown context: entId={entity.Uid}, entProto={entity.Prototype}, context={inputComp.ContextName}. . Setting default \"{InputContextContainer.DefaultContextName}\" context...");
|
||||
inputMan.Contexts.SetActiveContext(InputContextContainer.DefaultContextName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Robust.Client.Audio.Midi;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.GameObjects.EntitySystems
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class MidiSystem : EntitySystem
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user