mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21e1b75f5d | ||
|
|
1f6ddd96a6 | ||
|
|
b4d2cd26aa | ||
|
|
ee6aee57bd | ||
|
|
ac1705e41f | ||
|
|
196a6047f1 | ||
|
|
b98b36a461 | ||
|
|
9980a98a94 | ||
|
|
5a1a1d0420 | ||
|
|
1c99678fe9 | ||
|
|
4049f10faa | ||
|
|
331c0bd43f | ||
|
|
604cd2f93d | ||
|
|
a87db2e57c | ||
|
|
4c7f0a8d6b | ||
|
|
9eaf52886a | ||
|
|
fce6f6c714 | ||
|
|
c04d51d489 | ||
|
|
d310871aa6 | ||
|
|
5fa422865f | ||
|
|
c137823355 | ||
|
|
0a0026b9ae | ||
|
|
97a2a5cfae | ||
|
|
a266e21d9e | ||
|
|
ad8bbe6401 | ||
|
|
71ce4749fe | ||
|
|
1e33c3c843 | ||
|
|
b3f3ca9725 | ||
|
|
33c37393ba | ||
|
|
ae36529744 | ||
|
|
ed2be48864 | ||
|
|
7ad5ce302e | ||
|
|
647f1a6808 | ||
|
|
6c44dd9665 | ||
|
|
c81413b0b4 | ||
|
|
88b3a557da | ||
|
|
572eb01290 | ||
|
|
9dab74c9d5 | ||
|
|
e1cb1e1b9c | ||
|
|
a23da702b1 | ||
|
|
ae9c2423ff | ||
|
|
a6dae8e30a | ||
|
|
96c0a4ae1f | ||
|
|
c26ebcbc78 | ||
|
|
8334050411 | ||
|
|
cc67edfc2c | ||
|
|
943ea9e6c8 | ||
|
|
3aa5cefe03 | ||
|
|
c5b34bab69 | ||
|
|
e4f24ec125 | ||
|
|
250971ade7 | ||
|
|
718adf9740 | ||
|
|
5d63aa8c95 | ||
|
|
17af3612a5 | ||
|
|
d2ecf6b9b1 | ||
|
|
2a1eda0d38 | ||
|
|
f0180abeb0 | ||
|
|
720f1b1d05 | ||
|
|
ae45a96753 | ||
|
|
74257c72ee | ||
|
|
cea088f4b4 | ||
|
|
88678e7d58 | ||
|
|
d222e25d22 | ||
|
|
f0d7fbb6f2 | ||
|
|
adec0e71ec | ||
|
|
86d9067d62 | ||
|
|
b989c9dbee | ||
|
|
3101ec1985 | ||
|
|
9ec2da1777 | ||
|
|
0acd28e8f4 | ||
|
|
c340f50ee5 | ||
|
|
2b589215aa | ||
|
|
490a567ad4 | ||
|
|
32f0c49484 | ||
|
|
61113d2434 | ||
|
|
6ba1baa88c | ||
|
|
07867acb9a | ||
|
|
3e28b083b9 | ||
|
|
68d9e13edf |
@@ -1,44 +1,21 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Benchmarks.Serialization.Definitions;
|
||||
using Robust.Server;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Sequence;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Benchmarks.Serialization.Copy
|
||||
{
|
||||
public class SerializationCopyBenchmark
|
||||
public class SerializationCopyBenchmark : SerializationBenchmark
|
||||
{
|
||||
public SerializationCopyBenchmark()
|
||||
{
|
||||
IoCManager.InitThread();
|
||||
ServerIoC.RegisterIoC();
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var assemblies = new[]
|
||||
{
|
||||
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Shared"),
|
||||
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Server"),
|
||||
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Benchmarks")
|
||||
};
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
IoCManager.Resolve<IConfigurationManagerInternal>().LoadCVarsFromAssembly(assembly);
|
||||
}
|
||||
|
||||
IoCManager.Resolve<IReflectionManager>().LoadAssemblies(assemblies);
|
||||
|
||||
SerializationManager = IoCManager.Resolve<ISerializationManager>();
|
||||
SerializationManager.Initialize();
|
||||
InitializeSerialization();
|
||||
|
||||
DataDefinitionWithString = new DataDefinitionWithString {StringField = "ABC"};
|
||||
|
||||
@@ -50,8 +27,6 @@ namespace Robust.Benchmarks.Serialization.Copy
|
||||
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
|
||||
}
|
||||
|
||||
private ISerializationManager SerializationManager { get; }
|
||||
|
||||
private const string String = "ABC";
|
||||
|
||||
private const int Integer = 1;
|
||||
|
||||
@@ -6,6 +6,10 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Benchmarks.Serialization.Definitions
|
||||
{
|
||||
/// <summary>
|
||||
/// Arbitrarily large data definition for benchmarks.
|
||||
/// Taken from content.
|
||||
/// </summary>
|
||||
[Prototype("seed")]
|
||||
public class SeedDataDefinition : IPrototype
|
||||
{
|
||||
@@ -96,13 +100,15 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
Repeat
|
||||
}
|
||||
|
||||
public enum Gas {}
|
||||
public enum Gas
|
||||
{
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public struct SeedChemQuantity
|
||||
{
|
||||
[DataField("Min")]
|
||||
public int Min { get; }
|
||||
public int Min;
|
||||
|
||||
[DataField("Max")]
|
||||
public int Max;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Benchmarks.Serialization.Definitions;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Sequence;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Benchmarks.Serialization.Read
|
||||
@@ -13,7 +16,7 @@ namespace Robust.Benchmarks.Serialization.Read
|
||||
InitializeSerialization();
|
||||
|
||||
StringDataDefNode = new MappingDataNode();
|
||||
StringDataDefNode.AddNode(new ValueDataNode("string"), new ValueDataNode("ABC"));
|
||||
StringDataDefNode.Add(new ValueDataNode("string"), new ValueDataNode("ABC"));
|
||||
|
||||
var yamlStream = new YamlStream();
|
||||
yamlStream.Load(new StringReader(SeedDataDefinition.Prototype));
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Robust.Benchmarks.Serialization.Definitions;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Sequence;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Benchmarks.Serialization.Write
|
||||
{
|
||||
public class SerializationWriteBenchmark : SerializationBenchmark
|
||||
{
|
||||
public SerializationWriteBenchmark()
|
||||
{
|
||||
InitializeSerialization();
|
||||
|
||||
DataDefinitionWithString = new DataDefinitionWithString {StringField = "ABC"};
|
||||
|
||||
var yamlStream = new YamlStream();
|
||||
yamlStream.Load(new StringReader(SeedDataDefinition.Prototype));
|
||||
|
||||
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
|
||||
|
||||
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
|
||||
}
|
||||
|
||||
private const string String = "ABC";
|
||||
|
||||
private const int Integer = 1;
|
||||
|
||||
private DataDefinitionWithString DataDefinitionWithString { get; }
|
||||
|
||||
private SeedDataDefinition Seed { get; }
|
||||
|
||||
[Benchmark]
|
||||
public DataNode WriteString()
|
||||
{
|
||||
return SerializationManager.WriteValue(String);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public DataNode WriteInteger()
|
||||
{
|
||||
return SerializationManager.WriteValue(Integer);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public DataNode WriteDataDefinitionWithString()
|
||||
{
|
||||
return SerializationManager.WriteValue(DataDefinitionWithString);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public DataNode WriteSeedDataDefinition()
|
||||
{
|
||||
return SerializationManager.WriteValue(Seed);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public DataNode BaselineWriteSeedDataDefinition()
|
||||
{
|
||||
var mapping = new MappingDataNode();
|
||||
|
||||
mapping.Add("id", Seed.ID);
|
||||
mapping.Add("name", Seed.Name);
|
||||
mapping.Add("seedName", Seed.SeedName);
|
||||
mapping.Add("displayName", Seed.DisplayName);
|
||||
mapping.Add("productPrototypes", Seed.ProductPrototypes);
|
||||
mapping.Add("harvestRepeat", Seed.HarvestRepeat.ToString());
|
||||
mapping.Add("lifespan", Seed.Lifespan.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("maturation", Seed.Maturation.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("production", Seed.Production.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("yield", Seed.Yield.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("potency", Seed.Potency.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("growthStages", Seed.GrowthStages.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("idealLight", Seed.IdealLight.ToString(CultureInfo.InvariantCulture));
|
||||
mapping.Add("idealHeat", Seed.IdealHeat.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
var chemicals = new MappingDataNode();
|
||||
foreach (var (name, quantity) in Seed.Chemicals)
|
||||
{
|
||||
chemicals.Add(name, new MappingDataNode
|
||||
{
|
||||
["Min"] = new ValueDataNode(quantity.Min.ToString(CultureInfo.InvariantCulture)),
|
||||
["Max"] = new ValueDataNode(quantity.Max.ToString(CultureInfo.InvariantCulture)),
|
||||
["PotencyDivisor"] = new ValueDataNode(quantity.PotencyDivisor.ToString(CultureInfo.InvariantCulture))
|
||||
});
|
||||
}
|
||||
|
||||
mapping.Add("chemicals", chemicals);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,7 +247,6 @@ namespace {nameSpace}
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
Location.None));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,18 @@ using System.Threading;
|
||||
using NFluidsynth;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
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.Physics.Broadphase;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Logger = Robust.Shared.Log.Logger;
|
||||
|
||||
namespace Robust.Client.Audio.Midi
|
||||
@@ -32,24 +36,6 @@ namespace Robust.Client.Audio.Midi
|
||||
/// </returns>
|
||||
IMidiRenderer? GetNewRenderer();
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Checks whether the file at the given path is a valid midi file or not.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We add this here so content doesn't need to reference NFluidsynth.
|
||||
/// </remarks>
|
||||
bool IsMidiFile(string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the file at the given path is a valid midi file or not.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We add this here so content doesn't need to reference NFluidsynth.
|
||||
/// </remarks>
|
||||
bool IsSoundfontFile(string filename);
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Method called every frame.
|
||||
/// Should be used to update positional audio.
|
||||
@@ -57,6 +43,11 @@ namespace Robust.Client.Audio.Midi
|
||||
/// <param name="frameTime"></param>
|
||||
void FrameUpdate(float frameTime);
|
||||
|
||||
/// <summary>
|
||||
/// Volume, in db.
|
||||
/// </summary>
|
||||
float Volume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, MIDI support is available.
|
||||
/// </summary>
|
||||
@@ -72,9 +63,11 @@ namespace Robust.Client.Audio.Midi
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IResourceManagerInternal _resourceManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfgMan = default!;
|
||||
|
||||
private SharedBroadPhaseSystem _broadPhaseSystem = default!;
|
||||
|
||||
[ViewVariables]
|
||||
public bool IsAvailable
|
||||
{
|
||||
get
|
||||
@@ -85,12 +78,29 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<MidiRenderer> _renderers = new();
|
||||
[ViewVariables]
|
||||
private readonly List<IMidiRenderer> _renderers = new();
|
||||
|
||||
private bool _alive = true;
|
||||
private Settings? _settings;
|
||||
private Thread? _midiThread;
|
||||
private ISawmill _midiSawmill = default!;
|
||||
private float _volume = 0f;
|
||||
private bool _volumeDirty = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Volume
|
||||
{
|
||||
get => _volume;
|
||||
set
|
||||
{
|
||||
if (MathHelper.CloseTo(_volume, value))
|
||||
return;
|
||||
|
||||
_cfgMan.SetCVar(CVars.MidiVolume, value);
|
||||
_volumeDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] LinuxSoundfonts =
|
||||
{
|
||||
@@ -117,12 +127,19 @@ namespace Robust.Client.Audio.Midi
|
||||
private NFluidsynth.Logger.LoggerDelegate _loggerDelegate = default!;
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int OcclusionCollisionMask { get; set; }
|
||||
|
||||
private void InitializeFluidsynth()
|
||||
{
|
||||
if (FluidsynthInitialized || _failedInitialize) return;
|
||||
|
||||
_cfgMan.OnValueChanged(CVars.MidiVolume, value =>
|
||||
{
|
||||
_volume = value;
|
||||
_volumeDirty = true;
|
||||
}, true);
|
||||
|
||||
_midiSawmill = Logger.GetSawmill("midi");
|
||||
_sawmill = Logger.GetSawmill("midi.fluidsynth");
|
||||
_loggerDelegate = LoggerDelegate;
|
||||
@@ -175,18 +192,6 @@ namespace Robust.Client.Audio.Midi
|
||||
_sawmill.Log(rLevel, message);
|
||||
}
|
||||
|
||||
/*
|
||||
public bool IsMidiFile(string filename)
|
||||
{
|
||||
return SoundFont.IsMidiFile(filename);
|
||||
}
|
||||
|
||||
public bool IsSoundfontFile(string filename)
|
||||
{
|
||||
return SoundFont.IsSoundFont(filename);
|
||||
}
|
||||
*/
|
||||
|
||||
public IMidiRenderer? GetNewRenderer()
|
||||
{
|
||||
if (!FluidsynthInitialized)
|
||||
@@ -250,7 +255,9 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
|
||||
lock (_renderers)
|
||||
{
|
||||
_renderers.Add(renderer);
|
||||
}
|
||||
|
||||
return renderer;
|
||||
}
|
||||
@@ -268,74 +275,79 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
|
||||
// Update positions of streams every frame.
|
||||
lock (_renderers)
|
||||
foreach (var renderer in _renderers)
|
||||
foreach (var renderer in _renderers)
|
||||
{
|
||||
if (renderer.Disposed)
|
||||
continue;
|
||||
|
||||
if(_volumeDirty)
|
||||
renderer.Source.SetVolume(Volume);
|
||||
|
||||
if (!renderer.Mono)
|
||||
{
|
||||
if (renderer.Disposed)
|
||||
continue;
|
||||
|
||||
if (!renderer.Mono)
|
||||
{
|
||||
renderer.Source.SetGlobal();
|
||||
continue;
|
||||
}
|
||||
|
||||
MapCoordinates? mapPos = null;
|
||||
if (renderer.TrackingCoordinates != null)
|
||||
{
|
||||
mapPos = renderer.TrackingCoordinates.Value.ToMap(_entityManager);
|
||||
}
|
||||
else if (renderer.TrackingEntity != null)
|
||||
{
|
||||
mapPos = renderer.TrackingEntity.Transform.MapPosition;
|
||||
}
|
||||
|
||||
if (mapPos != null)
|
||||
{
|
||||
var pos = mapPos.Value;
|
||||
if (pos.MapId != _eyeManager.CurrentMap)
|
||||
{
|
||||
renderer.Source.SetVolume(-10000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
|
||||
var occlusion = 0f;
|
||||
if (sourceRelative.Length > 0)
|
||||
{
|
||||
occlusion = _broadPhaseSystem.IntersectRayPenetration(
|
||||
pos.MapId,
|
||||
new CollisionRay(
|
||||
pos.Position,
|
||||
sourceRelative.Normalized,
|
||||
OcclusionCollisionMask),
|
||||
sourceRelative.Length,
|
||||
renderer.TrackingEntity);
|
||||
}
|
||||
renderer.Source.SetOcclusion(occlusion);
|
||||
}
|
||||
|
||||
if (renderer.Source.SetPosition(pos.Position))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderer.TrackingEntity != null)
|
||||
{
|
||||
renderer.Source.SetVelocity(renderer.TrackingEntity.GlobalLinearVelocity());
|
||||
}
|
||||
|
||||
if (float.IsNaN(pos.Position.X) || float.IsNaN(pos.Position.Y))
|
||||
{
|
||||
// just duck out instead of move to NaN
|
||||
renderer.Source.SetOcclusion(float.MaxValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
_midiSawmill?.Warning("Interrupting positional audio, can't set position.");
|
||||
renderer.Source.StopPlaying();
|
||||
}
|
||||
renderer.Source.SetGlobal();
|
||||
continue;
|
||||
}
|
||||
|
||||
MapCoordinates? mapPos = null;
|
||||
if (renderer.TrackingCoordinates != null)
|
||||
{
|
||||
mapPos = renderer.TrackingCoordinates.Value.ToMap(_entityManager);
|
||||
}
|
||||
else if (renderer.TrackingEntity != null)
|
||||
{
|
||||
mapPos = renderer.TrackingEntity.Transform.MapPosition;
|
||||
}
|
||||
|
||||
if (mapPos != null)
|
||||
{
|
||||
var pos = mapPos.Value;
|
||||
if (pos.MapId != _eyeManager.CurrentMap)
|
||||
{
|
||||
renderer.Source.SetVolume(-10000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
|
||||
var occlusion = 0f;
|
||||
if (sourceRelative.Length > 0)
|
||||
{
|
||||
occlusion = _broadPhaseSystem.IntersectRayPenetration(
|
||||
pos.MapId,
|
||||
new CollisionRay(
|
||||
pos.Position,
|
||||
sourceRelative.Normalized,
|
||||
OcclusionCollisionMask),
|
||||
sourceRelative.Length,
|
||||
renderer.TrackingEntity);
|
||||
}
|
||||
|
||||
renderer.Source.SetOcclusion(occlusion);
|
||||
}
|
||||
|
||||
if (renderer.Source.SetPosition(pos.Position))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderer.TrackingEntity != null)
|
||||
{
|
||||
renderer.Source.SetVelocity(renderer.TrackingEntity.GlobalLinearVelocity());
|
||||
}
|
||||
|
||||
if (float.IsNaN(pos.Position.X) || float.IsNaN(pos.Position.Y))
|
||||
{
|
||||
// just duck out instead of move to NaN
|
||||
renderer.Source.SetOcclusion(float.MaxValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
_midiSawmill?.Warning("Interrupting positional audio, can't set position.");
|
||||
renderer.Source.StopPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
_volumeDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -346,6 +358,7 @@ namespace Robust.Client.Audio.Midi
|
||||
while (_alive)
|
||||
{
|
||||
lock (_renderers)
|
||||
{
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var renderer = _renderers[i];
|
||||
@@ -353,10 +366,11 @@ namespace Robust.Client.Audio.Midi
|
||||
renderer.Render();
|
||||
else
|
||||
{
|
||||
((IMidiRenderer)renderer).InternalDispose();
|
||||
renderer.InternalDispose();
|
||||
_renderers.Remove(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
@@ -367,9 +381,13 @@ namespace Robust.Client.Audio.Midi
|
||||
_alive = false;
|
||||
_midiThread?.Join();
|
||||
_settings?.Dispose();
|
||||
foreach (var renderer in _renderers)
|
||||
|
||||
lock (_renderers)
|
||||
{
|
||||
renderer?.Dispose();
|
||||
foreach (var renderer in _renderers)
|
||||
{
|
||||
renderer?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (FluidsynthInitialized && !_failedInitialize)
|
||||
@@ -424,6 +442,7 @@ namespace Robust.Client.Audio.Midi
|
||||
var span = new Span<byte>(buf.ToPointer(), length);
|
||||
var stream = _openStreams[(int) sfHandle];
|
||||
|
||||
// Fluidsynth's docs state that this method should leave the buffer unmodified if it fails. (returns -1)
|
||||
try
|
||||
{
|
||||
// Fluidsynth does a LOT of tiny allocations (frankly, way too much).
|
||||
@@ -447,6 +466,7 @@ namespace Robust.Client.Audio.Midi
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -468,10 +488,12 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
public override int Close(IntPtr sfHandle)
|
||||
{
|
||||
var stream = _openStreams[(int) sfHandle];
|
||||
if (!_openStreams.Remove((int) sfHandle, out var stream))
|
||||
return -1;
|
||||
|
||||
stream.Dispose();
|
||||
_openStreams.Remove((int) sfHandle);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using MidiEvent = NFluidsynth.MidiEvent;
|
||||
|
||||
namespace Robust.Client.Audio.Midi
|
||||
@@ -21,6 +23,17 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
public interface IMidiRenderer : IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The buffered audio source of this renderer.
|
||||
/// </summary>
|
||||
internal IClydeBufferedAudioSource Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this renderer has been disposed or not.
|
||||
/// </summary>
|
||||
bool Disposed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This controls whether the midi file being played will loop or not.
|
||||
/// </summary>
|
||||
@@ -110,6 +123,11 @@ namespace Robust.Client.Audio.Midi
|
||||
/// </summary>
|
||||
void StopAllNotes();
|
||||
|
||||
/// <summary>
|
||||
/// Render and play MIDI to the audio source.
|
||||
/// </summary>
|
||||
internal void Render();
|
||||
|
||||
/// <summary>
|
||||
/// Loads a new soundfont into the renderer.
|
||||
/// </summary>
|
||||
@@ -159,7 +177,7 @@ namespace Robust.Client.Audio.Midi
|
||||
internal void InternalDispose();
|
||||
}
|
||||
|
||||
public class MidiRenderer : IMidiRenderer
|
||||
internal class MidiRenderer : IMidiRenderer
|
||||
{
|
||||
[Dependency] private readonly IClydeAudio _clydeAudio = default!;
|
||||
[Dependency] private readonly ITaskManager _taskManager = default!;
|
||||
@@ -186,10 +204,16 @@ namespace Robust.Client.Audio.Midi
|
||||
private const int SampleRate = 44100;
|
||||
private const int Buffers = SampleRate / 2205;
|
||||
private readonly object _playerStateLock = new();
|
||||
private bool _debugEvents = false;
|
||||
private SequencerClientId _synthRegister;
|
||||
private SequencerClientId _debugRegister;
|
||||
public IClydeBufferedAudioSource Source { get; set; }
|
||||
IClydeBufferedAudioSource IMidiRenderer.Source => Source;
|
||||
|
||||
[ViewVariables]
|
||||
public bool Disposed { get; private set; } = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public byte MidiProgram
|
||||
{
|
||||
get => _midiProgram;
|
||||
@@ -203,6 +227,7 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public byte MidiBank
|
||||
{
|
||||
get => _midiBank;
|
||||
@@ -216,6 +241,7 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public uint MidiSoundfont
|
||||
{
|
||||
get => _midiSoundfont;
|
||||
@@ -229,10 +255,16 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool DisablePercussionChannel { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool DisableProgramChangeEvent { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PlayerTotalTick => _player?.GetTotalTicks ?? 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PlayerTick
|
||||
{
|
||||
get => _player?.CurrentTick ?? 0;
|
||||
@@ -243,12 +275,19 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public uint SequencerTick => _sequencer?.Tick ?? 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public double SequencerTimeScale => _sequencer?.TimeScale ?? 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Mono { get; set; }
|
||||
|
||||
[ViewVariables]
|
||||
public MidiRendererStatus Status { get; private set; } = MidiRendererStatus.None;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool LoopMidi
|
||||
{
|
||||
get => _loopMidi;
|
||||
@@ -260,10 +299,11 @@ namespace Robust.Client.Audio.Midi
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public IEntity? TrackingEntity { get; set; } = null;
|
||||
public EntityCoordinates? TrackingCoordinates { get; set; } = null;
|
||||
|
||||
internal bool Free { get; set; } = false;
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public EntityCoordinates? TrackingCoordinates { get; set; } = null;
|
||||
|
||||
internal MidiRenderer(Settings settings, SoundFontLoader soundFontLoader, bool mono = true)
|
||||
{
|
||||
@@ -276,6 +316,7 @@ namespace Robust.Client.Audio.Midi
|
||||
_soundFontLoader = soundFontLoader;
|
||||
_synth = new Synth(_settings);
|
||||
_sequencer = new Sequencer(false);
|
||||
_debugRegister = _sequencer.RegisterClient("honk", DumpSequencerEvent);
|
||||
_synthRegister = _sequencer.RegisterFluidsynth(_synth);
|
||||
|
||||
_synth.AddSoundFontLoader(soundFontLoader);
|
||||
@@ -285,6 +326,27 @@ namespace Robust.Client.Audio.Midi
|
||||
Source.StartPlaying();
|
||||
}
|
||||
|
||||
private void DumpSequencerEvent(uint time, SequencerEvent @event)
|
||||
{
|
||||
// ReSharper disable once UseStringInterpolation
|
||||
_midiSawmill.Debug(string.Format(
|
||||
"{0:D8}: {1} chan:{2:D2} key:{3:D5} bank:{4:D2} ctrl:{5:D5} dur:{6:D5} pitch:{7:D5} prog:{8:D3} val:{9:D5} vel:{10:D5}",
|
||||
time,
|
||||
@event.Type.ToString().PadLeft(22),
|
||||
@event.Channel,
|
||||
@event.Key,
|
||||
@event.Bank,
|
||||
@event.Control,
|
||||
@event.Duration,
|
||||
@event.Pitch,
|
||||
@event.Program,
|
||||
@event.Value,
|
||||
@event.Velocity));
|
||||
|
||||
@event.Dest = _synthRegister;
|
||||
_sequencer.SendNow(@event);
|
||||
}
|
||||
|
||||
public bool OpenInput()
|
||||
{
|
||||
if (Disposed)
|
||||
@@ -294,7 +356,11 @@ namespace Robust.Client.Audio.Midi
|
||||
Status = MidiRendererStatus.Input;
|
||||
StopAllNotes();
|
||||
|
||||
_driver = new MidiDriver(_settings, MidiDriverEventHandler);
|
||||
lock (_playerStateLock)
|
||||
{
|
||||
_driver = new MidiDriver(_settings, MidiDriverEventHandler);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -332,8 +398,13 @@ namespace Robust.Client.Audio.Midi
|
||||
{
|
||||
if (Status != MidiRendererStatus.Input) return false;
|
||||
Status = MidiRendererStatus.None;
|
||||
_driver?.Dispose();
|
||||
_driver = null;
|
||||
|
||||
lock (_playerStateLock)
|
||||
{
|
||||
_driver?.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
|
||||
StopAllNotes();
|
||||
return true;
|
||||
}
|
||||
@@ -357,7 +428,8 @@ namespace Robust.Client.Audio.Midi
|
||||
|
||||
public void StopAllNotes()
|
||||
{
|
||||
_synth.AllNotesOff(-1);
|
||||
lock(_playerStateLock)
|
||||
_synth.AllNotesOff(-1);
|
||||
}
|
||||
|
||||
public void LoadSoundfont(string filename, bool resetPresets = false)
|
||||
@@ -372,13 +444,15 @@ namespace Robust.Client.Audio.Midi
|
||||
public event Action<Shared.Audio.Midi.MidiEvent>? OnMidiEvent;
|
||||
public event Action? OnMidiPlayerFinished;
|
||||
|
||||
internal void Render(int length = SampleRate / 250)
|
||||
void IMidiRenderer.Render()
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
private void Render(int length = SampleRate / 250)
|
||||
{
|
||||
if (Disposed) return;
|
||||
|
||||
// SSE needs this.
|
||||
DebugTools.Assert(length % 4 == 0, "Sample length must be multiple of 4");
|
||||
|
||||
var buffersProcessed = Source.GetNumberOfBuffersProcessed();
|
||||
if(buffersProcessed == Buffers) _midiSawmill.Warning("MIDI buffer overflow!");
|
||||
if (buffersProcessed == 0) return;
|
||||
@@ -393,36 +467,16 @@ namespace Robust.Client.Audio.Midi
|
||||
Source.GetBuffersProcessed(buffers);
|
||||
|
||||
lock (_playerStateLock)
|
||||
{
|
||||
// _sequencer.Process(10);
|
||||
_synth?.WriteSampleFloat(length * buffers.Length, audio, 0, Mono ? 1 : 2,
|
||||
audio, Mono ? length * buffers.Length : 1, Mono ? 1 : 2);
|
||||
|
||||
}
|
||||
if (Mono) // Turn audio to mono
|
||||
{
|
||||
var l = length * buffers.Length;
|
||||
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
fixed (float* ptr = audio)
|
||||
{
|
||||
for (var j = 0; j < l; j += 4)
|
||||
{
|
||||
var k = j + l;
|
||||
|
||||
var jV = Sse.LoadVector128(ptr + j);
|
||||
var kV = Sse.LoadVector128(ptr + k);
|
||||
|
||||
Sse.Store(j + ptr, Sse.Add(jV, kV));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var j = 0; j < l; j++)
|
||||
{
|
||||
var k = j + l;
|
||||
audio[j] = ((audio[k] + audio[j]));
|
||||
}
|
||||
}
|
||||
NumericsHelpers.Add(audio[..l], audio[l..]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < buffers.Length; i++)
|
||||
@@ -452,6 +506,7 @@ namespace Robust.Client.Audio.Midi
|
||||
var timestamp = SequencerTick;
|
||||
var midiEv = (Shared.Audio.Midi.MidiEvent) midiEvent;
|
||||
midiEv.Tick = timestamp;
|
||||
midiEvent.Dispose();
|
||||
SendMidiEvent(midiEv);
|
||||
return 0;
|
||||
}
|
||||
@@ -462,6 +517,7 @@ namespace Robust.Client.Audio.Midi
|
||||
var timestamp = SequencerTick;
|
||||
var midiEv = (Shared.Audio.Midi.MidiEvent) midiEvent;
|
||||
midiEv.Tick = timestamp;
|
||||
midiEvent.Dispose();
|
||||
SendMidiEvent(midiEv);
|
||||
return 0;
|
||||
}
|
||||
@@ -478,16 +534,16 @@ namespace Robust.Client.Audio.Midi
|
||||
lock(_playerStateLock)
|
||||
switch (midiEvent.Type)
|
||||
{
|
||||
// Note On 0x80
|
||||
case 144:
|
||||
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
|
||||
break;
|
||||
|
||||
// Note Off - 0x90
|
||||
// Note Off - 0x80
|
||||
case 128:
|
||||
_synth.NoteOff(midiEvent.Channel, midiEvent.Key);
|
||||
break;
|
||||
|
||||
// Note On 0x90
|
||||
case 144:
|
||||
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
|
||||
break;
|
||||
|
||||
// After Touch - 0xA
|
||||
case 160:
|
||||
_synth.KeyPressure(midiEvent.Channel, midiEvent.Key, midiEvent.Value);
|
||||
@@ -522,6 +578,12 @@ namespace Robust.Client.Audio.Midi
|
||||
case 81:
|
||||
// System Messages - 0xF0
|
||||
case 240:
|
||||
switch (midiEvent.Control)
|
||||
{
|
||||
case 11:
|
||||
_synth.AllNotesOff(midiEvent.Channel);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -543,7 +605,7 @@ namespace Robust.Client.Audio.Midi
|
||||
if (Disposed) return;
|
||||
|
||||
var seqEv = (SequencerEvent) midiEvent;
|
||||
seqEv.Dest = _synthRegister;
|
||||
seqEv.Dest = _debugEvents ? _debugRegister : _synthRegister;
|
||||
_sequencer.SendAt(seqEv, time, absolute);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -25,6 +26,7 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IPlayerManager _playMan = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly IClientEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityLookup _entityLookup = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IDiscordRichPresence _discord = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
@@ -165,7 +167,7 @@ namespace Robust.Client
|
||||
/// receiving states when they join the lobby.
|
||||
/// </summary>
|
||||
/// <param name="session">Session of the player.</param>
|
||||
private void OnPlayerJoinedServer(IPlayerSession session)
|
||||
private void OnPlayerJoinedServer(ICommonSession session)
|
||||
{
|
||||
DebugTools.Assert(RunLevel < ClientRunLevel.Connected);
|
||||
OnRunLevelChanged(ClientRunLevel.Connected);
|
||||
@@ -175,20 +177,11 @@ namespace Robust.Client
|
||||
PlayerJoinedServer?.Invoke(this, new PlayerEventArgs(session));
|
||||
}
|
||||
|
||||
private void GameStartedSetup()
|
||||
{
|
||||
_entityManager.Startup();
|
||||
_mapManager.Startup();
|
||||
|
||||
_timing.ResetSimTime();
|
||||
_timing.Paused = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Player is joining the game
|
||||
/// </summary>
|
||||
/// <param name="session">Session of the player.</param>
|
||||
private void OnPlayerJoinedGame(IPlayerSession session)
|
||||
private void OnPlayerJoinedGame(ICommonSession session)
|
||||
{
|
||||
DebugTools.Assert(RunLevel >= ClientRunLevel.Connected);
|
||||
OnRunLevelChanged(ClientRunLevel.InGame);
|
||||
@@ -218,12 +211,22 @@ namespace Robust.Client
|
||||
GameStoppedReset();
|
||||
}
|
||||
|
||||
private void GameStartedSetup()
|
||||
{
|
||||
_entityManager.Startup();
|
||||
_mapManager.Startup();
|
||||
_entityLookup.Startup();
|
||||
|
||||
_timing.ResetSimTime();
|
||||
_timing.Paused = false;
|
||||
}
|
||||
|
||||
private void GameStoppedReset()
|
||||
{
|
||||
IoCManager.Resolve<INetConfigurationManager>().FlushMessages();
|
||||
_gameStates.Reset();
|
||||
_playMan.Shutdown();
|
||||
IoCManager.Resolve<IEntityLookup>().Shutdown();
|
||||
_entityLookup.Shutdown();
|
||||
_entityManager.Shutdown();
|
||||
_mapManager.Shutdown();
|
||||
_discord.ClearPresence();
|
||||
@@ -295,12 +298,12 @@ namespace Robust.Client
|
||||
/// <summary>
|
||||
/// The session that triggered the event.
|
||||
/// </summary>
|
||||
private IPlayerSession? Session { get; }
|
||||
private ICommonSession? Session { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the class.
|
||||
/// </summary>
|
||||
public PlayerEventArgs(IPlayerSession? session)
|
||||
public PlayerEventArgs(ICommonSession? session)
|
||||
{
|
||||
Session = session;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Robust.Client
|
||||
IoCManager.Register<IMapManagerInternal, ClientMapManager>();
|
||||
IoCManager.Register<IClientMapManager, ClientMapManager>();
|
||||
IoCManager.Register<IEntityManager, ClientEntityManager>();
|
||||
IoCManager.Register<IEntityLookup, SharedEntityLookup>();
|
||||
IoCManager.Register<IEntityLookup, EntityLookup>();
|
||||
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
|
||||
IoCManager.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
|
||||
IoCManager.Register<IClydeTileDefinitionManager, ClydeTileDefinitionManager>();
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Robust.Client
|
||||
public bool Launcher { get; }
|
||||
public string? Username { get; }
|
||||
public IReadOnlyCollection<(string key, string value)> CVars { get; }
|
||||
public IReadOnlyCollection<(string key, string value)> LogLevels { get; }
|
||||
|
||||
// Manual parser because C# has no good command line parsing libraries. Also dependencies bad.
|
||||
// Also I don't like spending 100ms parsing command line args. Do you?
|
||||
@@ -31,6 +32,7 @@ namespace Robust.Client
|
||||
var launcher = false;
|
||||
string? username = null;
|
||||
var cvars = new List<(string, string)>();
|
||||
var logLevels = new List<(string, string)>();
|
||||
var mountOptions = new MountOptions();
|
||||
|
||||
using var enumerator = args.GetEnumerator();
|
||||
@@ -124,6 +126,26 @@ namespace Robust.Client
|
||||
|
||||
mountOptions.DirMounts.Add(enumerator.Current);
|
||||
}
|
||||
else if (arg == "--loglevel")
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
C.WriteLine("Missing loglevel sawmill.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var loglevel = enumerator.Current;
|
||||
DebugTools.AssertNotNull(loglevel);
|
||||
var pos = loglevel.IndexOf('=');
|
||||
|
||||
if (pos == -1)
|
||||
{
|
||||
C.WriteLine("Expected = in loglevel.");
|
||||
return false;
|
||||
}
|
||||
|
||||
logLevels.Add((loglevel[..pos], loglevel[(pos + 1)..]));
|
||||
}
|
||||
else if (arg == "--help")
|
||||
{
|
||||
PrintHelp();
|
||||
@@ -142,6 +164,7 @@ namespace Robust.Client
|
||||
launcher,
|
||||
username,
|
||||
cvars,
|
||||
logLevels,
|
||||
connectAddress,
|
||||
ss14Address,
|
||||
mountOptions);
|
||||
@@ -162,6 +185,7 @@ Options:
|
||||
--launcher Run in launcher mode (no main menu, auto connect).
|
||||
--username Override username.
|
||||
--cvar Specifies an additional cvar overriding the config file. Syntax is <key>=<value>
|
||||
--loglevel Specifies an additional sawmill log level overriding the default values. Syntax is <key>=<value>
|
||||
--mount-dir Resource directory to mount.
|
||||
--mount-zip Resource zip to mount.
|
||||
--help Display this help text and exit.
|
||||
@@ -175,6 +199,7 @@ Options:
|
||||
bool launcher,
|
||||
string? username,
|
||||
IReadOnlyCollection<(string key, string value)> cVars,
|
||||
IReadOnlyCollection<(string key, string value)> logLevels,
|
||||
string connectAddress, string? ss14Address,
|
||||
MountOptions mountOptions)
|
||||
{
|
||||
@@ -184,6 +209,7 @@ Options:
|
||||
Launcher = launcher;
|
||||
Username = username;
|
||||
CVars = cVars;
|
||||
LogLevels = logLevels;
|
||||
ConnectAddress = connectAddress;
|
||||
Ss14Address = ss14Address;
|
||||
MountOptions = mountOptions;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Robust.Client.Console
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc cref="IClientConsoleHost" />
|
||||
internal class ClientConsoleHost : ConsoleHost, IClientConsoleHost
|
||||
{
|
||||
@@ -45,9 +45,9 @@ namespace Robust.Client.Console
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
NetManager.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME, HandleConCmdReg);
|
||||
NetManager.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME, HandleConCmdAck);
|
||||
NetManager.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME, ProcessCommand);
|
||||
NetManager.RegisterNetMessage<MsgConCmdReg>(HandleConCmdReg);
|
||||
NetManager.RegisterNetMessage<MsgConCmdAck>(HandleConCmdAck);
|
||||
NetManager.RegisterNetMessage<MsgConCmd>(ProcessCommand);
|
||||
|
||||
Reset();
|
||||
LogManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
|
||||
|
||||
@@ -25,6 +25,34 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class MonitorInfoCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "monitorinfo";
|
||||
public string Description => "";
|
||||
public string Help => "Usage: monitorinfo <id>";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
shell.WriteError("Expected one argument.");
|
||||
return;
|
||||
}
|
||||
|
||||
var clyde = IoCManager.Resolve<IClyde>();
|
||||
var monitor = clyde.EnumerateMonitors().Single(c => c.Id == int.Parse(args[0]));
|
||||
|
||||
shell.WriteLine($"{monitor.Id}: {monitor.Name}");
|
||||
shell.WriteLine($"Video modes:");
|
||||
|
||||
foreach (var mode in monitor.VideoModes)
|
||||
{
|
||||
shell.WriteLine($" {mode.Width}x{mode.Height} {mode.RefreshRate} Hz {mode.RedBits}/{mode.GreenBits}/{mode.BlueBits}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class SetMonitorCommand : IConsoleCommand
|
||||
{
|
||||
|
||||
@@ -17,11 +17,11 @@ namespace Robust.Client.Console
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgScriptStop>(MsgScriptStop.NAME);
|
||||
_netManager.RegisterNetMessage<MsgScriptEval>(MsgScriptEval.NAME);
|
||||
_netManager.RegisterNetMessage<MsgScriptStart>(MsgScriptStart.NAME);
|
||||
_netManager.RegisterNetMessage<MsgScriptResponse>(MsgScriptResponse.NAME, ReceiveScriptResponse);
|
||||
_netManager.RegisterNetMessage<MsgScriptStartAck>(MsgScriptStartAck.NAME, ReceiveScriptStartAckResponse);
|
||||
_netManager.RegisterNetMessage<MsgScriptStop>();
|
||||
_netManager.RegisterNetMessage<MsgScriptEval>();
|
||||
_netManager.RegisterNetMessage<MsgScriptStart>();
|
||||
_netManager.RegisterNetMessage<MsgScriptResponse>(ReceiveScriptResponse);
|
||||
_netManager.RegisterNetMessage<MsgScriptStartAck>(ReceiveScriptStartAckResponse);
|
||||
}
|
||||
|
||||
private void ReceiveScriptStartAckResponse(MsgScriptStartAck message)
|
||||
@@ -30,7 +30,8 @@ namespace Robust.Client.Console
|
||||
|
||||
var console = new ScriptConsoleServer(this, session);
|
||||
_activeConsoles.Add(session, console);
|
||||
console.Open();
|
||||
// FIXME: When this is Open(), resizing the window will cause its position to get NaN'd.
|
||||
console.OpenCentered();
|
||||
}
|
||||
|
||||
private void ReceiveScriptResponse(MsgScriptResponse message)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
@@ -23,7 +23,7 @@ namespace Robust.Client.Debugging
|
||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityLookup _lookup = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
if (value && !_overlayManager.HasOverlay<EntityPositionOverlay>())
|
||||
{
|
||||
_overlayManager.AddOverlay(new EntityPositionOverlay(_entityManager, _eyeManager));
|
||||
_overlayManager.AddOverlay(new EntityPositionOverlay(_lookup, _eyeManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -171,7 +171,7 @@ namespace Robust.Client.Debugging
|
||||
// all entities have a TransformComponent
|
||||
var transform = physBody.Owner.Transform;
|
||||
|
||||
var worldBox = physBody.GetWorldAABB(_mapManager);
|
||||
var worldBox = physBody.GetWorldAABB();
|
||||
if (worldBox.IsEmpty()) continue;
|
||||
|
||||
foreach (var fixture in physBody.Fixtures)
|
||||
@@ -270,14 +270,14 @@ namespace Robust.Client.Debugging
|
||||
|
||||
private sealed class EntityPositionOverlay : Overlay
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IEntityLookup _lookup;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public EntityPositionOverlay(IEntityManager entityManager, IEyeManager eyeManager)
|
||||
public EntityPositionOverlay(IEntityLookup lookup, IEyeManager eyeManager)
|
||||
{
|
||||
_entityManager = entityManager;
|
||||
_lookup = lookup;
|
||||
_eyeManager = eyeManager;
|
||||
}
|
||||
|
||||
@@ -286,18 +286,17 @@ namespace Robust.Client.Debugging
|
||||
const float stubLength = 0.25f;
|
||||
|
||||
var worldHandle = (DrawingHandleWorld) args.DrawingHandle;
|
||||
foreach (var entity in _entityManager.GetEntities())
|
||||
var viewport = _eyeManager.GetWorldViewport();
|
||||
|
||||
foreach (var entity in _lookup.GetEntitiesIntersecting(_eyeManager.CurrentMap, viewport))
|
||||
{
|
||||
var transform = entity.Transform;
|
||||
if (transform.MapID != _eyeManager.CurrentMap ||
|
||||
!_eyeManager.GetWorldViewport().Contains(transform.WorldPosition))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var center = transform.WorldPosition;
|
||||
var xLine = transform.WorldRotation.RotateVec(Vector2.UnitX);
|
||||
var yLine = transform.WorldRotation.RotateVec(Vector2.UnitY);
|
||||
var worldRotation = transform.WorldRotation;
|
||||
|
||||
var xLine = worldRotation.RotateVec(Vector2.UnitX);
|
||||
var yLine = worldRotation.RotateVec(Vector2.UnitY);
|
||||
|
||||
worldHandle.DrawLine(center, center + xLine * stubLength, Color.Red);
|
||||
worldHandle.DrawLine(center, center + yLine * stubLength, Color.Green);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.Debugging
|
||||
{
|
||||
@@ -54,7 +54,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgRay>(MsgRay.NAME, HandleDrawRay);
|
||||
_net.RegisterNetMessage<MsgRay>(HandleDrawRay);
|
||||
}
|
||||
|
||||
private void HandleDrawRay(MsgRay msg)
|
||||
|
||||
@@ -125,7 +125,6 @@ namespace Robust.Client
|
||||
_prototypeManager.Resync();
|
||||
_mapManager.Initialize();
|
||||
_entityManager.Initialize();
|
||||
IoCManager.Resolve<IEntityLookup>().Initialize();
|
||||
_gameStateManager.Initialize();
|
||||
_placementManager.Initialize();
|
||||
_viewVariablesManager.Initialize();
|
||||
@@ -203,6 +202,26 @@ namespace Robust.Client
|
||||
|
||||
SetupLogging(_logManager, logHandlerFactory ?? (() => new ConsoleLogHandler()));
|
||||
|
||||
if (_commandLineArgs != null)
|
||||
{
|
||||
foreach (var (sawmill, level) in _commandLineArgs.LogLevels)
|
||||
{
|
||||
LogLevel? logLevel;
|
||||
if (level == "null")
|
||||
logLevel = null;
|
||||
else
|
||||
{
|
||||
if (!Enum.TryParse<LogLevel>(level, out var result))
|
||||
{
|
||||
System.Console.WriteLine($"LogLevel {level} does not exist!");
|
||||
continue;
|
||||
}
|
||||
logLevel = result;
|
||||
}
|
||||
_logManager.GetSawmill(sawmill).Level = logLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out user data directory.
|
||||
var userDataDir = GetUserDataDir();
|
||||
|
||||
|
||||
@@ -9,58 +9,30 @@ namespace Robust.Client.GameObjects
|
||||
public ClientComponentFactory()
|
||||
{
|
||||
// Required for the engine to work
|
||||
Register<MetaDataComponent>();
|
||||
RegisterReference<MetaDataComponent, IMetaDataComponent>();
|
||||
|
||||
// Required for the engine to work
|
||||
Register<TransformComponent>();
|
||||
RegisterReference<TransformComponent, ITransformComponent>();
|
||||
|
||||
Register<MapComponent>();
|
||||
RegisterReference<MapComponent, IMapComponent>();
|
||||
|
||||
Register<MapGridComponent>();
|
||||
RegisterReference<MapGridComponent, IMapGridComponent>();
|
||||
|
||||
Register<PhysicsComponent>();
|
||||
RegisterReference<PhysicsComponent, IPhysBody>();
|
||||
|
||||
Register<CollisionWakeComponent>();
|
||||
|
||||
Register<ContainerManagerComponent>();
|
||||
RegisterReference<ContainerManagerComponent, IContainerManager>();
|
||||
|
||||
RegisterIgnore("KeyBindingInput");
|
||||
|
||||
Register<InputComponent>();
|
||||
|
||||
Register<SpriteComponent>();
|
||||
RegisterReference<SpriteComponent, SharedSpriteComponent>();
|
||||
RegisterReference<SpriteComponent, ISpriteComponent>();
|
||||
|
||||
Register<ClientOccluderComponent>();
|
||||
RegisterReference<ClientOccluderComponent, OccluderComponent>();
|
||||
|
||||
Register<EyeComponent>();
|
||||
RegisterReference<EyeComponent, SharedEyeComponent>();
|
||||
|
||||
Register<AppearanceComponent>();
|
||||
RegisterReference<AppearanceComponent, SharedAppearanceComponent>();
|
||||
|
||||
Register<AppearanceTestComponent>();
|
||||
Register<SnapGridComponent>();
|
||||
|
||||
Register<ClientUserInterfaceComponent>();
|
||||
RegisterReference<ClientUserInterfaceComponent, SharedUserInterfaceComponent>();
|
||||
|
||||
Register<AnimationPlayerComponent>();
|
||||
|
||||
Register<TimerComponent>();
|
||||
RegisterClass<MetaDataComponent>();
|
||||
RegisterClass<TransformComponent>();
|
||||
RegisterClass<MapComponent>();
|
||||
RegisterClass<MapGridComponent>();
|
||||
RegisterClass<PhysicsComponent>();
|
||||
RegisterClass<CollisionWakeComponent>();
|
||||
RegisterClass<ClientUserInterfaceComponent>();
|
||||
RegisterClass<ContainerManagerComponent>();
|
||||
RegisterClass<InputComponent>();
|
||||
RegisterClass<SpriteComponent>();
|
||||
RegisterClass<ClientOccluderComponent>();
|
||||
RegisterClass<EyeComponent>();
|
||||
RegisterClass<AppearanceComponent>();
|
||||
RegisterClass<AppearanceTestComponent>();
|
||||
RegisterClass<SnapGridComponent>();
|
||||
RegisterClass<AnimationPlayerComponent>();
|
||||
RegisterClass<TimerComponent>();
|
||||
|
||||
#if DEBUG
|
||||
Register<DebugExceptionOnAddComponent>();
|
||||
Register<DebugExceptionInitializeComponent>();
|
||||
Register<DebugExceptionStartupComponent>();
|
||||
RegisterClass<DebugExceptionOnAddComponent>();
|
||||
RegisterClass<DebugExceptionInitializeComponent>();
|
||||
RegisterClass<DebugExceptionStartupComponent>();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Prometheus;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
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;
|
||||
@@ -67,7 +62,7 @@ namespace Robust.Client.GameObjects
|
||||
/// <inheritdoc />
|
||||
public void SetupNetworking()
|
||||
{
|
||||
_networkManager.RegisterNetMessage<MsgEntity>(MsgEntity.NAME, HandleEntityNetworkMessage);
|
||||
_networkManager.RegisterNetMessage<MsgEntity>(HandleEntityNetworkMessage);
|
||||
}
|
||||
|
||||
public override void TickUpdate(float frameTime, Histogram? histogram)
|
||||
@@ -109,6 +104,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public void SendComponentNetworkMessage(INetChannel? channel, IEntity entity, IComponent component, ComponentMessage message)
|
||||
{
|
||||
if (!component.NetID.HasValue)
|
||||
|
||||
@@ -10,6 +10,7 @@ using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedAppearanceComponent))]
|
||||
public sealed class AppearanceComponent : SharedAppearanceComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedEyeComponent))]
|
||||
public class EyeComponent : SharedEyeComponent
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
|
||||
@@ -8,10 +8,11 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(OccluderComponent))]
|
||||
internal sealed class ClientOccluderComponent : OccluderComponent
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
|
||||
[ViewVariables] private (GridId, Vector2i) _lastPosition;
|
||||
[ViewVariables] internal OccluderDir Occluding { get; private set; }
|
||||
[ViewVariables] internal uint UpdateGeneration { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Animations;
|
||||
@@ -167,7 +168,7 @@ namespace Robust.Client.GameObjects
|
||||
set
|
||||
{
|
||||
_radius = MathF.Max(value, 0.01f); // setting radius to 0 causes exceptions, so just use a value close enough to zero that it's unnoticeable.
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PointLightRadiusChangedMessage(this));
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PointLightRadiusChangedEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +180,18 @@ namespace Robust.Client.GameObjects
|
||||
Mask = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What MapId we are intersecting for RenderingTreeSystem.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
internal MapId IntersectingMapId { get; set; } = MapId.Nullspace;
|
||||
|
||||
/// <summary>
|
||||
/// What grids we're on for RenderingTreeSystem.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
internal List<GridId> IntersectingGrids = new();
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
if (_maskPath != null)
|
||||
@@ -230,7 +243,7 @@ namespace Robust.Client.GameObjects
|
||||
if (map != MapId.Nullspace)
|
||||
{
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local,
|
||||
new RenderTreeRemoveLightMessage(this, map));
|
||||
new RenderTreeRemoveLightEvent(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,11 +261,11 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public struct PointLightRadiusChangedMessage
|
||||
public class PointLightRadiusChangedEvent : EntityEventArgs
|
||||
{
|
||||
public PointLightComponent PointLightComponent { get; }
|
||||
|
||||
public PointLightRadiusChangedMessage(PointLightComponent pointLightComponent)
|
||||
public PointLightRadiusChangedEvent(PointLightComponent pointLightComponent)
|
||||
{
|
||||
PointLightComponent = pointLightComponent;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedSpriteComponent))]
|
||||
[ComponentReference(typeof(ISpriteComponent))]
|
||||
public sealed class SpriteComponent : SharedSpriteComponent, ISpriteComponent,
|
||||
IComponentDebug, ISerializationHooks
|
||||
{
|
||||
@@ -123,6 +125,18 @@ namespace Robust.Client.GameObjects
|
||||
[DataField("directional")]
|
||||
private bool _directional = true;
|
||||
|
||||
/// <summary>
|
||||
/// What MapId we are intersecting for RenderingTreeSystem.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
internal MapId IntersectingMapId { get; set; } = MapId.Nullspace;
|
||||
|
||||
/// <summary>
|
||||
/// What grids we're on for RenderingTreeSystem.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
internal List<GridId> IntersectingGrids { get; } = new();
|
||||
|
||||
[DataField("layerDatums")]
|
||||
private List<PrototypeLayerData> LayerDatums
|
||||
{
|
||||
@@ -1345,18 +1359,6 @@ namespace Robust.Client.GameObjects
|
||||
return texture;
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
var map = Owner.Transform.MapID;
|
||||
if (map != MapId.Nullspace)
|
||||
{
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local,
|
||||
new RenderTreeRemoveSpriteMessage(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
public void FrameUpdate(float delta)
|
||||
{
|
||||
foreach (var t in Layers)
|
||||
@@ -1576,9 +1578,10 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendFormat(
|
||||
"vis/depth/scl/rot/ofs/col/diral/dir: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{7}\n",
|
||||
"vis/depth/scl/rot/ofs/col/norot/override/dir: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{8}/{7}\n",
|
||||
Visible, DrawDepth, Scale, Rotation, Offset,
|
||||
Color, Directional, GetDir(RSI.State.DirectionType.Dir8, Owner.Transform.WorldRotation)
|
||||
Color, NoRotation, GetDir(RSI.State.DirectionType.Dir8, Owner.Transform.WorldRotation),
|
||||
DirectionOverride
|
||||
);
|
||||
|
||||
foreach (var layer in Layers)
|
||||
@@ -2176,6 +2179,10 @@ namespace Robust.Client.GameObjects
|
||||
return null;
|
||||
}
|
||||
|
||||
public void QueueDelete()
|
||||
{
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
@@ -2190,10 +2197,12 @@ namespace Robust.Client.GameObjects
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public void SendMessage(IComponent? owner, ComponentMessage message)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public void SendNetworkMessage(IComponent owner, ComponentMessage message, INetChannel? channel = null)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedUserInterfaceComponent))]
|
||||
public class ClientUserInterfaceComponent : SharedUserInterfaceComponent, ISerializationHooks
|
||||
{
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
@@ -23,6 +23,9 @@ namespace Robust.Client.GameObjects
|
||||
[DataField("interfaces", readOnly: true)]
|
||||
private List<PrototypeData> _interfaceData = new();
|
||||
|
||||
[ViewVariables]
|
||||
public IEnumerable<BoundUserInterface> Interfaces => _openInterfaces.Values;
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
_interfaces.Clear();
|
||||
@@ -33,48 +36,40 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel,
|
||||
ICommonSession? session = null)
|
||||
internal void MessageReceived(BoundUIWrapMessage msg)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
|
||||
switch (message)
|
||||
switch (msg.Message)
|
||||
{
|
||||
case BoundInterfaceMessageWrapMessage wrapped:
|
||||
// Double nested switches who needs readability anyways.
|
||||
switch (wrapped.Message)
|
||||
case OpenBoundInterfaceMessage _:
|
||||
if (_openInterfaces.ContainsKey(msg.UiKey))
|
||||
{
|
||||
case OpenBoundInterfaceMessage _:
|
||||
if (_openInterfaces.ContainsKey(wrapped.UiKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
OpenInterface(wrapped);
|
||||
break;
|
||||
OpenInterface(msg);
|
||||
break;
|
||||
|
||||
case CloseBoundInterfaceMessage _:
|
||||
Close(wrapped.UiKey, true);
|
||||
break;
|
||||
case CloseBoundInterfaceMessage _:
|
||||
Close(msg.UiKey, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (_openInterfaces.TryGetValue(wrapped.UiKey, out var bi))
|
||||
{
|
||||
bi.InternalReceiveMessage(wrapped.Message);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (_openInterfaces.TryGetValue(msg.UiKey, out var bi))
|
||||
{
|
||||
bi.InternalReceiveMessage(msg.Message);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenInterface(BoundInterfaceMessageWrapMessage wrapped)
|
||||
private void OpenInterface(BoundUIWrapMessage wrapped)
|
||||
{
|
||||
var data = _interfaces[wrapped.UiKey];
|
||||
// TODO: This type should be cached, but I'm too lazy.
|
||||
var type = _reflectionManager.LooseGetType(data.ClientType);
|
||||
var boundInterface = (BoundUserInterface) _dynamicTypeFactory.CreateInstance(type, new[]{this, wrapped.UiKey});
|
||||
var boundInterface =
|
||||
(BoundUserInterface) _dynamicTypeFactory.CreateInstance(type, new[] {this, wrapped.UiKey});
|
||||
boundInterface.Open();
|
||||
_openInterfaces[wrapped.UiKey] = boundInterface;
|
||||
}
|
||||
@@ -86,7 +81,7 @@ namespace Robust.Client.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
if(!remoteCall)
|
||||
if (!remoteCall)
|
||||
SendMessage(new CloseBoundInterfaceMessage(), uiKey);
|
||||
_openInterfaces.Remove(uiKey);
|
||||
boundUserInterface.Dispose();
|
||||
@@ -94,7 +89,8 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
internal void SendMessage(BoundUserInterfaceMessage message, object uiKey)
|
||||
{
|
||||
SendNetworkMessage(new BoundInterfaceMessageWrapMessage(message, uiKey));
|
||||
EntitySystem.Get<UserInterfaceSystem>()
|
||||
.Send(new BoundUIWrapMessage(Owner.Uid, message, uiKey));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,6 @@ namespace Robust.Client.GameObjects
|
||||
_broadPhaseSystem = Get<SharedBroadPhaseSystem>();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
UnsubscribeNetworkEvent<PlayAudioEntityMessage>();
|
||||
UnsubscribeNetworkEvent<PlayAudioGlobalMessage>();
|
||||
UnsubscribeNetworkEvent<PlayAudioPositionalMessage>();
|
||||
UnsubscribeNetworkEvent<StopAudioMessageClient>();
|
||||
|
||||
UnsubscribeLocalEvent<SoundSystem.QueryAudioSystem>();
|
||||
}
|
||||
|
||||
private void StopAudioMessageHandler(StopAudioMessageClient ev)
|
||||
{
|
||||
var stream = _playingClydeStreams.Find(p => p.NetIdentifier == ev.Identifier);
|
||||
@@ -265,7 +254,7 @@ namespace Robust.Client.GameObjects
|
||||
if (!source.SetPosition(entity.Transform.WorldPosition))
|
||||
{
|
||||
source.Dispose();
|
||||
Logger.Warning("Can't play positional audio, can't set position.");
|
||||
Logger.Warning($"Can't play positional audio \"{stream.Name}\", can't set position.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -312,7 +301,7 @@ namespace Robust.Client.GameObjects
|
||||
if (!source.SetPosition(coordinates.ToMapPos(EntityManager)))
|
||||
{
|
||||
source.Dispose();
|
||||
Logger.Warning("Can't play positional audio, can't set position.");
|
||||
Logger.Warning("Can't play positional audio \"{stream.Name}\", can't set position.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,15 +38,6 @@ namespace Robust.Client.GameObjects
|
||||
SubscribeLocalEvent<ClientOccluderComponent, SnapGridPositionChangedEvent>(HandleSnapGridMove);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Shutdown()
|
||||
{
|
||||
UnsubscribeLocalEvent<OccluderDirtyEvent>();
|
||||
UnsubscribeLocalEvent<ClientOccluderComponent, SnapGridPositionChangedEvent>();
|
||||
|
||||
base.Shutdown();
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#if DEBUG
|
||||
using System;
|
||||
using System.Text;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
internal sealed class DebugGridTileLookupSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
if (_enabled == value) return;
|
||||
_enabled = value;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
_label.Visible = true;
|
||||
LastTile = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
_label.Text = null;
|
||||
_label.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enabled;
|
||||
|
||||
private (GridId Grid, Vector2i Indices) LastTile;
|
||||
|
||||
// Label and shit that follows cursor
|
||||
private Label _label = new()
|
||||
{
|
||||
Visible = false,
|
||||
};
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<SendGridTileLookupMessage>(HandleSentEntities);
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.AddChild(_label);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
UnsubscribeNetworkEvent<SendGridTileLookupMessage>();
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.RemoveChild(_label);
|
||||
}
|
||||
|
||||
private void RequestEntities(GridId gridId, Vector2i indices)
|
||||
{
|
||||
if (gridId == GridId.Invalid) return;
|
||||
RaiseNetworkEvent(new RequestGridTileLookupMessage(gridId, indices));
|
||||
}
|
||||
|
||||
private void HandleSentEntities(SendGridTileLookupMessage message)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
var text = new StringBuilder();
|
||||
text.AppendLine($"GridId: {LastTile.Grid}, Tile: {LastTile.Indices}");
|
||||
|
||||
for (var i = 0; i < message.Entities.Count; i++)
|
||||
{
|
||||
var uid = message.Entities[i];
|
||||
|
||||
if (!EntityManager.TryGetEntity(uid, out var entity)) continue;
|
||||
|
||||
text.AppendLine(entity.ToString());
|
||||
}
|
||||
|
||||
_label.Text = text.ToString();
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
if (!Enabled) return;
|
||||
|
||||
var mousePos = _inputManager.MouseScreenPosition;
|
||||
var worldPos = _eyeManager.ScreenToMap(mousePos);
|
||||
|
||||
GridId gridId;
|
||||
Vector2i tile;
|
||||
|
||||
if (_mapManager.TryFindGridAt(worldPos, out var grid))
|
||||
{
|
||||
gridId = grid.Index;
|
||||
tile = grid.WorldToTile(worldPos.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
gridId = GridId.Invalid;
|
||||
tile = new Vector2i((int) MathF.Floor(worldPos.Position.X), (int) MathF.Floor(worldPos.Position.Y));
|
||||
}
|
||||
|
||||
LayoutContainer.SetPosition(_label, mousePos.Position);
|
||||
|
||||
if ((gridId, tile).Equals(LastTile)) return;
|
||||
|
||||
_label.Text = null;
|
||||
LastTile = (gridId, tile);
|
||||
RequestEntities(gridId, tile);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RequestTileEntities : IConsoleCommand
|
||||
{
|
||||
public string Command => "tilelookup";
|
||||
public string Description => "Used for debugging GridTileLookupSystem";
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<DebugGridTileLookupSystem>().Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -67,9 +67,10 @@ namespace Robust.Client.GameObjects
|
||||
//Create effect from creation message
|
||||
var effect = new Effect(message, resourceCache, _mapManager, _entityManager);
|
||||
effect.Deathtime = gameTiming.CurTime + message.LifeTime;
|
||||
if (effect.AttachedEntityUid != null)
|
||||
if (effect.AttachedEntityUid != null
|
||||
&& _entityManager.TryGetEntity(effect.AttachedEntityUid.Value, out var attachedEntity))
|
||||
{
|
||||
effect.AttachedEntity = _entityManager.GetEntity(effect.AttachedEntityUid.Value);
|
||||
effect.AttachedEntity = attachedEntity;
|
||||
}
|
||||
|
||||
_Effects.Add(effect);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Physics;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -6,6 +8,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
@@ -47,14 +50,171 @@ namespace Robust.Client.GameObjects
|
||||
_mapManager.OnGridCreated += MapManagerOnGridCreated;
|
||||
_mapManager.OnGridRemoved += MapManagerOnGridRemoved;
|
||||
|
||||
SubscribeLocalEvent<EntMapIdChangedMessage>(EntMapIdChanged);
|
||||
SubscribeLocalEvent<MoveEvent>(EntMoved);
|
||||
SubscribeLocalEvent<EntParentChangedMessage>(EntParentChanged);
|
||||
SubscribeLocalEvent<PointLightRadiusChangedMessage>(PointLightRadiusChanged);
|
||||
SubscribeLocalEvent<RenderTreeRemoveSpriteMessage>(RemoveSprite);
|
||||
SubscribeLocalEvent<RenderTreeRemoveLightMessage>(RemoveLight);
|
||||
// Due to how recursion works, this must be done.
|
||||
SubscribeLocalEvent<MoveEvent>(AnythingMoved);
|
||||
|
||||
SubscribeLocalEvent<SpriteComponent, EntMapIdChangedMessage>(SpriteMapChanged);
|
||||
SubscribeLocalEvent<SpriteComponent, MoveEvent>(SpriteMoved);
|
||||
SubscribeLocalEvent<SpriteComponent, EntParentChangedMessage>(SpriteParentChanged);
|
||||
SubscribeLocalEvent<SpriteComponent, ComponentRemove>(RemoveSprite);
|
||||
|
||||
SubscribeLocalEvent<PointLightComponent, EntMapIdChangedMessage>(LightMapChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, MoveEvent>(LightMoved);
|
||||
SubscribeLocalEvent<PointLightComponent, EntParentChangedMessage>(LightParentChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, PointLightRadiusChangedEvent>(PointLightRadiusChanged);
|
||||
SubscribeLocalEvent<PointLightComponent, RenderTreeRemoveLightEvent>(RemoveLight);
|
||||
}
|
||||
|
||||
private void AnythingMoved(MoveEvent args)
|
||||
{
|
||||
AnythingMovedSubHandler(args.Sender.Transform);
|
||||
}
|
||||
|
||||
private void AnythingMovedSubHandler(ITransformComponent sender)
|
||||
{
|
||||
// This recursive search is needed, as MoveEvent is defined to not care about indirect events like children.
|
||||
// WHATEVER YOU DO, DON'T REPLACE THIS WITH SPAMMING EVENTS UNLESS YOU HAVE A GUARANTEE IT WON'T LAG THE GC.
|
||||
// (Struct-based events ok though)
|
||||
if (sender.Owner.TryGetComponent(out SpriteComponent? sprite))
|
||||
QueueSpriteUpdate(sprite);
|
||||
if (sender.Owner.TryGetComponent(out PointLightComponent? light))
|
||||
QueueLightUpdate(light);
|
||||
foreach (ITransformComponent child in sender.Children)
|
||||
{
|
||||
AnythingMovedSubHandler(child);
|
||||
}
|
||||
}
|
||||
|
||||
// For the RemoveX methods
|
||||
// If the Transform is removed BEFORE the Sprite/Light,
|
||||
// then the MapIdChanged code will handle and remove it (because MapId gets set to nullspace).
|
||||
// Otherwise these will still have their past MapId and that's all we need..
|
||||
|
||||
#region SpriteHandlers
|
||||
private void SpriteMapChanged(EntityUid uid, SpriteComponent component, EntMapIdChangedMessage args)
|
||||
{
|
||||
QueueSpriteUpdate(component);
|
||||
}
|
||||
|
||||
private void SpriteMoved(EntityUid uid, SpriteComponent component, MoveEvent args)
|
||||
{
|
||||
QueueSpriteUpdate(component);
|
||||
}
|
||||
|
||||
private void SpriteParentChanged(EntityUid uid, SpriteComponent component, EntParentChangedMessage args)
|
||||
{
|
||||
QueueSpriteUpdate(component);
|
||||
}
|
||||
|
||||
private void RemoveSprite(EntityUid uid, SpriteComponent component, ComponentRemove args)
|
||||
{
|
||||
ClearSprite(component);
|
||||
}
|
||||
|
||||
private void ClearSprite(SpriteComponent component)
|
||||
{
|
||||
if (_gridTrees.TryGetValue(component.IntersectingMapId, out var gridTrees))
|
||||
{
|
||||
foreach (var gridId in component.IntersectingGrids)
|
||||
{
|
||||
if (!gridTrees.TryGetValue(gridId, out var tree)) continue;
|
||||
tree.SpriteTree.Remove(component);
|
||||
}
|
||||
}
|
||||
|
||||
component.IntersectingGrids.Clear();
|
||||
}
|
||||
|
||||
private void QueueSpriteUpdate(SpriteComponent component)
|
||||
{
|
||||
if (component.TreeUpdateQueued) return;
|
||||
|
||||
component.TreeUpdateQueued = true;
|
||||
_spriteQueue.Add(component);
|
||||
|
||||
foreach (var child in component.Owner.Transform.Children)
|
||||
{
|
||||
QueueSpriteUpdate(child.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private void QueueSpriteUpdate(IEntity entity)
|
||||
{
|
||||
if (!entity.TryGetComponent(out SpriteComponent? spriteComponent)) return;
|
||||
QueueSpriteUpdate(spriteComponent);
|
||||
|
||||
foreach (var child in entity.Transform.Children)
|
||||
{
|
||||
QueueSpriteUpdate(child.Owner);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LightHandlers
|
||||
private void LightMapChanged(EntityUid uid, PointLightComponent component, EntMapIdChangedMessage args)
|
||||
{
|
||||
QueueLightUpdate(component);
|
||||
}
|
||||
|
||||
private void LightMoved(EntityUid uid, PointLightComponent component, MoveEvent args)
|
||||
{
|
||||
QueueLightUpdate(component);
|
||||
}
|
||||
|
||||
private void LightParentChanged(EntityUid uid, PointLightComponent component, EntParentChangedMessage args)
|
||||
{
|
||||
QueueLightUpdate(component);
|
||||
}
|
||||
|
||||
private void PointLightRadiusChanged(EntityUid uid, PointLightComponent component, PointLightRadiusChangedEvent args)
|
||||
{
|
||||
QueueLightUpdate(component);
|
||||
}
|
||||
|
||||
private void RemoveLight(EntityUid uid, PointLightComponent component, RenderTreeRemoveLightEvent args)
|
||||
{
|
||||
ClearLight(component);
|
||||
}
|
||||
|
||||
private void ClearLight(PointLightComponent component)
|
||||
{
|
||||
if (_gridTrees.TryGetValue(component.IntersectingMapId, out var gridTrees))
|
||||
{
|
||||
foreach (var gridId in component.IntersectingGrids)
|
||||
{
|
||||
if (!gridTrees.TryGetValue(gridId, out var tree)) continue;
|
||||
tree.LightTree.Remove(component);
|
||||
}
|
||||
}
|
||||
|
||||
component.IntersectingGrids.Clear();
|
||||
}
|
||||
|
||||
private void QueueLightUpdate(PointLightComponent component)
|
||||
{
|
||||
if (component.TreeUpdateQueued) return;
|
||||
|
||||
component.TreeUpdateQueued = true;
|
||||
_lightQueue.Add(component);
|
||||
|
||||
foreach (var child in component.Owner.Transform.Children)
|
||||
{
|
||||
QueueLightUpdate(child.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private void QueueLightUpdate(IEntity entity)
|
||||
{
|
||||
if (!entity.TryGetComponent(out PointLightComponent? lightComponent)) return;
|
||||
QueueLightUpdate(lightComponent);
|
||||
|
||||
foreach (var child in entity.Transform.Children)
|
||||
{
|
||||
QueueLightUpdate(child.Owner);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
@@ -62,136 +222,27 @@ namespace Robust.Client.GameObjects
|
||||
_mapManager.MapDestroyed -= MapManagerOnMapDestroyed;
|
||||
_mapManager.OnGridCreated -= MapManagerOnGridCreated;
|
||||
_mapManager.OnGridRemoved -= MapManagerOnGridRemoved;
|
||||
|
||||
UnsubscribeLocalEvent<EntMapIdChangedMessage>();
|
||||
UnsubscribeLocalEvent<MoveEvent>();
|
||||
UnsubscribeLocalEvent<EntParentChangedMessage>();
|
||||
UnsubscribeLocalEvent<PointLightRadiusChangedMessage>();
|
||||
UnsubscribeLocalEvent<RenderTreeRemoveSpriteMessage>();
|
||||
UnsubscribeLocalEvent<RenderTreeRemoveLightMessage>();
|
||||
}
|
||||
|
||||
// For these next 2 methods (the Remove* ones):
|
||||
// If the Transform is removed BEFORE the Sprite/Light,
|
||||
// then the MapIdChanged code will handle and remove it (because MapId gets set to nullspace).
|
||||
// Otherwise these will still have their past MapId and that's all we need..
|
||||
private void RemoveLight(RenderTreeRemoveLightMessage ev)
|
||||
{
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Map, MapTrees.LightAabbFunc(ev.Light), true))
|
||||
{
|
||||
_gridTrees[ev.Map][gridId].LightTree.Remove(ev.Light);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveSprite(RenderTreeRemoveSpriteMessage ev)
|
||||
{
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Map, MapTrees.SpriteAabbFunc(ev.Sprite), true))
|
||||
{
|
||||
_gridTrees[ev.Map][gridId].SpriteTree.Remove(ev.Sprite);
|
||||
}
|
||||
}
|
||||
|
||||
private void PointLightRadiusChanged(PointLightRadiusChangedMessage ev)
|
||||
{
|
||||
QueueUpdateLight(ev.PointLightComponent);
|
||||
}
|
||||
|
||||
private void EntParentChanged(EntParentChangedMessage ev)
|
||||
{
|
||||
UpdateEntity(ev.Entity);
|
||||
}
|
||||
|
||||
private void EntMoved(MoveEvent ev)
|
||||
{
|
||||
UpdateEntity(ev.Sender);
|
||||
}
|
||||
|
||||
private void UpdateEntity(IEntity entity)
|
||||
{
|
||||
if (entity.TryGetComponent(out SpriteComponent? spriteComponent))
|
||||
{
|
||||
if (!spriteComponent.TreeUpdateQueued)
|
||||
{
|
||||
spriteComponent.TreeUpdateQueued = true;
|
||||
|
||||
_spriteQueue.Add(spriteComponent);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
QueueUpdateLight(light);
|
||||
}
|
||||
|
||||
foreach (var child in entity.Transform.ChildEntityUids)
|
||||
{
|
||||
UpdateEntity(EntityManager.GetEntity(child));
|
||||
}
|
||||
}
|
||||
|
||||
private void QueueUpdateLight(PointLightComponent light)
|
||||
{
|
||||
if (!light.TreeUpdateQueued)
|
||||
{
|
||||
light.TreeUpdateQueued = true;
|
||||
|
||||
_lightQueue.Add(light);
|
||||
}
|
||||
}
|
||||
|
||||
private void EntMapIdChanged(EntMapIdChangedMessage ev)
|
||||
{
|
||||
// Nullspace is a valid map ID for stuff to have but we also aren't gonna bother indexing it.
|
||||
// So that's why there's a GetValueOrDefault.
|
||||
var oldMapTrees = _gridTrees.GetValueOrDefault(ev.OldMapId);
|
||||
var newMapTrees = _gridTrees.GetValueOrDefault(ev.Entity.Transform.MapID);
|
||||
|
||||
// TODO: MMMM probably a better way to do this.
|
||||
if (ev.Entity.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
if (oldMapTrees != null)
|
||||
{
|
||||
foreach (var (_, gridTree) in oldMapTrees)
|
||||
{
|
||||
gridTree.SpriteTree.Remove(sprite);
|
||||
}
|
||||
}
|
||||
|
||||
var bounds = MapTrees.SpriteAabbFunc(sprite);
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Entity.Transform.MapID, bounds, true))
|
||||
{
|
||||
var gridBounds = gridId == GridId.Invalid
|
||||
? bounds : bounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
|
||||
newMapTrees?[gridId].SpriteTree.AddOrUpdate(sprite, gridBounds);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.Entity.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
if (oldMapTrees != null)
|
||||
{
|
||||
foreach (var (_, gridTree) in oldMapTrees)
|
||||
{
|
||||
gridTree.LightTree.Remove(light);
|
||||
}
|
||||
}
|
||||
|
||||
var bounds = MapTrees.LightAabbFunc(light);
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(ev.Entity.Transform.MapID, bounds, true))
|
||||
{
|
||||
var gridBounds = gridId == GridId.Invalid
|
||||
? bounds : bounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
|
||||
newMapTrees?[gridId].LightTree.AddOrUpdate(light, gridBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MapManagerOnMapDestroyed(object? sender, MapEventArgs e)
|
||||
{
|
||||
foreach (var (_, gridTree) in _gridTrees[e.Map])
|
||||
{
|
||||
foreach (var comp in gridTree.LightTree)
|
||||
{
|
||||
comp.IntersectingGrids.Clear();
|
||||
}
|
||||
|
||||
foreach (var comp in gridTree.SpriteTree)
|
||||
{
|
||||
comp.IntersectingGrids.Clear();
|
||||
}
|
||||
|
||||
// Just in case?
|
||||
gridTree.LightTree.Clear();
|
||||
gridTree.SpriteTree.Clear();
|
||||
}
|
||||
|
||||
_gridTrees.Remove(e.Map);
|
||||
}
|
||||
|
||||
@@ -215,47 +266,109 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
private void MapManagerOnGridRemoved(MapId mapId, GridId gridId)
|
||||
{
|
||||
var gridTree = _gridTrees[mapId][gridId];
|
||||
|
||||
foreach (var sprite in gridTree.SpriteTree)
|
||||
{
|
||||
sprite.IntersectingGrids.Remove(gridId);
|
||||
}
|
||||
|
||||
foreach (var light in gridTree.LightTree)
|
||||
{
|
||||
light.IntersectingGrids.Remove(gridId);
|
||||
}
|
||||
|
||||
// Clear in case
|
||||
gridTree.LightTree.Clear();
|
||||
gridTree.SpriteTree.Clear();
|
||||
_gridTrees[mapId].Remove(gridId);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
foreach (var queuedUpdateSprite in _spriteQueue)
|
||||
foreach (var sprite in _spriteQueue)
|
||||
{
|
||||
var map = queuedUpdateSprite.Owner.Transform.MapID;
|
||||
if (map == MapId.Nullspace)
|
||||
var mapId = sprite.Owner.Transform.MapID;
|
||||
|
||||
// If we're on a new map then clear the old one.
|
||||
if (sprite.IntersectingMapId != mapId)
|
||||
{
|
||||
continue;
|
||||
ClearSprite(sprite);
|
||||
}
|
||||
|
||||
var mapTree = _gridTrees[map];
|
||||
sprite.IntersectingMapId = mapId;
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(map,
|
||||
MapTrees.SpriteAabbFunc(queuedUpdateSprite), true))
|
||||
if (mapId == MapId.Nullspace) continue;
|
||||
|
||||
var mapTree = _gridTrees[mapId];
|
||||
var aabb = MapTrees.SpriteAabbFunc(sprite);
|
||||
var intersectingGrids = _mapManager.FindGridIdsIntersecting(mapId, aabb, true).ToList();
|
||||
|
||||
// Remove from old
|
||||
foreach (var gridId in sprite.IntersectingGrids)
|
||||
{
|
||||
mapTree[gridId].SpriteTree.AddOrUpdate(queuedUpdateSprite);
|
||||
if (intersectingGrids.Contains(gridId)) continue;
|
||||
mapTree[gridId].SpriteTree.Remove(sprite);
|
||||
}
|
||||
|
||||
queuedUpdateSprite.TreeUpdateQueued = false;
|
||||
// Rebuild in the update below
|
||||
sprite.IntersectingGrids.Clear();
|
||||
|
||||
// Update / add to new
|
||||
foreach (var gridId in intersectingGrids)
|
||||
{
|
||||
var translated = aabb.Translated(gridId == GridId.Invalid
|
||||
? Vector2.Zero
|
||||
: -_mapManager.GetGrid(gridId).WorldPosition);
|
||||
|
||||
mapTree[gridId].SpriteTree.AddOrUpdate(sprite, translated);
|
||||
|
||||
sprite.IntersectingGrids.Add(gridId);
|
||||
}
|
||||
|
||||
sprite.TreeUpdateQueued = false;
|
||||
}
|
||||
|
||||
foreach (var queuedUpdateLight in _lightQueue)
|
||||
foreach (var light in _lightQueue)
|
||||
{
|
||||
var map = queuedUpdateLight.Owner.Transform.MapID;
|
||||
if (map == MapId.Nullspace)
|
||||
var mapId = light.Owner.Transform.MapID;
|
||||
|
||||
// If we're on a new map then clear the old one.
|
||||
if (light.IntersectingMapId != mapId)
|
||||
{
|
||||
continue;
|
||||
ClearLight(light);
|
||||
}
|
||||
|
||||
var mapTree = _gridTrees[map];
|
||||
light.IntersectingMapId = mapId;
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(map,
|
||||
MapTrees.LightAabbFunc(queuedUpdateLight), true))
|
||||
if (mapId == MapId.Nullspace) continue;
|
||||
|
||||
var mapTree = _gridTrees[mapId];
|
||||
var aabb = MapTrees.LightAabbFunc(light);
|
||||
var intersectingGrids = _mapManager.FindGridIdsIntersecting(mapId, aabb, true).ToList();
|
||||
|
||||
// Remove from old
|
||||
foreach (var gridId in intersectingGrids)
|
||||
{
|
||||
mapTree[gridId].LightTree.AddOrUpdate(queuedUpdateLight);
|
||||
if (intersectingGrids.Contains(gridId)) continue;
|
||||
mapTree[gridId].LightTree.Remove(light);
|
||||
}
|
||||
|
||||
queuedUpdateLight.TreeUpdateQueued = false;
|
||||
// Rebuild in the update below
|
||||
light.IntersectingGrids.Clear();
|
||||
|
||||
// Update / add to new
|
||||
foreach (var gridId in intersectingGrids)
|
||||
{
|
||||
var translated = aabb.Translated(gridId == GridId.Invalid
|
||||
? Vector2.Zero
|
||||
: -_mapManager.GetGrid(gridId).WorldPosition);
|
||||
|
||||
mapTree[gridId].LightTree.AddOrUpdate(light, translated);
|
||||
light.IntersectingGrids.Add(gridId);
|
||||
}
|
||||
|
||||
light.TreeUpdateQueued = false;
|
||||
}
|
||||
|
||||
_spriteQueue.Clear();
|
||||
@@ -290,21 +403,9 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
internal struct RenderTreeRemoveSpriteMessage
|
||||
internal class RenderTreeRemoveLightEvent : EntityEventArgs
|
||||
{
|
||||
public RenderTreeRemoveSpriteMessage(SpriteComponent sprite, MapId map)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Map = map;
|
||||
}
|
||||
|
||||
public SpriteComponent Sprite { get; }
|
||||
public MapId Map { get; }
|
||||
}
|
||||
|
||||
internal struct RenderTreeRemoveLightMessage
|
||||
{
|
||||
public RenderTreeRemoveLightMessage(PointLightComponent light, MapId map)
|
||||
public RenderTreeRemoveLightEvent(PointLightComponent light, MapId map)
|
||||
{
|
||||
Light = light;
|
||||
Map = map;
|
||||
|
||||
@@ -16,11 +16,17 @@ namespace Robust.Client.GameObjects
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private RenderingTreeSystem _treeSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_treeSystem = Get<RenderingTreeSystem>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
var renderTreeSystem = EntitySystemManager.GetEntitySystem<RenderingTreeSystem>();
|
||||
|
||||
// So we could calculate the correct size of the entities based on the contents of their sprite...
|
||||
// Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
|
||||
var pvsBounds = _eyeManager.GetWorldViewport().Enlarged(5);
|
||||
@@ -33,18 +39,9 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(currentMap, pvsBounds, true))
|
||||
{
|
||||
Box2 gridBounds;
|
||||
var gridBounds = gridId == GridId.Invalid ? pvsBounds : pvsBounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
|
||||
if (gridId == GridId.Invalid)
|
||||
{
|
||||
gridBounds = pvsBounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBounds = pvsBounds.Translated(-_mapManager.GetGrid(gridId).WorldPosition);
|
||||
}
|
||||
|
||||
var mapTree = renderTreeSystem.GetSpriteTreeForMap(currentMap, gridId);
|
||||
var mapTree = _treeSystem.GetSpriteTreeForMap(currentMap, gridId);
|
||||
|
||||
mapTree.QueryAabb(ref frameTime, (ref float state, in SpriteComponent value) =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class UserInterfaceSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<BoundUIWrapMessage>(MessageReceived);
|
||||
SubscribeLocalEvent<ClientUserInterfaceComponent, ComponentShutdown>(OnUserInterfaceShutdown);
|
||||
}
|
||||
|
||||
private void OnUserInterfaceShutdown(EntityUid uid, ClientUserInterfaceComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var bui in component.Interfaces)
|
||||
{
|
||||
bui.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void MessageReceived(BoundUIWrapMessage ev)
|
||||
{
|
||||
var cmp = ComponentManager.GetComponent<ClientUserInterfaceComponent>(ev.Entity);
|
||||
|
||||
cmp.MessageReceived(ev);
|
||||
}
|
||||
|
||||
internal void Send(BoundUIWrapMessage msg)
|
||||
{
|
||||
RaiseNetworkEvent(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public class PlayerAttachedMsg : ComponentMessage
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public class PlayerDetachedMsg : ComponentMessage
|
||||
{
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
// Used in EXCEPTION_TOLERANCE preprocessor
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -5,19 +7,18 @@ using System.Linq;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.Timing;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Input;
|
||||
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;
|
||||
|
||||
@@ -80,8 +81,8 @@ namespace Robust.Client.GameStates
|
||||
{
|
||||
_processor = new GameStateProcessor(_timing);
|
||||
|
||||
_network.RegisterNetMessage<MsgState>(MsgState.NAME, HandleStateMessage);
|
||||
_network.RegisterNetMessage<MsgStateAck>(MsgStateAck.NAME);
|
||||
_network.RegisterNetMessage<MsgState>(HandleStateMessage);
|
||||
_network.RegisterNetMessage<MsgStateAck>();
|
||||
_client.RunLevelChanged += RunLevelChanged;
|
||||
|
||||
_config.OnValueChanged(CVars.NetInterp, b => _processor.Interpolation = b, true);
|
||||
|
||||
@@ -146,13 +146,12 @@ namespace Robust.Client.GameStates
|
||||
private void DrawWorld(in OverlayDrawArgs args)
|
||||
{
|
||||
bool pvsEnabled = _configurationManager.GetCVar<bool>("net.pvs");
|
||||
|
||||
if(!pvsEnabled)
|
||||
return;
|
||||
|
||||
float pvsSize = _configurationManager.GetCVar<float>("net.maxupdaterange");
|
||||
float pvsRange = _configurationManager.GetCVar<float>("net.maxupdaterange");
|
||||
var pvsCenter = _eyeManager.CurrentEye.Position;
|
||||
Box2 pvsBox = Box2.CenteredAround(pvsCenter.Position, new Vector2(pvsSize, pvsSize));
|
||||
Box2 pvsBox = Box2.CenteredAround(pvsCenter.Position, new Vector2(pvsRange * 2, pvsRange * 2));
|
||||
|
||||
var worldHandle = args.WorldHandle;
|
||||
|
||||
|
||||
@@ -44,8 +44,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
internal bool IsEfxSupported;
|
||||
|
||||
private ISawmill _openALSawmill = default!;
|
||||
|
||||
private void _initializeAudio()
|
||||
{
|
||||
_openALSawmill = Logger.GetSawmill("clyde.oal");
|
||||
|
||||
_audioOpenDevice();
|
||||
|
||||
// Create OpenAL context.
|
||||
@@ -74,9 +78,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_alContextExtensions.Add(extension);
|
||||
}
|
||||
|
||||
Logger.DebugS("clyde.oal", "OpenAL Vendor: {0}", AL.Get(ALGetString.Vendor));
|
||||
Logger.DebugS("clyde.oal", "OpenAL Renderer: {0}", AL.Get(ALGetString.Renderer));
|
||||
Logger.DebugS("clyde.oal", "OpenAL Version: {0}", AL.Get(ALGetString.Version));
|
||||
_openALSawmill.Debug("OpenAL Vendor: {0}", AL.Get(ALGetString.Vendor));
|
||||
_openALSawmill.Debug("OpenAL Renderer: {0}", AL.Get(ALGetString.Renderer));
|
||||
_openALSawmill.Debug("OpenAL Version: {0}", AL.Get(ALGetString.Version));
|
||||
}
|
||||
|
||||
private void _audioOpenDevice()
|
||||
@@ -89,7 +93,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_openALDevice = ALC.OpenDevice(preferredDevice);
|
||||
if (_openALDevice == IntPtr.Zero)
|
||||
{
|
||||
Logger.WarningS("clyde.oal", "Unable to open preferred audio device '{0}': {1}. Falling back default.",
|
||||
_openALSawmill.Warning("Unable to open preferred audio device '{0}': {1}. Falling back default.",
|
||||
preferredDevice, ALC.GetError(ALDevice.Null));
|
||||
|
||||
_openALDevice = ALC.OpenDevice(null);
|
||||
@@ -153,7 +157,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Clear out finalized audio sources.
|
||||
while (_sourceDisposeQueue.TryDequeue(out var handles))
|
||||
{
|
||||
Logger.DebugS("clyde.oal", "Cleaning out source {0} which finalized in another thread.", handles.sourceHandle);
|
||||
_openALSawmill.Debug("Cleaning out source {0} which finalized in another thread.", handles.sourceHandle);
|
||||
if (IsEfxSupported) RemoveEfx(handles);
|
||||
AL.DeleteSource(handles.sourceHandle);
|
||||
_checkAlError();
|
||||
@@ -163,7 +167,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Clear out finalized buffered audio sources.
|
||||
while (_bufferedSourceDisposeQueue.TryDequeue(out var handles))
|
||||
{
|
||||
Logger.DebugS("clyde.oal", "Cleaning out buffered source {0} which finalized in another thread.", handles.sourceHandle);
|
||||
_openALSawmill.Debug("Cleaning out buffered source {0} which finalized in another thread.", handles.sourceHandle);
|
||||
if (IsEfxSupported) RemoveEfx(handles);
|
||||
AL.DeleteSource(handles.sourceHandle);
|
||||
_checkAlError();
|
||||
@@ -211,24 +215,24 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return audioSource;
|
||||
}
|
||||
|
||||
private static void _checkAlcError(ALDevice device,
|
||||
private void _checkAlcError(ALDevice device,
|
||||
[CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = -1)
|
||||
{
|
||||
var error = ALC.GetError(device);
|
||||
if (error != AlcError.NoError)
|
||||
{
|
||||
Logger.ErrorS("clyde.oal", "[{0}:{1}] ALC error: {2}", callerMember, callerLineNumber, error);
|
||||
_openALSawmill.Error("[{0}:{1}] ALC error: {2}", callerMember, callerLineNumber, error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _checkAlError([CallerMemberName] string callerMember = "",
|
||||
private void _checkAlError([CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = -1)
|
||||
{
|
||||
var error = AL.GetError();
|
||||
if (error != ALError.NoError)
|
||||
{
|
||||
Logger.ErrorS("clyde.oal", "[{0}:{1}] AL error: {2}", callerMember, callerLineNumber, error);
|
||||
_openALSawmill.Error("[{0}:{1}] AL error: {2}", callerMember, callerLineNumber, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +334,35 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return new AudioStream(handle, length, wav.NumChannels, name);
|
||||
}
|
||||
|
||||
public AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null)
|
||||
{
|
||||
var fmt = channels switch
|
||||
{
|
||||
1 => ALFormat.Mono16,
|
||||
2 => ALFormat.Stereo16,
|
||||
_ => throw new ArgumentOutOfRangeException(
|
||||
nameof(channels), "Only stereo and mono is currently supported")
|
||||
};
|
||||
|
||||
var buffer = AL.GenBuffer();
|
||||
_checkAlError();
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (short* ptr = samples)
|
||||
{
|
||||
AL.BufferData(buffer, fmt, (IntPtr) ptr, samples.Length * sizeof(short), sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
_checkAlError();
|
||||
|
||||
var handle = new ClydeHandle(_audioSampleBuffers.Count);
|
||||
var length = TimeSpan.FromSeconds((double) samples.Length / channels / sampleRate);
|
||||
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
|
||||
return new AudioStream(handle, length, channels, name);
|
||||
}
|
||||
|
||||
private sealed class LoadedAudioSample
|
||||
{
|
||||
public readonly int BufferHandle;
|
||||
@@ -381,14 +414,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.SourcePlay(SourceHandle);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void StopPlaying()
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.SourceStop(SourceHandle);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public bool IsPlaying
|
||||
@@ -407,14 +440,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.GetSource(SourceHandle, ALSourceb.Looping, out var ret);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
return ret;
|
||||
}
|
||||
set
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.Source(SourceHandle, ALSourceb.Looping, value);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +455,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.Source(SourceHandle, ALSourceb.SourceRelative, true);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetVolume(float decibels)
|
||||
@@ -436,7 +469,21 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
_gain = MathF.Pow(10, decibels / 10);
|
||||
AL.Source(SourceHandle, ALSourcef.Gain, _gain * priorOcclusion);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetVolumeDirect(float scale)
|
||||
{
|
||||
_checkDisposed();
|
||||
var priorOcclusion = 1f;
|
||||
if (!IsEfxSupported)
|
||||
{
|
||||
AL.GetSource(SourceHandle, ALSourcef.Gain, out var priorGain);
|
||||
priorOcclusion = priorGain / _gain;
|
||||
}
|
||||
_gain = scale;
|
||||
AL.Source(SourceHandle, ALSourcef.Gain, _gain * priorOcclusion);
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetOcclusion(float blocks)
|
||||
@@ -453,7 +500,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
gain *= gain * gain;
|
||||
AL.Source(SourceHandle, ALSourcef.Gain, _gain * gain);
|
||||
}
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
private void SetOcclusionEfx(float gain, float cutoff)
|
||||
@@ -473,7 +520,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.Source(SourceHandle, ALSourcef.SecOffset, seconds);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public bool SetPosition(Vector2 position)
|
||||
@@ -499,7 +546,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
#endif
|
||||
|
||||
AL.Source(SourceHandle, ALSource3f.Position, x, y, 0);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -526,14 +573,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
AL.Source(SourceHandle, ALSource3f.Velocity, x, y, 0);
|
||||
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetPitch(float pitch)
|
||||
{
|
||||
_checkDisposed();
|
||||
AL.Source(SourceHandle, ALSourcef.Pitch, pitch);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
~AudioSource()
|
||||
@@ -559,7 +606,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
if (FilterHandle != 0) EFX.DeleteFilter(FilterHandle);
|
||||
AL.DeleteSource(SourceHandle);
|
||||
_master._audioSources.Remove(SourceHandle);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
SourceHandle = -1;
|
||||
@@ -609,7 +656,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_checkDisposed();
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.SourcePlay(stackalloc int[] {SourceHandle!.Value});
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void StopPlaying()
|
||||
@@ -617,7 +664,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_checkDisposed();
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.SourceStop(SourceHandle!.Value);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public bool IsPlaying
|
||||
@@ -643,7 +690,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_mono = false;
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.Source(SourceHandle!.Value, ALSourceb.SourceRelative, true);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetLooping()
|
||||
@@ -662,7 +709,21 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
_gain = MathF.Pow(10, decibels / 10);
|
||||
AL.Source(SourceHandle!.Value, ALSourcef.Gain, _gain * priorOcclusion);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetVolumeDirect(float scale)
|
||||
{
|
||||
_checkDisposed();
|
||||
var priorOcclusion = 1f;
|
||||
if (!IsEfxSupported)
|
||||
{
|
||||
AL.GetSource(SourceHandle!.Value, ALSourcef.Gain, out var priorGain);
|
||||
priorOcclusion = priorGain / _gain;
|
||||
}
|
||||
_gain = scale;
|
||||
AL.Source(SourceHandle!.Value, ALSourcef.Gain, _gain * priorOcclusion);
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetOcclusion(float blocks)
|
||||
@@ -680,7 +741,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
AL.Source(SourceHandle!.Value, ALSourcef.Gain, gain * _gain);
|
||||
}
|
||||
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
private void SetOcclusionEfx(float gain, float cutoff)
|
||||
@@ -700,7 +761,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_checkDisposed();
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.Source(SourceHandle!.Value, ALSourcef.SecOffset, seconds);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public bool SetPosition(Vector2 position)
|
||||
@@ -717,7 +778,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_mono = true;
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.Source(SourceHandle!.Value, ALSource3f.Position, x, y, 0);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -744,7 +805,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
AL.Source(SourceHandle!.Value, ALSource3f.Velocity, x, y, 0);
|
||||
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
public void SetPitch(float pitch)
|
||||
@@ -752,7 +813,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_checkDisposed();
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
AL.Source(SourceHandle!.Value, ALSourcef.Pitch, pitch);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
~BufferedAudioSource()
|
||||
@@ -783,7 +844,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
AL.DeleteSource(SourceHandle.Value);
|
||||
AL.DeleteBuffers(BufferHandles);
|
||||
_master._bufferedAudioSources.Remove(SourceHandle.Value);
|
||||
_checkAlError();
|
||||
_master._checkAlError();
|
||||
}
|
||||
|
||||
SourceHandle = null;
|
||||
|
||||
@@ -470,18 +470,20 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private sealed class MonitorHandle : IClydeMonitor
|
||||
{
|
||||
public MonitorHandle(int id, string name, Vector2i size, int refreshRate)
|
||||
public MonitorHandle(int id, string name, Vector2i size, int refreshRate, VideoMode[] videoModes)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Size = size;
|
||||
RefreshRate = refreshRate;
|
||||
VideoModes = videoModes;
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
public Vector2i Size { get; }
|
||||
public int RefreshRate { get; }
|
||||
public IEnumerable<VideoMode> VideoModes { get; }
|
||||
}
|
||||
|
||||
private abstract class MonitorReg
|
||||
|
||||
@@ -59,7 +59,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private bool _enableSoftShadows = true;
|
||||
|
||||
private bool _checkGLErrors;
|
||||
private bool _initialized;
|
||||
|
||||
private Thread? _gameThread;
|
||||
|
||||
@@ -105,7 +104,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return false;
|
||||
|
||||
_initializeAudio();
|
||||
_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,14 +48,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public IClydeDebugInfo DebugInfo { get; } = new DummyDebugInfo();
|
||||
public IClydeDebugStats DebugStats { get; } = new DummyDebugStats();
|
||||
|
||||
public event Action<TextEventArgs>? TextEntered;
|
||||
public event Action<MouseMoveEventArgs>? MouseMove;
|
||||
public event Action<MouseEnterLeaveEventArgs>? MouseEnterLeave;
|
||||
public event Action<KeyEventArgs>? KeyUp;
|
||||
public event Action<KeyEventArgs>? KeyDown;
|
||||
public event Action<MouseWheelEventArgs>? MouseWheel;
|
||||
public event Action<WindowClosedEventArgs>? CloseWindow;
|
||||
public event Action<WindowDestroyedEventArgs>? DestroyWindow;
|
||||
public event Action<TextEventArgs>? TextEntered { add { } remove { } }
|
||||
public event Action<MouseMoveEventArgs>? MouseMove { add { } remove { } }
|
||||
public event Action<MouseEnterLeaveEventArgs>? MouseEnterLeave { add { } remove { } }
|
||||
public event Action<KeyEventArgs>? KeyUp { add { } remove { } }
|
||||
public event Action<KeyEventArgs>? KeyDown { add { } remove { } }
|
||||
public event Action<MouseWheelEventArgs>? MouseWheel { add { } remove { } }
|
||||
public event Action<WindowClosedEventArgs>? CloseWindow { add { } remove { } }
|
||||
public event Action<WindowDestroyedEventArgs>? DestroyWindow { add { } remove { } }
|
||||
|
||||
public Texture GetStockTexture(ClydeStockTexture stockTexture)
|
||||
{
|
||||
@@ -248,6 +248,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return new(default, default, 1, name);
|
||||
}
|
||||
|
||||
public AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null)
|
||||
{
|
||||
// TODO: Might wanna actually load this so the length gets reported correctly.
|
||||
return new(default, default, channels, name);
|
||||
}
|
||||
|
||||
public IClydeAudioSource CreateAudioSource(AudioStream stream)
|
||||
{
|
||||
return DummyAudioSource.Instance;
|
||||
@@ -323,6 +329,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Nada.
|
||||
}
|
||||
|
||||
public void SetVolumeDirect(float scale)
|
||||
{
|
||||
// Nada.
|
||||
}
|
||||
|
||||
public void SetOcclusion(float blocks)
|
||||
{
|
||||
// Nada.
|
||||
@@ -594,7 +605,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public bool IsVisible { get; set; } = true;
|
||||
public Vector2 ContentScale => Vector2.One;
|
||||
public bool DisposeOnClose { get; set; }
|
||||
public event Action<WindowClosedEventArgs>? Closed;
|
||||
public event Action<WindowClosedEventArgs>? Closed { add { } remove { } }
|
||||
|
||||
public void MaximizeOnMonitor(IClydeMonitor monitor)
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var impl = (CursorImpl) cursor;
|
||||
DebugTools.Assert(impl.Owner == this);
|
||||
|
||||
if (impl.Id == null)
|
||||
if (impl.Id == default)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(cursor));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenToolkit.GraphicsLibraryFramework;
|
||||
using Robust.Shared.Utility;
|
||||
using GlfwVideoMode = OpenToolkit.GraphicsLibraryFramework.VideoMode;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
@@ -18,7 +20,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private readonly Dictionary<int, WinThreadMonitorReg> _winThreadMonitors = new();
|
||||
|
||||
// Can't use ClydeHandle because it's 64 bit.
|
||||
// TODO: this should be MONITOR ID.
|
||||
private int _nextMonitorId = 1;
|
||||
private int _primaryMonitorId;
|
||||
private readonly Dictionary<int, GlfwMonitorReg> _monitors = new();
|
||||
@@ -39,6 +40,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
ProcessEvents();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void WinThreadSetupMonitor(Monitor* monitor)
|
||||
{
|
||||
var id = _nextMonitorId++;
|
||||
@@ -48,12 +50,31 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var name = GLFW.GetMonitorName(monitor);
|
||||
var videoMode = GLFW.GetVideoMode(monitor);
|
||||
var modesPtr = GLFW.GetVideoModesRaw(monitor, out var modeCount);
|
||||
var modes = new VideoMode[modeCount];
|
||||
for (var i = 0; i < modes.Length; i++)
|
||||
{
|
||||
modes[i] = ConvertVideoMode(modesPtr[i]);
|
||||
}
|
||||
|
||||
GLFW.SetMonitorUserPointer(monitor, (void*) id);
|
||||
|
||||
_winThreadMonitors.Add(id, new WinThreadMonitorReg {Ptr = monitor});
|
||||
|
||||
SendEvent(new EventMonitorSetup(id, name, *videoMode));
|
||||
SendEvent(new EventMonitorSetup(id, name, ConvertVideoMode(*videoMode), modes));
|
||||
}
|
||||
|
||||
private static VideoMode ConvertVideoMode(in GlfwVideoMode mode)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Width = (ushort) mode.Width,
|
||||
Height = (ushort) mode.Height,
|
||||
RedBits = (byte) mode.RedBits,
|
||||
RefreshRate = (ushort) mode.RefreshRate,
|
||||
GreenBits = (byte) mode.GreenBits,
|
||||
BlueBits = (byte) mode.BlueBits,
|
||||
};
|
||||
}
|
||||
|
||||
private void ProcessSetupMonitor(EventMonitorSetup ev)
|
||||
@@ -61,8 +82,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var impl = new MonitorHandle(
|
||||
ev.Id,
|
||||
ev.Name,
|
||||
(ev.Mode.Width, ev.Mode.Height),
|
||||
ev.Mode.RefreshRate);
|
||||
(ev.CurrentMode.Width, ev.CurrentMode.Height),
|
||||
ev.CurrentMode.RefreshRate,
|
||||
ev.AllModes);
|
||||
|
||||
_clyde._monitorHandles.Add(impl);
|
||||
_monitors[ev.Id] = new GlfwMonitorReg
|
||||
|
||||
@@ -210,7 +210,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
(
|
||||
int Id,
|
||||
string Name,
|
||||
VideoMode Mode
|
||||
VideoMode CurrentMode,
|
||||
VideoMode[] AllModes
|
||||
) : EventBase;
|
||||
|
||||
private record EventMonitorDestroy
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Robust.Client.Audio;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
@@ -8,6 +9,7 @@ namespace Robust.Client.Graphics
|
||||
// AUDIO SYSTEM DOWN BELOW.
|
||||
AudioStream LoadAudioOggVorbis(Stream stream, string? name = null);
|
||||
AudioStream LoadAudioWav(Stream stream, string? name = null);
|
||||
AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null);
|
||||
|
||||
void SetMasterVolume(float newVolume);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Robust.Client.Graphics
|
||||
void SetPitch(float pitch);
|
||||
void SetGlobal();
|
||||
void SetVolume(float decibels);
|
||||
void SetVolumeDirect(float decibels);
|
||||
void SetOcclusion(float blocks);
|
||||
void SetPlaybackPosition(float seconds);
|
||||
void SetVelocity(Vector2 velocity);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Shared.Maths;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
@@ -14,5 +15,7 @@ namespace Robust.Client.Graphics
|
||||
string Name { get; }
|
||||
Vector2i Size { get; }
|
||||
int RefreshRate { get; }
|
||||
|
||||
IEnumerable<VideoMode> VideoModes { get; }
|
||||
}
|
||||
}
|
||||
|
||||
12
Robust.Client/Graphics/VideoMode.cs
Normal file
12
Robust.Client/Graphics/VideoMode.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
public struct VideoMode
|
||||
{
|
||||
public ushort Width;
|
||||
public ushort Height;
|
||||
public ushort RefreshRate;
|
||||
public byte RedBits;
|
||||
public byte BlueBits;
|
||||
public byte GreenBits;
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,12 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using YamlDotNet.Core;
|
||||
@@ -145,13 +146,13 @@ namespace Robust.Client.Input
|
||||
.Where(p => _bindingsByFunction[p].Count == 0)
|
||||
.ToArray();
|
||||
|
||||
mapping.AddNode("version", new ValueDataNode("1"));
|
||||
mapping.AddNode("binds", serializationManager.WriteValue(modifiedBindings));
|
||||
mapping.AddNode("leaveEmpty", serializationManager.WriteValue(leaveEmpty));
|
||||
mapping.Add("version", new ValueDataNode("1"));
|
||||
mapping.Add("binds", serializationManager.WriteValue(modifiedBindings));
|
||||
mapping.Add("leaveEmpty", serializationManager.WriteValue(leaveEmpty));
|
||||
|
||||
var path = new ResourcePath(KeybindsPath);
|
||||
using var writer = new StreamWriter(_resourceMan.UserData.Create(path));
|
||||
var stream = new YamlStream {new(mapping.ToMappingNode())};
|
||||
var stream = new YamlStream {new(mapping.ToYaml())};
|
||||
stream.Save(new YamlMappingFix(new Emitter(writer)), false);
|
||||
}
|
||||
|
||||
@@ -333,6 +334,7 @@ namespace Robust.Client.Input
|
||||
{
|
||||
// christ this crap *is* re-entrant thanks to PlacementManager and
|
||||
// I honestly have no idea what the best solution here is.
|
||||
// note from the future: context switches won't cause re-entrancy anymore because InputContextContainer defers context switches
|
||||
DebugTools.Assert(!_currentlyFindingViewport, "Re-entrant key events??");
|
||||
|
||||
try
|
||||
@@ -340,6 +342,8 @@ namespace Robust.Client.Input
|
||||
// This is terrible but anyways.
|
||||
// This flag keeps track of "did a viewport fire the key up for us" so we know we don't do it again.
|
||||
_currentlyFindingViewport = true;
|
||||
// And this stops context switches from causing crashes
|
||||
Contexts.DeferringEnabled = true;
|
||||
|
||||
binding.State = state;
|
||||
|
||||
@@ -360,12 +364,14 @@ namespace Robust.Client.Input
|
||||
finally
|
||||
{
|
||||
_currentlyFindingViewport = false;
|
||||
Contexts.DeferringEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ViewportKeyEvent(Control? viewport, BoundKeyEventArgs eventArgs)
|
||||
{
|
||||
_currentlyFindingViewport = false;
|
||||
Contexts.DeferringEnabled = false;
|
||||
|
||||
var cmd = GetInputCommand(eventArgs.Function);
|
||||
// TODO: Allow input commands to still get forwarded to server if necessary.
|
||||
@@ -453,7 +459,7 @@ namespace Robust.Client.Input
|
||||
var robustMapping = mapping.ToDataNode() as MappingDataNode;
|
||||
if (robustMapping == null) throw new InvalidOperationException();
|
||||
|
||||
if (robustMapping.TryGetNode("binds", out var BaseKeyRegsNode))
|
||||
if (robustMapping.TryGet("binds", out var BaseKeyRegsNode))
|
||||
{
|
||||
var baseKeyRegs = serializationManager.ReadValueOrThrow<KeyBindingRegistration[]>(BaseKeyRegsNode);
|
||||
|
||||
@@ -482,7 +488,7 @@ namespace Robust.Client.Input
|
||||
}
|
||||
}
|
||||
|
||||
if (userData && robustMapping.TryGetNode("leaveEmpty", out var node))
|
||||
if (userData && robustMapping.TryGet("leaveEmpty", out var node))
|
||||
{
|
||||
var leaveEmpty = serializationManager.ReadValueOrThrow<BoundKeyFunction[]>(node);
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Robust.Client.Physics
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
UnsubscribeLocalEvent<IslandSolveMessage>();
|
||||
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(typeof(PhysicsIslandOverlay));
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace Robust.Client.Placement
|
||||
{
|
||||
_drawingShader = _prototypeManager.Index<ShaderPrototype>("unshaded").Instance();
|
||||
|
||||
NetworkManager.RegisterNetMessage<MsgPlacement>(MsgPlacement.NAME, HandlePlacementMessage);
|
||||
NetworkManager.RegisterNetMessage<MsgPlacement>(HandlePlacementMessage);
|
||||
|
||||
_modeDictionary.Clear();
|
||||
foreach (var type in ReflectionManager.GetAllChildren<PlacementMode>())
|
||||
|
||||
@@ -2,13 +2,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
{
|
||||
public interface IPlayerManager : Shared.Players.ISharedPlayerManager
|
||||
{
|
||||
new IEnumerable<IPlayerSession> Sessions { get; }
|
||||
IReadOnlyDictionary<NetUserId, IPlayerSession> SessionsDict { get; }
|
||||
new IEnumerable<ICommonSession> Sessions { get; }
|
||||
IReadOnlyDictionary<NetUserId, ICommonSession> SessionsDict { get; }
|
||||
|
||||
LocalPlayer? LocalPlayer { get; }
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Client side session of a player.
|
||||
/// </summary>
|
||||
[Obsolete("Use the base " + nameof(ICommonSession))]
|
||||
public interface IPlayerSession : ICommonSession { }
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
@@ -36,7 +37,7 @@ namespace Robust.Client.Player
|
||||
/// Session of the local client.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public IPlayerSession Session => InternalSession;
|
||||
public ICommonSession Session => InternalSession;
|
||||
|
||||
internal PlayerSession InternalSession { get; set; } = default!;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -28,7 +27,7 @@ namespace Robust.Client.Player
|
||||
/// <summary>
|
||||
/// Active sessions of connected clients to the server.
|
||||
/// </summary>
|
||||
private readonly Dictionary<NetUserId, IPlayerSession> _sessions = new();
|
||||
private readonly Dictionary<NetUserId, ICommonSession> _sessions = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ICommonSession> NetworkedSessions
|
||||
@@ -69,10 +68,10 @@ namespace Robust.Client.Player
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
IEnumerable<IPlayerSession> IPlayerManager.Sessions => _sessions.Values;
|
||||
IEnumerable<ICommonSession> IPlayerManager.Sessions => _sessions.Values;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<NetUserId, IPlayerSession> SessionsDict => _sessions;
|
||||
public IReadOnlyDictionary<NetUserId, ICommonSession> SessionsDict => _sessions;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler? PlayerListUpdated;
|
||||
@@ -82,8 +81,8 @@ namespace Robust.Client.Player
|
||||
{
|
||||
_client.RunLevelChanged += OnRunLevelChanged;
|
||||
|
||||
_network.RegisterNetMessage<MsgPlayerListReq>(MsgPlayerListReq.NAME);
|
||||
_network.RegisterNetMessage<MsgPlayerList>(MsgPlayerList.NAME, HandlePlayerList);
|
||||
_network.RegisterNetMessage<MsgPlayerListReq>();
|
||||
_network.RegisterNetMessage<MsgPlayerList>(HandlePlayerList);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -5,9 +5,8 @@ using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
{
|
||||
internal sealed class PlayerSession : IPlayerSession
|
||||
internal sealed class PlayerSession : ICommonSession
|
||||
{
|
||||
/// <inheritdoc />
|
||||
internal SessionStatus Status { get; set; } = SessionStatus.Connecting;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -26,17 +25,15 @@ namespace Robust.Client.Player
|
||||
/// <inheritdoc />
|
||||
public NetUserId UserId { get; }
|
||||
|
||||
/// <inheritdoc cref="IPlayerSession" />
|
||||
internal string Name { get; set; } = "<Unknown>";
|
||||
|
||||
/// <inheritdoc cref="IPlayerSession" />
|
||||
/// <inheritdoc />
|
||||
string ICommonSession.Name
|
||||
{
|
||||
get => this.Name;
|
||||
set => this.Name = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
internal short Ping { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -51,7 +48,7 @@ namespace Robust.Client.Player
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a PlayerSession.
|
||||
/// </summary
|
||||
/// </summary>
|
||||
public PlayerSession(NetUserId user)
|
||||
{
|
||||
UserId = user;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Robust.Client.Prototypes
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_netManager.RegisterNetMessage<MsgReloadPrototypes>(MsgReloadPrototypes.NAME, accept: NetMessageAccept.Server);
|
||||
_netManager.RegisterNetMessage<MsgReloadPrototypes>(accept: NetMessageAccept.Server);
|
||||
|
||||
_clyde.OnWindowFocused += WindowFocusedChanged;
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.Manager.Result;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Validation;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
|
||||
namespace Robust.Client.Serialization
|
||||
@@ -19,7 +21,7 @@ namespace Robust.Client.Serialization
|
||||
bool skipHook,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
if (!node.TryGetNode("type", out var typeNode))
|
||||
if (!node.TryGet("type", out var typeNode))
|
||||
throw new InvalidMappingException("No type specified for AppearanceVisualizer!");
|
||||
|
||||
if (typeNode is not ValueDataNode typeValueDataNode)
|
||||
@@ -32,7 +34,7 @@ namespace Robust.Client.Serialization
|
||||
$"Invalid type {typeValueDataNode.Value} specified for AppearanceVisualizer!");
|
||||
|
||||
var newNode = (MappingDataNode)node.Copy();
|
||||
newNode.RemoveNode("type");
|
||||
newNode.Remove("type");
|
||||
return serializationManager.Read(type, newNode, context, skipHook);
|
||||
}
|
||||
|
||||
@@ -40,7 +42,7 @@ namespace Robust.Client.Serialization
|
||||
IDependencyCollection dependencies,
|
||||
ISerializationContext? context)
|
||||
{
|
||||
if (!node.TryGetNode("type", out var typeNode) || typeNode is not ValueDataNode valueNode)
|
||||
if (!node.TryGet("type", out var typeNode) || typeNode is not ValueDataNode valueNode)
|
||||
{
|
||||
return new ErrorNode(node, "Missing/Invalid type", true);
|
||||
}
|
||||
@@ -53,14 +55,14 @@ namespace Robust.Client.Serialization
|
||||
return new ErrorNode(node, $"Failed to resolve type: {valueNode.Value}", true);
|
||||
}
|
||||
|
||||
return serializationManager.ValidateNode(type, node.CopyCast<MappingDataNode>().RemoveNode("type"));
|
||||
return serializationManager.ValidateNode(type, node.CopyCast<MappingDataNode>().Remove("type"));
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, AppearanceVisualizer value, bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
var mapping = serializationManager.WriteValueAs<MappingDataNode>(value.GetType(), value, alwaysWrite, context);
|
||||
mapping.AddNode("type", new ValueDataNode(value.GetType().Name));
|
||||
mapping.Add("type", new ValueDataNode(value.GetType().Name));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public bool HideRoot { get; set; }
|
||||
|
||||
public Item? Root => _root;
|
||||
public Item? TreeRoot => _root;
|
||||
|
||||
public Item? Selected => _selectedIndex == null ? null : _itemList[_selectedIndex.Value];
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
sawmill.Warning("Failed to load debug console history due to exception!\n{e}");
|
||||
sawmill.Warning($"Failed to load debug console history due to exception!\n{e}");
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
_label.Text = string.Join("\n", _inputManager.DownKeyFunctions);
|
||||
var functionsText = string.Join("\n", _inputManager.DownKeyFunctions);
|
||||
_label.Text = $"Context: {_inputManager.Contexts.ActiveContext.Name}\n{functionsText}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
var (spaceX, spaceY) = Parent!.Size;
|
||||
if (Position.Y > spaceY)
|
||||
{
|
||||
LayoutContainer.SetPosition(this, (Position.X, spaceY - HEADER_SIZE_Y));
|
||||
LayoutContainer.SetPosition(this, (Position.X, spaceY + HEADER_SIZE_Y));
|
||||
}
|
||||
|
||||
if (Position.X > spaceX)
|
||||
@@ -104,6 +104,16 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
// 50 is arbitrary here. As long as it's bumped back into view.
|
||||
LayoutContainer.SetPosition(this, (spaceX - 50, Position.Y));
|
||||
}
|
||||
|
||||
if (Position.Y < 0)
|
||||
{
|
||||
LayoutContainer.SetPosition(this, (Position.X, 0));
|
||||
}
|
||||
|
||||
if (Position.X < 0)
|
||||
{
|
||||
LayoutContainer.SetPosition(this, (0, Position.Y));
|
||||
}
|
||||
}
|
||||
|
||||
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace Robust.Client.UserInterface
|
||||
{
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IClydeInternal _clyde = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Robust.Client.ViewVariables
|
||||
var styleOther = false;
|
||||
var type = obj.GetType();
|
||||
|
||||
var members = new List<(MemberInfo, VVAccess, object? value, Action<object, bool> onValueChanged, Type)>();
|
||||
var members = new List<(MemberInfo, VVAccess, object? value, Action<object?, bool> onValueChanged, Type)>();
|
||||
|
||||
foreach (var fieldInfo in type.GetAllFields())
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using NumberType = Robust.Client.ViewVariables.Editors.VVPropEditorNumeric.NumberType;
|
||||
using static Robust.Client.ViewVariables.Editors.VVPropEditorNumeric;
|
||||
|
||||
namespace Robust.Client.ViewVariables
|
||||
{
|
||||
@@ -43,17 +43,13 @@ namespace Robust.Client.ViewVariables
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesOpenSession>(MsgViewVariablesOpenSession.NAME,
|
||||
_netMessageOpenSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesRemoteData>(MsgViewVariablesRemoteData.NAME,
|
||||
_netMessageRemoteData);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesCloseSession>(MsgViewVariablesCloseSession.NAME,
|
||||
_netMessageCloseSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesDenySession>(MsgViewVariablesDenySession.NAME,
|
||||
_netMessageDenySession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesModifyRemote>(MsgViewVariablesModifyRemote.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqSession>(MsgViewVariablesReqSession.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqData>(MsgViewVariablesReqData.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesOpenSession>(_netMessageOpenSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesRemoteData>(_netMessageRemoteData);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesCloseSession>(_netMessageCloseSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesDenySession>(_netMessageDenySession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesModifyRemote>();
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqSession>();
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqData>();
|
||||
}
|
||||
|
||||
public VVPropEditor PropertyFor(Type? type)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime;
|
||||
@@ -217,6 +217,26 @@ namespace Robust.Server
|
||||
_log.RootSawmill.AddHandler(_logHandler!);
|
||||
}
|
||||
|
||||
if (_commandLineArgs != null)
|
||||
{
|
||||
foreach (var (sawmill, level) in _commandLineArgs.LogLevels)
|
||||
{
|
||||
LogLevel? logLevel;
|
||||
if (level == "null")
|
||||
logLevel = null;
|
||||
else
|
||||
{
|
||||
if (!Enum.TryParse<LogLevel>(level, out var result))
|
||||
{
|
||||
System.Console.WriteLine($"LogLevel {level} does not exist!");
|
||||
continue;
|
||||
}
|
||||
logLevel = result;
|
||||
}
|
||||
_log.GetSawmill(sawmill).Level = logLevel;
|
||||
}
|
||||
}
|
||||
|
||||
SelfLog.Enable(s => { System.Console.WriteLine("SERILOG ERROR: {0}", s); });
|
||||
|
||||
if (!SetupLoki())
|
||||
@@ -306,7 +326,6 @@ namespace Robust.Server
|
||||
// Call Init in game assemblies.
|
||||
_modLoader.BroadcastRunLevel(ModRunLevel.Init);
|
||||
_entityManager.Initialize();
|
||||
IoCManager.Resolve<IEntityLookup>().Initialize();
|
||||
|
||||
IoCManager.Resolve<ISerializationManager>().Initialize();
|
||||
|
||||
@@ -319,6 +338,7 @@ namespace Robust.Server
|
||||
|
||||
IoCManager.Resolve<IServerConsoleHost>().Initialize();
|
||||
_entityManager.Startup();
|
||||
IoCManager.Resolve<IEntityLookup>().Startup();
|
||||
_stateManager.Initialize();
|
||||
_scriptHost.Initialize();
|
||||
|
||||
@@ -330,6 +350,7 @@ namespace Robust.Server
|
||||
|
||||
_watchdogApi.Initialize();
|
||||
|
||||
AddFinalStringsToSerializer();
|
||||
_stringSerializer.LockStrings();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _config.GetCVar(CVars.SysWinTickPeriod) >= 0)
|
||||
@@ -342,6 +363,16 @@ namespace Robust.Server
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AddFinalStringsToSerializer()
|
||||
{
|
||||
var factory = IoCManager.Resolve<IComponentFactory>();
|
||||
foreach (var regType in factory.AllRegisteredTypes)
|
||||
{
|
||||
var reg = factory.GetRegistration(regType);
|
||||
_stringSerializer.AddString(reg.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SetupLoki()
|
||||
{
|
||||
var enabled = _config.GetCVar(CVars.LokiEnabled);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -12,6 +12,7 @@ namespace Robust.Server
|
||||
public string? ConfigFile { get; }
|
||||
public string? DataDir { get; }
|
||||
public IReadOnlyCollection<(string key, string value)> CVars { get; }
|
||||
public IReadOnlyCollection<(string key, string value)> LogLevels { get; }
|
||||
|
||||
// Manual parser because C# has no good command line parsing libraries. Also dependencies bad.
|
||||
// Also I don't like spending 100ms parsing command line args. Do you?
|
||||
@@ -21,6 +22,7 @@ namespace Robust.Server
|
||||
string? configFile = null;
|
||||
string? dataDir = null;
|
||||
var cvars = new List<(string, string)>();
|
||||
var logLevels = new List<(string, string)>();
|
||||
var mountOptions = new MountOptions();
|
||||
|
||||
using var enumerator = args.GetEnumerator();
|
||||
@@ -93,13 +95,33 @@ namespace Robust.Server
|
||||
|
||||
mountOptions.DirMounts.Add(enumerator.Current);
|
||||
}
|
||||
else if (arg == "--loglevel")
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
C.WriteLine("Missing loglevel sawmill.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var loglevel = enumerator.Current;
|
||||
DebugTools.AssertNotNull(loglevel);
|
||||
var pos = loglevel.IndexOf('=');
|
||||
|
||||
if (pos == -1)
|
||||
{
|
||||
C.WriteLine("Expected = in loglevel.");
|
||||
return false;
|
||||
}
|
||||
|
||||
logLevels.Add((loglevel[..pos], loglevel[(pos + 1)..]));
|
||||
}
|
||||
else
|
||||
{
|
||||
C.WriteLine("Unknown argument: {0}", arg);
|
||||
}
|
||||
}
|
||||
|
||||
parsed = new CommandLineArgs(configFile, dataDir, cvars, mountOptions);
|
||||
parsed = new CommandLineArgs(configFile, dataDir, cvars, logLevels, mountOptions);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,17 +132,19 @@ Options:
|
||||
--config-file Path to the config file to read from.
|
||||
--data-dir Path to the data directory to read/write from/to.
|
||||
--cvar Specifies an additional cvar overriding the config file. Syntax is <key>=<value>
|
||||
--loglevel Specifies an additional sawmill log level overriding the default values. Syntax is <key>=<value>
|
||||
--mount-dir Resource directory to mount.
|
||||
--mount-zip Resource zip to mount.
|
||||
--help Display this help text and exit.
|
||||
");
|
||||
}
|
||||
|
||||
private CommandLineArgs(string? configFile, string? dataDir, IReadOnlyCollection<(string, string)> cVars, MountOptions mountOptions)
|
||||
private CommandLineArgs(string? configFile, string? dataDir, IReadOnlyCollection<(string, string)> cVars, IReadOnlyCollection<(string, string)> logLevels, MountOptions mountOptions)
|
||||
{
|
||||
ConfigFile = configFile;
|
||||
DataDir = dataDir;
|
||||
CVars = cVars;
|
||||
LogLevels = logLevels;
|
||||
MountOptions = mountOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,8 @@ namespace Robust.Server.Console.Commands
|
||||
else
|
||||
{
|
||||
var mapEnt = mapMgr.GetMapEntity(mapId);
|
||||
|
||||
transform.AttachParent(mapEnt);
|
||||
transform.WorldPosition = position;
|
||||
transform.AttachParent(mapEnt);
|
||||
}
|
||||
|
||||
shell.WriteLine($"Teleported {player} to {mapId}:{posX},{posY}.");
|
||||
|
||||
@@ -62,15 +62,14 @@ namespace Robust.Server.Console
|
||||
var sudoShell = new SudoShell(this, localShell, shell);
|
||||
ExecuteInShell(sudoShell, argStr.Substring("sudo ".Length));
|
||||
});
|
||||
|
||||
|
||||
LoadConsoleCommands();
|
||||
|
||||
// setup networking with clients
|
||||
NetManager.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME, ProcessCommand);
|
||||
NetManager.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME);
|
||||
NetManager.RegisterNetMessage<MsgConCmd>(ProcessCommand);
|
||||
NetManager.RegisterNetMessage<MsgConCmdAck>();
|
||||
|
||||
NetManager.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME,
|
||||
message => HandleRegistrationRequest(message.MsgChannel));
|
||||
NetManager.RegisterNetMessage<MsgConCmdReg>(message => HandleRegistrationRequest(message.MsgChannel));
|
||||
}
|
||||
|
||||
private void ExecuteInShell(IConsoleShell shell, string command)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
@@ -6,14 +7,14 @@ using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Server.Debugging
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal class DebugDrawingManager : IDebugDrawingManager
|
||||
{
|
||||
[Dependency] private readonly IServerNetManager _net = default!;
|
||||
[Dependency] private readonly IPhysicsManager _physics = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgRay>(MsgRay.NAME);
|
||||
_net.RegisterNetMessage<MsgRay>();
|
||||
// TODO _physics.DebugDrawRay += data => PhysicsOnDebugDrawRay(data);
|
||||
}
|
||||
|
||||
|
||||
45
Robust.Server/GameObjects/Components/Actor/ActorComponent.cs
Normal file
45
Robust.Server/GameObjects/Components/Actor/ActorComponent.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
public class ActorComponent : Component
|
||||
{
|
||||
public override string Name => "Actor";
|
||||
|
||||
[ViewVariables]
|
||||
public IPlayerSession PlayerSession { get; internal set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity whenever a player attaches to this entity.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public class PlayerAttachedMsg : ComponentMessage
|
||||
{
|
||||
public IPlayerSession NewPlayer { get; }
|
||||
|
||||
public PlayerAttachedMsg(IPlayerSession newPlayer)
|
||||
{
|
||||
NewPlayer = newPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity whenever a player detaches from this entity.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public class PlayerDetachedMsg : ComponentMessage
|
||||
{
|
||||
public IPlayerSession OldPlayer { get; }
|
||||
|
||||
public PlayerDetachedMsg(IPlayerSession oldPlayer)
|
||||
{
|
||||
OldPlayer = oldPlayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
public class BasicActorComponent : Component, IActorComponent
|
||||
{
|
||||
public override string Name => "BasicActor";
|
||||
|
||||
[ViewVariables] public IPlayerSession playerSession { get; internal set; } = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
// Warning: careful here, Detach removes this component, make sure this is after the base shutdown
|
||||
// to prevent infinite recursion
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
playerSession?.DetachFromEntity();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity whenever a player attaches to this entity.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlayerAttachedMsg : ComponentMessage
|
||||
{
|
||||
public IPlayerSession NewPlayer { get; }
|
||||
|
||||
public PlayerAttachedMsg(IPlayerSession newPlayer)
|
||||
{
|
||||
NewPlayer = newPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity whenever a player detaches from this entity.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PlayerDetachedMsg : ComponentMessage
|
||||
{
|
||||
public IPlayerSession OldPlayer { get; }
|
||||
|
||||
public PlayerDetachedMsg(IPlayerSession oldPlayer)
|
||||
{
|
||||
OldPlayer = oldPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerAttachSystemMessage : EntityEventArgs
|
||||
{
|
||||
public PlayerAttachSystemMessage(IEntity entity, IPlayerSession newPlayer)
|
||||
{
|
||||
Entity = entity;
|
||||
NewPlayer = newPlayer;
|
||||
}
|
||||
|
||||
public IEntity Entity { get; }
|
||||
public IPlayerSession NewPlayer { get; }
|
||||
}
|
||||
|
||||
public class PlayerDetachedSystemMessage : EntityEventArgs
|
||||
{
|
||||
public PlayerDetachedSystemMessage(IEntity entity)
|
||||
{
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
public IEntity Entity { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
public interface IActorComponent : IComponent
|
||||
{
|
||||
IPlayerSession playerSession { get; }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedAppearanceComponent))]
|
||||
public sealed class AppearanceComponent : SharedAppearanceComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedEyeComponent))]
|
||||
public class EyeComponent : SharedEyeComponent
|
||||
{
|
||||
[DataField("drawFov")]
|
||||
|
||||
@@ -14,6 +14,8 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(SharedSpriteComponent))]
|
||||
[ComponentReference(typeof(ISpriteRenderableComponent))]
|
||||
public class SpriteComponent : SharedSpriteComponent, ISpriteRenderableComponent, ISerializationHooks
|
||||
{
|
||||
const string LayerSerializationCache = "spritelayersrv";
|
||||
|
||||
@@ -7,8 +7,6 @@ using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
@@ -20,6 +18,7 @@ namespace Robust.Server.GameObjects
|
||||
/// </summary>
|
||||
/// <seealso cref="BoundUserInterface"/>
|
||||
[PublicAPI]
|
||||
[ComponentReference(typeof(SharedUserInterfaceComponent))]
|
||||
public sealed class ServerUserInterfaceComponent : SharedUserInterfaceComponent, ISerializationHooks
|
||||
{
|
||||
private readonly Dictionary<object, BoundUserInterface> _interfaces =
|
||||
@@ -48,7 +47,8 @@ namespace Robust.Server.GameObjects
|
||||
return _interfaces[uiKey];
|
||||
}
|
||||
|
||||
public bool TryGetBoundUserInterface(object uiKey, [NotNullWhen(true)] out BoundUserInterface? boundUserInterface)
|
||||
public bool TryGetBoundUserInterface(object uiKey,
|
||||
[NotNullWhen(true)] out BoundUserInterface? boundUserInterface)
|
||||
{
|
||||
return _interfaces.TryGetValue(uiKey, out boundUserInterface);
|
||||
}
|
||||
@@ -67,32 +67,20 @@ namespace Robust.Server.GameObjects
|
||||
|
||||
internal void SendToSession(IPlayerSession session, BoundUserInterfaceMessage message, object uiKey)
|
||||
{
|
||||
SendNetworkMessage(new BoundInterfaceMessageWrapMessage(message, uiKey), session.ConnectedClient);
|
||||
EntitySystem.Get<UserInterfaceSystem>()
|
||||
.SendTo(session, new BoundUIWrapMessage(Owner.Uid, message, uiKey));
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel,
|
||||
ICommonSession? session = null)
|
||||
internal void ReceiveMessage(IPlayerSession session, BoundUIWrapMessage msg)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
|
||||
switch (message)
|
||||
if (!_interfaces.TryGetValue(msg.UiKey, out var @interface))
|
||||
{
|
||||
case BoundInterfaceMessageWrapMessage wrapped:
|
||||
if (session == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(session));
|
||||
}
|
||||
|
||||
if (!_interfaces.TryGetValue(wrapped.UiKey, out var @interface))
|
||||
{
|
||||
Logger.DebugS("go.comp.ui", "Got BoundInterfaceMessageWrapMessage for unknown UI key: {0}",
|
||||
wrapped.UiKey);
|
||||
return;
|
||||
}
|
||||
|
||||
@interface.ReceiveMessage(wrapped.Message, (IPlayerSession)session);
|
||||
break;
|
||||
Logger.DebugS("go.comp.ui", "Got BoundInterfaceMessageWrapMessage for unknown UI key: {0}",
|
||||
msg.UiKey);
|
||||
return;
|
||||
}
|
||||
|
||||
@interface.ReceiveMessage(msg.Message, session);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +141,7 @@ namespace Robust.Server.GameObjects
|
||||
{
|
||||
_playerStateOverrides[session] = state;
|
||||
}
|
||||
|
||||
_stateDirty = true;
|
||||
}
|
||||
|
||||
@@ -178,7 +167,6 @@ namespace Robust.Server.GameObjects
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Opens this interface for a specific client.
|
||||
/// </summary>
|
||||
|
||||
173
Robust.Server/GameObjects/EntitySystems/ActorSystem.cs
Normal file
173
Robust.Server/GameObjects/EntitySystems/ActorSystem.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// System that handles players being attached/detached from entities.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class ActorSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AttachPlayerEvent>(OnActorPlayerAttach);
|
||||
SubscribeLocalEvent<ActorComponent, DetachPlayerEvent>(OnActorPlayerDetach);
|
||||
SubscribeLocalEvent<ActorComponent, ComponentShutdown>(OnActorShutdown);
|
||||
}
|
||||
|
||||
private void OnActorPlayerAttach(AttachPlayerEvent args)
|
||||
{
|
||||
// Cannot attach to a deleted entity.
|
||||
if (args.Entity.Deleted)
|
||||
{
|
||||
args.Result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var uid = args.Entity.Uid;
|
||||
|
||||
// Check if there was a player attached to the entity already...
|
||||
if (ComponentManager.TryGetComponent(uid, out ActorComponent actor))
|
||||
{
|
||||
// If we're not forcing the attach, this fails.
|
||||
if (!args.Force)
|
||||
{
|
||||
args.Result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the event's force-kicked session before detaching it.
|
||||
args.ForceKicked = actor.PlayerSession;
|
||||
|
||||
// This detach cannot fail, as a player is attached to this entity.
|
||||
// It's important to note that detaching the player removes the component.
|
||||
RaiseLocalEvent(uid, new DetachPlayerEvent());
|
||||
}
|
||||
|
||||
// We add the actor component.
|
||||
actor = ComponentManager.AddComponent<ActorComponent>(args.Entity);
|
||||
actor.PlayerSession = args.Player;
|
||||
args.Player.SetAttachedEntity(args.Entity);
|
||||
args.Result = true;
|
||||
|
||||
// TODO: Remove component message.
|
||||
args.Entity.SendMessage(actor, new PlayerAttachedMsg(args.Player));
|
||||
|
||||
// The player is fully attached now, raise an event!
|
||||
RaiseLocalEvent(uid, new PlayerAttachedEvent(args.Entity, args.Player));
|
||||
}
|
||||
|
||||
private void OnActorPlayerDetach(EntityUid uid, ActorComponent component, DetachPlayerEvent args)
|
||||
{
|
||||
// Removing the component will call shutdown, and our subscription will handle the rest of the detach logic.
|
||||
ComponentManager.RemoveComponent<ActorComponent>(uid);
|
||||
args.Result = true;
|
||||
}
|
||||
|
||||
private void OnActorShutdown(EntityUid uid, ActorComponent component, ComponentShutdown args)
|
||||
{
|
||||
component.PlayerSession.SetAttachedEntity(null);
|
||||
|
||||
var entity = EntityManager.GetEntity(uid);
|
||||
|
||||
// TODO: Remove component message.
|
||||
entity.SendMessage(component, new PlayerDetachedMsg(component.PlayerSession));
|
||||
|
||||
// The player is fully detached now that the component has shut down.
|
||||
RaiseLocalEvent(uid, new PlayerDetachedEvent(entity, component.PlayerSession));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise this broadcast event to attach a player to an entity, optionally detaching the player attached to it.
|
||||
/// </summary>
|
||||
public class AttachPlayerEvent : EntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Player to attach to the entity.
|
||||
/// Input parameter.
|
||||
/// </summary>
|
||||
public IPlayerSession Player { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity to attach the player to.
|
||||
/// Input parameter.
|
||||
/// </summary>
|
||||
public IEntity Entity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to force-attach the player,
|
||||
/// detaching any players attached to it if any.
|
||||
/// Input parameter.
|
||||
/// </summary>
|
||||
public bool Force { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If the attach was forced and there was a player attached to the entity before, this will be it.
|
||||
/// Output parameter.
|
||||
/// </summary>
|
||||
public IPlayerSession? ForceKicked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the player was attached correctly.
|
||||
/// False if not forcing and the entity already had a player attached to it.
|
||||
/// Output parameter.
|
||||
/// </summary>
|
||||
public bool Result { get; set; } = false;
|
||||
|
||||
public AttachPlayerEvent(IEntity entity, IPlayerSession player, bool force = false)
|
||||
{
|
||||
Entity = entity;
|
||||
Player = player;
|
||||
Force = force;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raise this directed event to detach a player from an entity.
|
||||
/// </summary>
|
||||
public class DetachPlayerEvent : EntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the player was detached correctly.
|
||||
/// Fails if no player was attached to the entity.
|
||||
/// Output parameter.
|
||||
/// </summary>
|
||||
public bool Result { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event for when a player has been attached to an entity.
|
||||
/// </summary>
|
||||
public class PlayerAttachedEvent : EntityEventArgs
|
||||
{
|
||||
public IEntity Entity { get; }
|
||||
public IPlayerSession Player { get; }
|
||||
|
||||
public PlayerAttachedEvent(IEntity entity, IPlayerSession player)
|
||||
{
|
||||
Entity = entity;
|
||||
Player = player;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event for when a player has been detached from an entity.
|
||||
/// </summary>
|
||||
public class PlayerDetachedEvent : EntityEventArgs
|
||||
{
|
||||
public IEntity Entity { get; }
|
||||
public IPlayerSession Player { get; }
|
||||
|
||||
public PlayerDetachedEvent(IEntity entity, IPlayerSession player)
|
||||
{
|
||||
Entity = entity;
|
||||
Player = player;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,13 +80,9 @@ namespace Robust.Server.GameObjects
|
||||
Identifier = id
|
||||
};
|
||||
|
||||
var players = (playerFilter as IFilter).Recipients;
|
||||
foreach (var player in players)
|
||||
{
|
||||
RaiseNetworkEvent(msg, player.ConnectedClient);
|
||||
}
|
||||
RaiseNetworkEvent(msg, playerFilter);
|
||||
|
||||
return new AudioSourceServer(this, id, players);
|
||||
return new AudioSourceServer(this, id, playerFilter.Recipients.ToArray());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -105,21 +101,14 @@ namespace Robust.Server.GameObjects
|
||||
AudioParams = audioParams ?? AudioParams.Default,
|
||||
Identifier = id,
|
||||
};
|
||||
|
||||
IList<ICommonSession> players;
|
||||
var recipients = (playerFilter as IFilter).Recipients;
|
||||
|
||||
// We clone the filter here as to not modify the original instance.
|
||||
if (range > 0.0f)
|
||||
players = PasInRange(recipients, entity.Transform.MapPosition, range);
|
||||
else
|
||||
players = recipients;
|
||||
playerFilter = playerFilter.Clone().AddInRange(entity.Transform.MapPosition, range);
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
RaiseNetworkEvent(msg, player.ConnectedClient);
|
||||
}
|
||||
|
||||
return new AudioSourceServer(this, id, players);
|
||||
RaiseNetworkEvent(msg, playerFilter);
|
||||
|
||||
return new AudioSourceServer(this, id, playerFilter.Recipients.ToArray());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -136,29 +125,14 @@ namespace Robust.Server.GameObjects
|
||||
AudioParams = audioParams ?? AudioParams.Default,
|
||||
Identifier = id
|
||||
};
|
||||
|
||||
IList<ICommonSession> players;
|
||||
var recipients = (playerFilter as IFilter).Recipients;
|
||||
|
||||
// We clone the filter here as to not modify the original instance.
|
||||
if (range > 0.0f)
|
||||
players = PasInRange(recipients, coordinates.ToMap(EntityManager), range);
|
||||
else
|
||||
players = recipients;
|
||||
playerFilter = playerFilter.Clone().AddInRange(coordinates.ToMap(EntityManager), range);
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
RaiseNetworkEvent(msg, player.ConnectedClient);
|
||||
}
|
||||
|
||||
return new AudioSourceServer(this, id, players);
|
||||
}
|
||||
RaiseNetworkEvent(msg, playerFilter);
|
||||
|
||||
private static List<ICommonSession> PasInRange(IEnumerable<ICommonSession> players, MapCoordinates position, float range)
|
||||
{
|
||||
return players.Where(x =>
|
||||
x.AttachedEntity != null &&
|
||||
position.InRange(x.AttachedEntity.Transform.MapPosition, range))
|
||||
.ToList();
|
||||
return new AudioSourceServer(this, id, playerFilter.Recipients.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace Robust.Server.GameObjects
|
||||
/// <inheritdoc />
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Robust.Server.GameObjects
|
||||
[UsedImplicitly]
|
||||
public sealed class GridTileLookupSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEntityLookup _lookup = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private readonly Dictionary<GridId, Dictionary<Vector2i, GridTileLookupChunk>> _graph =
|
||||
@@ -198,16 +199,16 @@ namespace Robust.Server.GameObjects
|
||||
|
||||
private Box2 GetEntityBox(IEntity entity)
|
||||
{
|
||||
// Need to clip the aabb as anything with an edge intersecting another tile might be picked up, such as walls.
|
||||
if (entity.TryGetComponent(out IPhysBody? physics))
|
||||
return new Box2(physics.GetWorldAABB().BottomLeft + 0.01f, physics.GetWorldAABB().TopRight - 0.01f);
|
||||
|
||||
// Don't want to accidentally get neighboring tiles unless we're near an edge
|
||||
return Box2.CenteredAround(entity.Transform.Coordinates.ToMapPos(EntityManager), Vector2.One / 2);
|
||||
var aabb = _lookup.GetWorldAabbFromEntity(entity);
|
||||
return aabb.IsEmpty() ? aabb : aabb.Enlarged(-0.1f);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
#if DEBUG
|
||||
SubscribeNetworkEvent<RequestGridTileLookupMessage>(HandleRequest);
|
||||
#endif
|
||||
SubscribeLocalEvent<MoveEvent>(HandleEntityMove);
|
||||
SubscribeLocalEvent<EntityInitializedMessage>(HandleEntityInitialized);
|
||||
SubscribeLocalEvent<EntityDeletedMessage>(HandleEntityDeleted);
|
||||
@@ -219,14 +220,20 @@ namespace Robust.Server.GameObjects
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
UnsubscribeLocalEvent<MoveEvent>();
|
||||
UnsubscribeLocalEvent<EntityInitializedMessage>();
|
||||
UnsubscribeLocalEvent<EntityDeletedMessage>();
|
||||
|
||||
_mapManager.OnGridCreated -= HandleGridCreated;
|
||||
_mapManager.OnGridRemoved -= HandleGridRemoval;
|
||||
_mapManager.TileChanged -= HandleTileChanged;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private void HandleRequest(RequestGridTileLookupMessage message, EntitySessionEventArgs args)
|
||||
{
|
||||
var entities = GetEntitiesIntersecting(message.GridId, message.Indices).Select(e => e.Uid).ToList();
|
||||
RaiseNetworkEvent(new SendGridTileLookupMessage(message.GridId, message.Indices, entities), args.SenderSession.ConnectedClient);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void HandleEntityInitialized(EntityInitializedMessage message)
|
||||
{
|
||||
HandleEntityAdd(message.Entity);
|
||||
@@ -320,7 +327,12 @@ namespace Robust.Server.GameObjects
|
||||
/// <param name="moveEvent"></param>
|
||||
private void HandleEntityMove(MoveEvent moveEvent)
|
||||
{
|
||||
if (moveEvent.Sender.Deleted || moveEvent.NewPosition.GetGridId(EntityManager) == GridId.Invalid || !moveEvent.NewPosition.IsValid(EntityManager))
|
||||
// TODO: When Acruid does TileEntities we may actually be able to delete this system if tile lookups become fast enough
|
||||
var gridId = moveEvent.NewPosition.GetGridId(EntityManager);
|
||||
|
||||
if (moveEvent.Sender.Deleted ||
|
||||
gridId == GridId.Invalid ||
|
||||
!moveEvent.NewPosition.IsValid(EntityManager))
|
||||
{
|
||||
HandleEntityRemove(moveEvent.Sender);
|
||||
return;
|
||||
@@ -332,7 +344,7 @@ namespace Robust.Server.GameObjects
|
||||
}
|
||||
|
||||
// Memory leak protection
|
||||
var gridBounds = _mapManager.GetGrid(moveEvent.Sender.Transform.GridID).WorldBounds;
|
||||
var gridBounds = _mapManager.GetGrid(gridId).WorldBounds;
|
||||
if (!gridBounds.Contains(moveEvent.Sender.Transform.WorldPosition))
|
||||
{
|
||||
HandleEntityRemove(moveEvent.Sender);
|
||||
|
||||
@@ -22,6 +22,31 @@ namespace Robust.Server.GameObjects
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<BoundUIWrapMessage>(OnMessageReceived);
|
||||
SubscribeLocalEvent<ServerUserInterfaceComponent, ComponentShutdown>(OnUserInterfaceShutdown);
|
||||
}
|
||||
|
||||
private void OnUserInterfaceShutdown(EntityUid uid, ServerUserInterfaceComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var bui in component.Interfaces)
|
||||
{
|
||||
DeactivateInterface(bui);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SendTo(IPlayerSession session, BoundUIWrapMessage msg)
|
||||
{
|
||||
RaiseNetworkEvent(msg, session.ConnectedClient);
|
||||
}
|
||||
|
||||
private void OnMessageReceived(BoundUIWrapMessage msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent<ServerUserInterfaceComponent>(msg.Entity, out var uiComp))
|
||||
return;
|
||||
|
||||
uiComp.ReceiveMessage((IPlayerSession) args.SenderSession, msg);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,68 +1,37 @@
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
public class ServerComponentFactory : ComponentFactory
|
||||
{
|
||||
public ServerComponentFactory()
|
||||
{
|
||||
// Required for the engine to work
|
||||
Register<MetaDataComponent>();
|
||||
RegisterReference<MetaDataComponent, IMetaDataComponent>();
|
||||
|
||||
// Required for the engine to work
|
||||
Register<TransformComponent>();
|
||||
RegisterReference<TransformComponent, ITransformComponent>();
|
||||
|
||||
Register<MapComponent>();
|
||||
RegisterReference<MapComponent, IMapComponent>();
|
||||
|
||||
Register<MapGridComponent>();
|
||||
RegisterReference<MapGridComponent, IMapGridComponent>();
|
||||
|
||||
Register<EyeComponent>();
|
||||
RegisterReference<EyeComponent, SharedEyeComponent>();
|
||||
|
||||
Register<BasicActorComponent>();
|
||||
RegisterReference<BasicActorComponent, IActorComponent>();
|
||||
|
||||
Register<PhysicsComponent>();
|
||||
RegisterReference<PhysicsComponent, IPhysBody>();
|
||||
|
||||
Register<CollisionWakeComponent>();
|
||||
|
||||
Register<ContainerManagerComponent>();
|
||||
RegisterReference<ContainerManagerComponent, IContainerManager>();
|
||||
|
||||
Register<OccluderComponent>();
|
||||
|
||||
RegisterIgnore("Input");
|
||||
Register<SpriteComponent>();
|
||||
RegisterReference<SpriteComponent, SharedSpriteComponent>();
|
||||
RegisterReference<SpriteComponent, ISpriteRenderableComponent>();
|
||||
|
||||
Register<AppearanceComponent>();
|
||||
RegisterReference<AppearanceComponent, SharedAppearanceComponent>();
|
||||
|
||||
Register<SnapGridComponent>();
|
||||
|
||||
Register<ServerUserInterfaceComponent>();
|
||||
RegisterReference<ServerUserInterfaceComponent, SharedUserInterfaceComponent>();
|
||||
|
||||
Register<TimerComponent>();
|
||||
|
||||
RegisterIgnore("AnimationPlayer");
|
||||
|
||||
#if DEBUG
|
||||
Register<DebugExceptionOnAddComponent>();
|
||||
Register<DebugExceptionInitializeComponent>();
|
||||
Register<DebugExceptionStartupComponent>();
|
||||
#endif
|
||||
RegisterClass<MetaDataComponent>();
|
||||
RegisterClass<TransformComponent>();
|
||||
RegisterClass<MapComponent>();
|
||||
RegisterClass<MapGridComponent>();
|
||||
RegisterClass<EyeComponent>();
|
||||
RegisterClass<ActorComponent>();
|
||||
RegisterClass<PhysicsComponent>();
|
||||
RegisterClass<CollisionWakeComponent>();
|
||||
RegisterClass<ContainerManagerComponent>();
|
||||
RegisterClass<OccluderComponent>();
|
||||
RegisterClass<SpriteComponent>();
|
||||
RegisterClass<AppearanceComponent>();
|
||||
RegisterClass<SnapGridComponent>();
|
||||
RegisterClass<ServerUserInterfaceComponent>();
|
||||
RegisterClass<TimerComponent>();
|
||||
RegisterClass<MapSaveIdComponent>();
|
||||
|
||||
Register<MapSaveIdComponent>();
|
||||
#if DEBUG
|
||||
RegisterClass<DebugExceptionOnAddComponent>();
|
||||
RegisterClass<DebugExceptionInitializeComponent>();
|
||||
RegisterClass<DebugExceptionStartupComponent>();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -108,7 +107,7 @@ namespace Robust.Server.GameObjects
|
||||
/// <inheritdoc />
|
||||
public void SetupNetworking()
|
||||
{
|
||||
_networkManager.RegisterNetMessage<MsgEntity>(MsgEntity.NAME, HandleEntityNetworkMessage);
|
||||
_networkManager.RegisterNetMessage<MsgEntity>(HandleEntityNetworkMessage);
|
||||
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
|
||||
@@ -137,6 +136,7 @@ namespace Robust.Server.GameObjects
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public void SendComponentNetworkMessage(INetChannel? channel, IEntity entity, IComponent component,
|
||||
ComponentMessage message)
|
||||
{
|
||||
|
||||
@@ -132,11 +132,11 @@ namespace Robust.Server.GameStates
|
||||
if (session.Status != SessionStatus.InGame || session.AttachedEntityUid is null)
|
||||
return viewers;
|
||||
|
||||
var query = _compMan.EntityQuery<BasicActorComponent>();
|
||||
var query = _compMan.EntityQuery<ActorComponent>();
|
||||
|
||||
foreach (var actorComp in query)
|
||||
{
|
||||
if (actorComp.playerSession == session)
|
||||
if (actorComp.PlayerSession == session)
|
||||
viewers.Add(actorComp.Owner.Uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Players;
|
||||
@@ -63,8 +62,8 @@ namespace Robust.Server.GameStates
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_networkManager.RegisterNetMessage<MsgState>(MsgState.NAME);
|
||||
_networkManager.RegisterNetMessage<MsgStateAck>(MsgStateAck.NAME, HandleStateAck);
|
||||
_networkManager.RegisterNetMessage<MsgState>();
|
||||
_networkManager.RegisterNetMessage<MsgStateAck>(HandleStateAck);
|
||||
|
||||
_networkManager.Connected += HandleClientConnected;
|
||||
_networkManager.Disconnect += HandleClientDisconnect;
|
||||
@@ -211,7 +210,10 @@ namespace Robust.Server.GameStates
|
||||
_logger.Log(LogLevel.Error, e, string.Empty);
|
||||
}
|
||||
|
||||
return (new MsgState(session.ConnectedClient), null);
|
||||
var msg = _networkManager.CreateNetMessage<MsgState>();
|
||||
msg.MsgChannel = session.ConnectedClient;
|
||||
|
||||
return (msg, null);
|
||||
}
|
||||
|
||||
var mailBag = _playerManager.GetAllPlayers()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -9,10 +10,9 @@ using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Server.Map
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class ServerMapManager : MapManager, IServerMapManager
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
|
||||
private readonly List<(GameTick tick, GridId gridId)> _gridDeletionHistory = new();
|
||||
private readonly List<(GameTick tick, MapId mapId)> _mapDeletionHistory = new();
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Result;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Validation;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -767,7 +769,7 @@ namespace Robust.Server.Maps
|
||||
// Don't need to write it if nothing was written!
|
||||
if (compMapping.Children.Count != 0)
|
||||
{
|
||||
compMapping.AddNode("type", new ValueDataNode(component.Name));
|
||||
compMapping.Add("type", new ValueDataNode(component.Name));
|
||||
// Something actually got written!
|
||||
components.Add(compMapping.ToYamlNode());
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
@@ -34,7 +34,7 @@ namespace Robust.Server.Placement
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_networkManager.RegisterNetMessage<MsgPlacement>(MsgPlacement.NAME, HandleNetMessage);
|
||||
_networkManager.RegisterNetMessage<MsgPlacement>(HandleNetMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -212,7 +212,7 @@ namespace Robust.Server.Placement
|
||||
foreach (IEntity entity in IoCManager.Resolve<IEntityLookup>().GetEntitiesIntersecting(start.GetMapId(_entityManager),
|
||||
new Box2(start.Position, start.Position + rectSize)))
|
||||
{
|
||||
if (entity.Deleted || entity.HasComponent<IMapGridComponent>() || entity.HasComponent<IActorComponent>())
|
||||
if (entity.Deleted || entity.HasComponent<IMapGridComponent>() || entity.HasComponent<ActorComponent>())
|
||||
continue;
|
||||
entity.Delete();
|
||||
}
|
||||
@@ -223,10 +223,10 @@ namespace Robust.Server.Placement
|
||||
/// </summary>
|
||||
public void SendPlacementBegin(IEntity mob, int range, string objectType, string alignOption)
|
||||
{
|
||||
if (!mob.TryGetComponent<IActorComponent>(out var actor))
|
||||
if (!mob.TryGetComponent<ActorComponent>(out var actor))
|
||||
return;
|
||||
|
||||
var playerConnection = actor.playerSession.ConnectedClient;
|
||||
var playerConnection = actor.PlayerSession.ConnectedClient;
|
||||
if (playerConnection == null)
|
||||
return;
|
||||
|
||||
@@ -244,10 +244,10 @@ namespace Robust.Server.Placement
|
||||
/// </summary>
|
||||
public void SendPlacementBeginTile(IEntity mob, int range, string tileType, string alignOption)
|
||||
{
|
||||
if (!mob.TryGetComponent<IActorComponent>(out var actor))
|
||||
if (!mob.TryGetComponent<ActorComponent>(out var actor))
|
||||
return;
|
||||
|
||||
var playerConnection = actor.playerSession.ConnectedClient;
|
||||
var playerConnection = actor.PlayerSession.ConnectedClient;
|
||||
if (playerConnection == null)
|
||||
return;
|
||||
|
||||
@@ -265,10 +265,10 @@ namespace Robust.Server.Placement
|
||||
/// </summary>
|
||||
public void SendPlacementCancel(IEntity mob)
|
||||
{
|
||||
if (!mob.TryGetComponent<IActorComponent>(out var actor))
|
||||
if (!mob.TryGetComponent<ActorComponent>(out var actor))
|
||||
return;
|
||||
|
||||
var playerConnection = actor.playerSession.ConnectedClient;
|
||||
var playerConnection = actor.PlayerSession.ConnectedClient;
|
||||
if (playerConnection == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace Robust.Server.Player
|
||||
/// NOTE: The content pack almost certainly has an alternative for this.
|
||||
/// Do not call this directly for most content code.
|
||||
/// </summary>
|
||||
/// <param name="a">The entity to attach to.</param>
|
||||
void AttachToEntity(IEntity? a);
|
||||
/// <param name="entity">The entity to attach to.</param>
|
||||
void AttachToEntity(IEntity? entity);
|
||||
|
||||
/// <summary>
|
||||
/// Detaches this player from an entity.
|
||||
@@ -36,5 +36,12 @@ namespace Robust.Server.Player
|
||||
/// Persistent data for this player.
|
||||
/// </summary>
|
||||
IPlayerData Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal method to set <see cref="ICommonSession.AttachedEntity"/> and update the player's status.
|
||||
/// Do NOT use this unless you know what you're doing, you probably want <see cref="AttachToEntity"/>
|
||||
/// and <see cref="DetachFromEntity"/> instead.
|
||||
/// </summary>
|
||||
internal void SetAttachedEntity(IEntity? entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace Robust.Server.Player
|
||||
if (entity == null)
|
||||
return null;
|
||||
|
||||
if (!entity.TryGetComponent(out IActorComponent? actorComponent))
|
||||
if (!entity.TryGetComponent(out ActorComponent? actorComponent))
|
||||
return null;
|
||||
|
||||
return actorComponent.playerSession;
|
||||
return actorComponent.PlayerSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,24 @@ namespace Robust.Server.Player
|
||||
private readonly Dictionary<string, NetUserId> _userIdMap = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ICommonSession> NetworkedSessions => _sessions.Values;
|
||||
public IEnumerable<ICommonSession> NetworkedSessions => Sessions;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ICommonSession> Sessions => _sessions.Values;
|
||||
public IEnumerable<ICommonSession> Sessions
|
||||
{
|
||||
get
|
||||
{
|
||||
_sessionsLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
return _sessions.Values;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sessionsLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
@@ -93,8 +107,8 @@ namespace Robust.Server.Player
|
||||
|
||||
MaxPlayers = maxPlayers;
|
||||
|
||||
_network.RegisterNetMessage<MsgPlayerListReq>(MsgPlayerListReq.NAME, HandlePlayerListReq);
|
||||
_network.RegisterNetMessage<MsgPlayerList>(MsgPlayerList.NAME);
|
||||
_network.RegisterNetMessage<MsgPlayerListReq>(HandlePlayerListReq);
|
||||
_network.RegisterNetMessage<MsgPlayerList>();
|
||||
|
||||
_network.Connecting += OnConnecting;
|
||||
_network.Connected += NewSession;
|
||||
@@ -109,11 +123,20 @@ namespace Robust.Server.Player
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_sessions.TryGetValue(userId, out var iSession))
|
||||
_sessionsLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
session = iSession;
|
||||
return true;
|
||||
if (_sessions.TryGetValue(userId, out var iSession))
|
||||
{
|
||||
session = iSession;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sessionsLock.ExitReadLock();
|
||||
}
|
||||
|
||||
|
||||
session = null;
|
||||
return false;
|
||||
@@ -210,7 +233,9 @@ namespace Robust.Server.Player
|
||||
try
|
||||
{
|
||||
foreach (var s in _sessions.Values)
|
||||
{
|
||||
s.JoinGame();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -237,7 +262,9 @@ namespace Robust.Server.Player
|
||||
try
|
||||
{
|
||||
foreach (var s in _sessions.Values)
|
||||
{
|
||||
s.DetachFromEntity();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -286,9 +313,7 @@ namespace Robust.Server.Player
|
||||
try
|
||||
{
|
||||
return
|
||||
_sessions.Values.Where(predicate)
|
||||
.Cast<IPlayerSession>()
|
||||
.ToList();
|
||||
_sessions.Values.Where(predicate).ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Logger = Robust.Shared.Log.Logger;
|
||||
|
||||
namespace Robust.Server.Player
|
||||
{
|
||||
@@ -36,7 +37,7 @@ namespace Robust.Server.Player
|
||||
|
||||
[ViewVariables] public INetChannel ConnectedClient { get; }
|
||||
|
||||
[ViewVariables] public IEntity? AttachedEntity { get; private set; }
|
||||
[ViewVariables] public IEntity? AttachedEntity { get; set; }
|
||||
|
||||
[ViewVariables] public EntityUid? AttachedEntityUid => AttachedEntity?.Uid;
|
||||
|
||||
@@ -109,21 +110,21 @@ namespace Robust.Server.Player
|
||||
public event EventHandler<SessionStatusEventArgs>? PlayerStatusChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AttachToEntity(IEntity? a)
|
||||
public void AttachToEntity(IEntity? entity)
|
||||
{
|
||||
DetachFromEntity();
|
||||
|
||||
if (a == null)
|
||||
{
|
||||
if (entity == null)
|
||||
return;
|
||||
}
|
||||
|
||||
var actorComponent = a.AddComponent<BasicActorComponent>();
|
||||
actorComponent.playerSession = this;
|
||||
AttachedEntity = a;
|
||||
a.SendMessage(actorComponent, new PlayerAttachedMsg(this));
|
||||
a.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PlayerAttachSystemMessage(a, this));
|
||||
UpdatePlayerState();
|
||||
// This event needs to be broadcast.
|
||||
var attachPlayer = new AttachPlayerEvent(entity, this);
|
||||
entity.EntityManager.EventBus.RaiseLocalEvent(entity.Uid, attachPlayer);
|
||||
|
||||
if (!attachPlayer.Result)
|
||||
{
|
||||
Logger.Warning($"Couldn't attach player \"{this}\" to entity \"{entity}\"! Did it have a player already attached to it?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -132,22 +133,12 @@ namespace Robust.Server.Player
|
||||
if (AttachedEntity == null)
|
||||
return;
|
||||
|
||||
if (AttachedEntity.Deleted)
|
||||
{
|
||||
throw new InvalidOperationException("Tried to detach player, but my entity does not exist!");
|
||||
}
|
||||
var detachPlayer = new DetachPlayerEvent();
|
||||
AttachedEntity.EntityManager.EventBus.RaiseLocalEvent(AttachedEntity.Uid, detachPlayer, false);
|
||||
|
||||
if (AttachedEntity.TryGetComponent<BasicActorComponent>(out var actor))
|
||||
if (!detachPlayer.Result)
|
||||
{
|
||||
AttachedEntity.SendMessage(actor, new PlayerDetachedMsg(this));
|
||||
AttachedEntity.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PlayerDetachedSystemMessage(AttachedEntity));
|
||||
AttachedEntity.RemoveComponent<BasicActorComponent>();
|
||||
AttachedEntity = null;
|
||||
UpdatePlayerState();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Tried to detach player, but entity does not have ActorComponent!");
|
||||
Logger.Warning($"Couldn't detach player \"{this}\" to entity \"{AttachedEntity}\"! Is it missing an ActorComponent?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +181,13 @@ namespace Robust.Server.Player
|
||||
|
||||
public LoginType AuthType => ConnectedClient.AuthType;
|
||||
|
||||
/// <inheritdoc />
|
||||
void IPlayerSession.SetAttachedEntity(IEntity? entity)
|
||||
{
|
||||
AttachedEntity = entity;
|
||||
UpdatePlayerState();
|
||||
}
|
||||
|
||||
private void UpdatePlayerState()
|
||||
{
|
||||
PlayerState.Status = Status;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Robust.Server.Prototypes
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_netManager.RegisterNetMessage<MsgReloadPrototypes>(MsgReloadPrototypes.NAME, HandleReloadPrototypes, NetMessageAccept.Server);
|
||||
_netManager.RegisterNetMessage<MsgReloadPrototypes>(HandleReloadPrototypes, NetMessageAccept.Server);
|
||||
}
|
||||
|
||||
private void HandleReloadPrototypes(MsgReloadPrototypes msg)
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace Robust.Server.Scripting
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgScriptStop>(MsgScriptStop.NAME, ReceiveScriptEnd);
|
||||
_netManager.RegisterNetMessage<MsgScriptEval>(MsgScriptEval.NAME, ReceiveScriptEval);
|
||||
_netManager.RegisterNetMessage<MsgScriptStart>(MsgScriptStart.NAME, ReceiveScriptStart);
|
||||
_netManager.RegisterNetMessage<MsgScriptResponse>(MsgScriptResponse.NAME);
|
||||
_netManager.RegisterNetMessage<MsgScriptStartAck>(MsgScriptStartAck.NAME);
|
||||
_netManager.RegisterNetMessage<MsgScriptStop>(ReceiveScriptEnd);
|
||||
_netManager.RegisterNetMessage<MsgScriptEval>(ReceiveScriptEval);
|
||||
_netManager.RegisterNetMessage<MsgScriptStart>(ReceiveScriptStart);
|
||||
_netManager.RegisterNetMessage<MsgScriptResponse>();
|
||||
_netManager.RegisterNetMessage<MsgScriptStartAck>();
|
||||
|
||||
_playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Robust.Server
|
||||
IoCManager.Register<IMapManagerInternal, ServerMapManager>();
|
||||
IoCManager.Register<IServerMapManager, ServerMapManager>();
|
||||
IoCManager.Register<IEntityManager, ServerEntityManager>();
|
||||
IoCManager.Register<IEntityLookup, SharedEntityLookup>();
|
||||
IoCManager.Register<IEntityLookup, EntityLookup>();
|
||||
IoCManager.Register<IEntityNetworkManager, ServerEntityManager>();
|
||||
IoCManager.Register<IServerEntityNetworkManager, ServerEntityManager>();
|
||||
IoCManager.Register<IMapLoader, MapLoader>();
|
||||
|
||||
@@ -13,7 +13,7 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using DenyReason = Robust.Shared.Network.Messages.MsgViewVariablesDenySession.DenyReason;
|
||||
using static Robust.Shared.Network.Messages.MsgViewVariablesDenySession;
|
||||
|
||||
namespace Robust.Server.ViewVariables
|
||||
{
|
||||
@@ -34,16 +34,13 @@ namespace Robust.Server.ViewVariables
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqSession>(MsgViewVariablesReqSession.NAME,
|
||||
_msgReqSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqData>(MsgViewVariablesReqData.NAME, _msgReqData);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesModifyRemote>(MsgViewVariablesModifyRemote.NAME,
|
||||
_msgModifyRemote);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesCloseSession>(MsgViewVariablesCloseSession.NAME,
|
||||
_msgCloseSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesDenySession>(MsgViewVariablesDenySession.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesOpenSession>(MsgViewVariablesOpenSession.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesRemoteData>(MsgViewVariablesRemoteData.NAME);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqSession>(_msgReqSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesReqData>(_msgReqData);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesModifyRemote>(_msgModifyRemote);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesCloseSession>(_msgCloseSession);
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesDenySession>();
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesOpenSession>();
|
||||
_netManager.RegisterNetMessage<MsgViewVariablesRemoteData>();
|
||||
}
|
||||
|
||||
private void _msgCloseSession(MsgViewVariablesCloseSession message)
|
||||
|
||||
@@ -415,14 +415,26 @@ namespace Robust.Shared
|
||||
CVarDef.Create("physics.maxangularcorrection", 8.0f / 180.0f * MathF.PI);
|
||||
|
||||
// - Maximums
|
||||
// Squared
|
||||
// 35 m/s, AKA half a tile per frame allowed. Divide this by frametime to get units per second.
|
||||
/// <summary>
|
||||
/// Maximum linear velocity per second.
|
||||
/// Make sure that MaxLinVelocity / <see cref="NetTickrate"/> is around 0.5 or higher so that moving objects don't go through walls.
|
||||
/// MaxLinVelocity is compared to the dot product of linearVelocity * frameTime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default is 35 m/s. Around half a tile per tick at 60 ticks per second.
|
||||
/// </remarks>
|
||||
public static readonly CVarDef<float> MaxLinVelocity =
|
||||
CVarDef.Create("physics.maxlinvelocity", 0.56f);
|
||||
CVarDef.Create("physics.maxlinvelocity", 35f);
|
||||
|
||||
// Squared
|
||||
/// <summary>
|
||||
/// Maximum angular velocity in full rotations per second.
|
||||
/// MaxAngVelocity is compared to the squared rotation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default is 15 rotations per second. Approximately a quarter rotation per tick at 60 ticks per second.
|
||||
/// </remarks>
|
||||
public static readonly CVarDef<float> MaxAngVelocity =
|
||||
CVarDef.Create("physics.maxangvelocity", 0.5f * MathF.PI);
|
||||
CVarDef.Create("physics.maxangvelocity", 15f);
|
||||
|
||||
/*
|
||||
* DISCORD
|
||||
@@ -451,5 +463,12 @@ namespace Robust.Shared
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> DebugTargetFps =
|
||||
CVarDef.Create("debug.target_fps", 60, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
* MIDI
|
||||
*/
|
||||
|
||||
public static readonly CVarDef<float> MidiVolume =
|
||||
CVarDef.Create("midi.volume", 0f, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Robust.Shared.Configuration
|
||||
_netManager.Disconnect += PeerDisconnected;
|
||||
}
|
||||
|
||||
_netManager.RegisterNetMessage<MsgConVars>(MsgConVars.NAME, HandleNetVarMessage);
|
||||
_netManager.RegisterNetMessage<MsgConVars>(HandleNetVarMessage);
|
||||
}
|
||||
|
||||
private void PeerConnected(object? sender, NetChannelArgs e)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Shared.Containers
|
||||
@@ -5,6 +6,7 @@ namespace Robust.Shared.Containers
|
||||
/// <summary>
|
||||
/// The contents of this container have been changed.
|
||||
/// </summary>
|
||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
||||
public class ContainerContentsModifiedMessage : ComponentMessage
|
||||
{
|
||||
/// <summary>
|
||||
@@ -35,4 +37,4 @@ namespace Robust.Shared.Containers
|
||||
Removed = removed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,27 @@ namespace Robust.Shared.Containers
|
||||
return userContainer == otherContainer;
|
||||
}
|
||||
|
||||
public static bool IsInSameOrParentContainer(this IEntity user, IEntity other)
|
||||
{
|
||||
DebugTools.AssertNotNull(user);
|
||||
DebugTools.AssertNotNull(other);
|
||||
|
||||
var isUserContained = TryGetContainer(user, out var userContainer);
|
||||
var isOtherContained = TryGetContainer(other, out var otherContainer);
|
||||
|
||||
// Both entities are not in a container
|
||||
if (!isUserContained && !isOtherContained) return true;
|
||||
|
||||
// One contains the other
|
||||
if (userContainer?.Owner == other || otherContainer?.Owner == user) return true;
|
||||
|
||||
// Both entities are in different contained states
|
||||
if (isUserContained != isOtherContained) return false;
|
||||
|
||||
// Both entities are in the same container
|
||||
return userContainer == otherContainer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut method to make creation of containers easier.
|
||||
/// Creates a new container on the entity and gives it back to you.
|
||||
|
||||
@@ -16,8 +16,7 @@ namespace Robust.Shared.Containers
|
||||
/// <summary>
|
||||
/// Holds data about a set of entity containers on this entity.
|
||||
/// </summary>
|
||||
// [RegisterComponent]
|
||||
// [ComponentReference(typeof(IContainerManager))]
|
||||
[ComponentReference(typeof(IContainerManager))]
|
||||
public class ContainerManagerComponent : Component, IContainerManager
|
||||
{
|
||||
[Dependency] private readonly IRobustSerializer _serializer = default!;
|
||||
|
||||
@@ -106,6 +106,12 @@ namespace Robust.Shared.ContentPack
|
||||
|
||||
var asmName = reader.GetString(reader.GetAssemblyDefinition().Name);
|
||||
|
||||
if (peReader.PEHeaders.CorHeader?.ManagedNativeHeaderDirectory is {Size: not 0})
|
||||
{
|
||||
_sawmill.Error($"Assembly {asmName} contains native code.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (VerifyIL)
|
||||
{
|
||||
if (!DoVerifyIL(asmName, resolver, peReader, reader))
|
||||
@@ -404,7 +410,8 @@ namespace Robust.Shared.ContentPack
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsTypeAccessAllowed(SandboxConfig sandboxConfig, MTypeReferenced type, [NotNullWhen(true)] out TypeConfig? cfg)
|
||||
private bool IsTypeAccessAllowed(SandboxConfig sandboxConfig, MTypeReferenced type,
|
||||
[NotNullWhen(true)] out TypeConfig? cfg)
|
||||
{
|
||||
if (type.Namespace == null)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user