Compare commits

..

55 Commits

Author SHA1 Message Date
metalgearsloth
60b506cb2a Fix GetWorldAABB again (#1802)
No weird-ass bug this time. There was also an issue where occasionally the AABB on the client would disappear if you had a bunch of objects and used showbb but I think it's fixed now.
2021-06-09 12:25:08 +10:00
metalgearsloth
66117e35ba Don't store lights in rendertree if not enabled (#1803) 2021-06-09 01:37:40 +02:00
metalgearsloth
22cfee4f01 Don't store non-visible / occluded sprites in rendertree (#1805)
Sister commit to the point-light one.
2021-06-09 01:33:24 +02:00
metalgearsloth
d9355e576f Remove PhysicsManager (#1812)
Goodnight sweet prince
2021-06-09 01:26:51 +02:00
Vera Aguilera Puerto
e54e33edb0 Client Networked event subscriptions can now take in EntitySessionEventArgs (#1817) 2021-06-09 01:22:20 +02:00
mirrorcult
25881ce343 MapInit ECS event (#1813)
* MapInit ECS event

* allocs
2021-06-08 22:33:21 +02:00
Acruid
f64197c189 Removes the map and grid entity pivot hack from clientside map networking. (#1811) 2021-06-08 02:45:02 -07:00
metalgearsloth
a7ec907f1d Remove mass from physics comp state (#1810)
Deprecated by fixtures storing mass
2021-06-07 13:56:21 +10:00
metalgearsloth
81272b0bc8 Reduce rendertree allocs (#1806) 2021-06-06 14:50:31 +02:00
metalgearsloth
25c1c6ef91 Fix rendertree updatequeued (#1804)
Woulda pushed directly but I cooked my git so ya know, nothing to see here
2021-06-06 19:25:27 +10:00
ShadowCommander
d1a83134e3 Fix SpriteView when UI is scaled 2021-06-05 19:47:26 -07:00
metalgearsloth
71c2993d20 Add joint support for CollisionWakeComponent (#1794)
* Add joint support for CollisionWakeComponent

* Less bad

* Fix heresy
2021-06-05 18:16:06 +10:00
Galactic Chimp
14fa616723 #1224 removed obsolete FloatMath class (#1800) 2021-06-03 00:11:19 +02:00
metalgearsloth
d46ea9c9ba Add gridtilelookup debugger back in (#1792)
Was reverted from the broadphase PR.
2021-06-01 11:58:44 +10:00
ShadowCommander
ea00ccb34f Fix window not calling OnMouseExited 2021-05-31 18:56:23 -07:00
Pieter-Jan Briers
8e416bb3cb Fix error in RenderingTreeSystem.
Seems related to #1754? Doesn't seem to fix it though.
2021-06-01 00:01:36 +02:00
Galactic Chimp
8e0a26073d #1765 - replaced 3 try-catch clauses with if-else clause + VS autoformat of affected files (#1796) 2021-05-31 22:49:23 +02:00
metalgearsloth
9fa24948ea Fix EntitySystemManagerOrderTest (#1793) 2021-05-31 13:20:09 +02:00
metalgearsloth
b9a9cc4b0f Revert "Immediate broadphase updates (#1687)" (#1790)
This reverts commit ee6aee57bd.
2021-05-31 20:33:29 +10:00
Pieter-Jan Briers
a67345f9bf Add debug log for runtime/OS info on game start. 2021-05-31 10:48:30 +02:00
Pieter-Jan Briers
2a022f39bd Add system for loading extra serializer strings.
"fixture-0" comes up a LOT so we load this manually now.
2021-05-31 10:48:30 +02:00
Vera Aguilera Puerto
a3ba969589 Container modified events are raised directed to the container owner. 2021-05-31 10:14:02 +02:00
metalgearsloth
21e1b75f5d Remove ICollideSpecial entirely (#1782)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-05-31 09:41:11 +02:00
metalgearsloth
1f6ddd96a6 Optimise the shit out of showpos (#1788) 2021-05-31 09:11:29 +02:00
metalgearsloth
b4d2cd26aa Named joints (#1787)
1 step closer to ECS physics.
2021-05-31 09:01:02 +02:00
metalgearsloth
ee6aee57bd Immediate broadphase updates (#1687) 2021-05-31 08:58:23 +02:00
DrSmugleaf
ac1705e41f Make NetMessage name and group virtual to remove required boilerplate (#1770) 2021-05-31 08:53:46 +02:00
metalgearsloth
196a6047f1 Use Box2D FindMaxSeparation (#1786) 2021-05-31 08:52:01 +02:00
ShadowCommander
b98b36a461 Add loglevel command line arg (#1769) 2021-05-31 08:41:34 +02:00
mirrorcult
9980a98a94 Add new fluent functions for words that change based on gender (#1775) 2021-05-31 08:41:06 +02:00
Pieter-Jan Briers
5a1a1d0420 Add component names to string serializer. 2021-05-30 22:55:33 +02:00
ShadowCommander
1c99678fe9 Change other physics awake event calls to RaiseLocalEvent 2021-05-30 12:16:17 -07:00
ShadowCommander
4049f10faa Make awake dispatch local events (#1785) 2021-05-30 21:05:16 +02:00
metalgearsloth
331c0bd43f Fix PreventCollideEvent (#1781)
With directed bus it's better to raise it both ways for a collision.
2021-05-30 18:38:28 +02:00
metalgearsloth
604cd2f93d Fix physics nullrefs (#1780)
* Fix physics nullrefs

* woops
2021-05-30 05:15:22 -07:00
Vera Aguilera Puerto
a87db2e57c EntitySystemManager uses IRuntimeLog for exception logging. 2021-05-30 12:27:36 +02:00
ShadowCommander
4c7f0a8d6b Add container helper for entity storage interaction (#1777) 2021-05-29 11:40:36 +02:00
20kdc
9eaf52886a Make RenderingTreeSystem handle parent recursion properly, fixing space-station-14#4040 and possibly other bugs (#1776) 2021-05-29 11:39:35 +02:00
Vera Aguilera Puerto
fce6f6c714 Adds ActorSystem to handle Attaching/Detaching players to/from entities sanely. (#1774) 2021-05-29 11:37:34 +02:00
DrSmugleaf
c04d51d489 Add test for YAML hot reloading (#1773)
* Add test for YAML hot reloading

* Perhaps test the event firing as well
2021-05-27 15:50:44 +02:00
Vera Aguilera Puerto
d310871aa6 CVar for MIDI volume. 2021-05-26 19:27:02 +02:00
Vera Aguilera Puerto
5fa422865f AudioSystem warning now prints audio stream name, if any. 2021-05-26 18:56:30 +02:00
Vera Aguilera Puerto
c137823355 Proper cleanup when detaching player from a deleted entity. 2021-05-26 18:44:37 +02:00
Vera Aguilera Puerto
0a0026b9ae Add formatted message newline helper method. 2021-05-26 10:18:27 +02:00
Pieter-Jan Briers
97a2a5cfae Block loading of R2R'd .NET assemblies in sandboxing. 2021-05-25 16:57:54 +02:00
Pieter-Jan Briers
a266e21d9e Add single-type IoC register call. 2021-05-24 22:05:15 +02:00
Pieter-Jan Briers
ad8bbe6401 Clyde audio improvements:
1. Allow loading audio directly from a sample buffer
2. SetVolumeDirect that takes a 0 -> 1 scale similar to OpenAL's AL_GAIN.
3. Fix OpenAL threading bugs with logging by caching the sawmill.
2021-05-23 22:58:32 +02:00
Pieter-Jan Briers
71ce4749fe Show active input context on DebugInputPanel. 2021-05-23 22:58:32 +02:00
Pieter-Jan Briers
1e33c3c843 MIDI renderer debugging code. 2021-05-23 22:58:32 +02:00
Vera Aguilera Puerto
b3f3ca9725 MIDI renderer uses NumericsHelpers to convert stereo audio to mono. 2021-05-23 13:40:06 +02:00
Vera Aguilera Puerto
33c37393ba Fixes incorrect comment in MidiRenderer.
Pain.
2021-05-23 13:15:31 +02:00
metalgearsloth
ae36529744 Emit line for mapping node exceptions (#1764)
Makes it a billion times more useful when I dun screwed up
2021-05-22 11:36:28 +02:00
20kdc
ed2be48864 Fix Coordinates setter destroying local position during a parent change by migrating parent changes to it (#1763)
This fixes computer boards going missing. (Seriously.)
2021-05-22 11:36:18 +02:00
Vera Aguilera Puerto
7ad5ce302e Directed event improvements (#1761)
* IComponentManager holds a reference to IComponentFactory.

* Directed events for a same <TComp, TEvent> can be duplicated, component references of a component are added to the entity's event tables.

* Fix tests.

* Improvements, duplicated subscriptions are no more

* Cache component factory for faster access

* when the
2021-05-21 17:38:52 -07:00
Vera Aguilera Puerto
647f1a6808 Fixes bug where deleting things causes their sprite to appear and pile on 0,0.
- Cleans up an unneeded event.
2021-05-20 21:17:20 +02:00
135 changed files with 2106 additions and 1547 deletions

View File

@@ -6,6 +6,8 @@ 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;
@@ -61,6 +63,7 @@ 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!;
@@ -94,7 +97,7 @@ namespace Robust.Client.Audio.Midi
if (MathHelper.CloseTo(_volume, value))
return;
_volume = value;
_cfgMan.SetCVar(CVars.MidiVolume, value);
_volumeDirty = true;
}
}
@@ -131,6 +134,12 @@ namespace Robust.Client.Audio.Midi
{
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;

View File

@@ -7,6 +7,7 @@ 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;
@@ -203,7 +204,9 @@ 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;
@@ -313,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);
@@ -322,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)
@@ -428,9 +453,6 @@ namespace Robust.Client.Audio.Midi
{
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;
@@ -445,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++)
@@ -532,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);
@@ -576,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:
@@ -597,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);
}

View File

@@ -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;

View File

@@ -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));

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -93,7 +93,7 @@ namespace Robust.Client
// Disable load context usage on content start.
// This prevents Content.Client being loaded twice and things like csi blowing up because of it.
_modLoader.SetUseLoadContext(!ContentStart);
_modLoader.SetEnableSandboxing(false && Options.Sandboxing);
_modLoader.SetEnableSandboxing(Options.Sandboxing);
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), Options.ContentModulePrefix))
{
@@ -202,6 +202,28 @@ 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;
}
}
ProgramShared.PrintRuntimeInfo(_logManager.RootSawmill);
// Figure out user data directory.
var userDataDir = GetUserDataDir();

View File

@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Prometheus;
using Robust.Client.GameStates;
using Robust.Shared.Exceptions;
using Robust.Client.Player;
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;
@@ -21,6 +17,7 @@ namespace Robust.Client.GameObjects
/// </summary>
public sealed class ClientEntityManager : EntityManager, IClientEntityManagerInternal
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IClientNetManager _networkManager = default!;
[Dependency] private readonly IClientGameStateManager _gameStateManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
@@ -67,7 +64,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)
@@ -148,7 +145,11 @@ namespace Robust.Client.GameObjects
return;
case EntityMessageType.SystemMessage:
ReceivedSystemMessage?.Invoke(this, message.SystemMessage);
var msg = message.SystemMessage;
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalPlayer!.Session), msg)!;
ReceivedSystemMessage?.Invoke(this, msg);
ReceivedSystemMessage?.Invoke(this, sessionMsg);
return;
}
}

View File

@@ -44,11 +44,29 @@ namespace Robust.Client.GameObjects
public bool Enabled
{
get => _enabled;
set => _enabled = value;
set
{
if (_enabled == value) return;
_enabled = value;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PointLightUpdateEvent());
}
}
[ViewVariables(VVAccess.ReadWrite)]
public bool ContainerOccluded { get; set; }
public bool ContainerOccluded
{
get => _containerOccluded;
set
{
if (_containerOccluded == value) return;
_containerOccluded = value;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PointLightUpdateEvent());
}
}
private bool _containerOccluded;
/// <summary>
/// Determines if the light mask should automatically rotate with the entity. (like a flashlight)
@@ -270,4 +288,9 @@ namespace Robust.Client.GameObjects
PointLightComponent = pointLightComponent;
}
}
internal sealed class PointLightUpdateEvent : EntityEventArgs
{
}
}

View File

@@ -42,7 +42,12 @@ namespace Robust.Client.GameObjects
public override bool Visible
{
get => _visible;
set => _visible = value;
set
{
if (_visible == value) return;
_visible = value;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new SpriteUpdateEvent());
}
}
[DataField("drawdepth", customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
@@ -152,7 +157,7 @@ namespace Robust.Client.GameObjects
}
set
{
if(value == null) return;
if (value == null) return;
Layers.Clear();
foreach (var layerDatum in value)
@@ -162,11 +167,12 @@ namespace Robust.Client.GameObjects
if (!string.IsNullOrWhiteSpace(layerDatum.RsiPath))
{
var path = TextureRoot / layerDatum.RsiPath;
try
if (IoCManager.Resolve<IResourceCache>().TryGetResource(path, out RSIResource? resource))
{
layer.RSI = IoCManager.Resolve<IResourceCache>().GetResource<RSIResource>(path).RSI;
layer.RSI = resource.RSI;
}
catch
else
{
Logger.ErrorS(LogCategory, "Unable to load layer RSI '{0}'.", path);
}
@@ -308,13 +314,24 @@ namespace Robust.Client.GameObjects
}
[DataField("sprite", readOnly: true)] private string? rsi;
[DataField("layers", readOnly: true)] private List<PrototypeLayerData> layerDatums = new ();
[DataField("layers", readOnly: true)] private List<PrototypeLayerData> layerDatums = new();
[DataField("state", readOnly: true)] private string? state;
[DataField("texture", readOnly: true)] private string? texture;
[ViewVariables(VVAccess.ReadWrite)]
public bool ContainerOccluded { get; set; }
public bool ContainerOccluded
{
get => _containerOccluded;
set
{
if (_containerOccluded == value) return;
_containerOccluded = value;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new SpriteUpdateEvent());
}
}
private bool _containerOccluded;
[ViewVariables(VVAccess.ReadWrite)]
public bool TreeUpdateQueued { get; set; }
@@ -348,13 +365,13 @@ namespace Robust.Client.GameObjects
if (!string.IsNullOrWhiteSpace(rsi))
{
var rsiPath = TextureRoot / rsi;
try
if(IoCManager.Resolve<IResourceCache>().TryGetResource(rsiPath, out RSIResource? resource))
{
BaseRSI = IoCManager.Resolve<IResourceCache>().GetResource<RSIResource>(rsiPath).RSI;
BaseRSI = resource.RSI;
}
catch (Exception e)
else
{
Logger.ErrorS(SpriteComponent.LogCategory, "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e);
Logger.ErrorS(LogCategory, "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath);
}
}
}
@@ -482,7 +499,7 @@ namespace Robust.Client.GameObjects
public int AddBlankLayer(int? newIndex = null)
{
var layer = new Layer(this) {Visible = false};
var layer = new Layer(this) { Visible = false };
return AddLayer(layer, newIndex);
}
@@ -511,13 +528,13 @@ namespace Robust.Client.GameObjects
public int AddLayer(Texture? texture, int? newIndex = null)
{
var layer = new Layer(this) {Texture = texture};
var layer = new Layer(this) { Texture = texture };
return AddLayer(layer, newIndex);
}
public int AddLayer(RSI.StateId stateId, int? newIndex = null)
{
var layer = new Layer(this) {State = stateId};
var layer = new Layer(this) { State = stateId };
if (BaseRSI != null && BaseRSI.TryGetState(stateId, out var state))
{
layer.AnimationTimeLeft = state.GetDelay(0);
@@ -563,7 +580,7 @@ namespace Robust.Client.GameObjects
public int AddLayer(RSI.StateId stateId, RSI? rsi, int? newIndex = null)
{
var layer = new Layer(this) {State = stateId, RSI = rsi};
var layer = new Layer(this) { State = stateId, RSI = rsi };
if (rsi != null && rsi.TryGetState(stateId, out var state))
{
layer.AnimationTimeLeft = state.GetDelay(0);
@@ -1288,8 +1305,8 @@ namespace Robust.Client.GameObjects
var layerColor = color * layer.Color;
var position = -(Vector2) texture.Size / (2f * EyeManager.PixelsPerMeter) + layer.Offset;
var textureSize = texture.Size / (float) EyeManager.PixelsPerMeter;
var position = -(Vector2)texture.Size / (2f * EyeManager.PixelsPerMeter) + layer.Offset;
var textureSize = texture.Size / (float)EyeManager.PixelsPerMeter;
var quad = Box2.FromDimensions(position, textureSize);
// TODO: Implement layer-specific rotation and scale.
@@ -1309,7 +1326,7 @@ namespace Robust.Client.GameObjects
public static Angle CalcRectWorldAngle(Angle worldAngle, int numDirections)
{
var theta = worldAngle.Theta;
var segSize = (MathF.PI*2) / (numDirections * 2);
var segSize = (MathF.PI * 2) / (numDirections * 2);
var segments = (int)(theta / segSize);
var odd = segments % 2;
var result = theta - (segments * segSize) - (odd * segSize);
@@ -1359,18 +1376,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 RenderTreeRemoveSpriteEvent(this, map));
}
}
public void FrameUpdate(float delta)
{
foreach (var t in Layers)
@@ -1421,7 +1426,7 @@ namespace Robust.Client.GameObjects
if (curState == null)
return;
var thestate = (SpriteComponentState) curState;
var thestate = (SpriteComponentState)curState;
Visible = thestate.Visible;
DrawDepth = thestate.DrawDepth;
@@ -1991,13 +1996,13 @@ namespace Robust.Client.GameObjects
switch (layerProp)
{
case "texture":
LayerSetTexture(index, (string) value);
LayerSetTexture(index, (string)value);
return;
case "state":
LayerSetState(index, (string) value);
LayerSetState(index, (string)value);
return;
case "color":
LayerSetColor(index, (Color) value);
LayerSetColor(index, (Color)value);
return;
default:
throw new ArgumentException($"Unknown layer property '{layerProp}'");
@@ -2042,7 +2047,7 @@ namespace Robust.Client.GameObjects
yield break;
}
var dummy = new DummyIconEntity {Prototype = prototype};
var dummy = new DummyIconEntity { Prototype = prototype };
var spriteComponent = dummy.AddComponent<SpriteComponent>();
if (prototype.Components.TryGetValue("Appearance", out _))
@@ -2086,7 +2091,7 @@ namespace Robust.Client.GameObjects
return GetFallbackState(resourceCache);
}
var dummy = new DummyIconEntity {Prototype = prototype};
var dummy = new DummyIconEntity { Prototype = prototype };
var spriteComponent = dummy.AddComponent<SpriteComponent>();
dummy.Delete();
@@ -2123,7 +2128,7 @@ namespace Robust.Client.GameObjects
{
var typeFactory = IoCManager.Resolve<IDynamicTypeFactoryInternal>();
var serializationManager = IoCManager.Resolve<ISerializationManager>();
var comp = (T) typeFactory.CreateInstanceUnchecked(typeof(T));
var comp = (T)typeFactory.CreateInstanceUnchecked(typeof(T));
_components[typeof(T)] = comp;
comp.Owner = this;
@@ -2157,7 +2162,7 @@ namespace Robust.Client.GameObjects
public T GetComponent<T>()
{
return (T) _components[typeof(T)];
return (T)_components[typeof(T)];
}
public IComponent GetComponent(Type type)
@@ -2169,7 +2174,7 @@ namespace Robust.Client.GameObjects
{
component = null;
if (!_components.TryGetValue(typeof(T), out var value)) return false;
component = (T) value;
component = (T)value;
return true;
}
@@ -2225,4 +2230,9 @@ namespace Robust.Client.GameObjects
}
#endregion
}
internal sealed class SpriteUpdateEvent : EntityEventArgs
{
}
}

View File

@@ -254,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;
}
@@ -301,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;
}

View File

@@ -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

View File

@@ -27,6 +27,8 @@ namespace Robust.Client.GameObjects
private readonly List<SpriteComponent> _spriteQueue = new();
private readonly List<PointLightComponent> _lightQueue = new();
private HashSet<EntityUid> _checkedChildren = new();
internal DynamicTree<SpriteComponent> GetSpriteTreeForMap(MapId map, GridId grid)
{
return _gridTrees[map][grid].SpriteTree;
@@ -50,16 +52,58 @@ namespace Robust.Client.GameObjects
_mapManager.OnGridCreated += MapManagerOnGridCreated;
_mapManager.OnGridRemoved += MapManagerOnGridRemoved;
// 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, RenderTreeRemoveSpriteEvent>(RemoveSprite);
SubscribeLocalEvent<SpriteComponent, ComponentRemove>(RemoveSprite);
SubscribeLocalEvent<SpriteComponent, SpriteUpdateEvent>(HandleSpriteUpdate);
SubscribeLocalEvent<PointLightComponent, EntMapIdChangedMessage>(LightMapChanged);
SubscribeLocalEvent<PointLightComponent, MoveEvent>(LightMoved);
SubscribeLocalEvent<PointLightComponent, EntParentChangedMessage>(LightParentChanged);
SubscribeLocalEvent<PointLightComponent, PointLightRadiusChangedEvent>(PointLightRadiusChanged);
SubscribeLocalEvent<PointLightComponent, RenderTreeRemoveLightEvent>(RemoveLight);
SubscribeLocalEvent<PointLightComponent, PointLightUpdateEvent>(HandleLightUpdate);
}
private void HandleLightUpdate(EntityUid uid, PointLightComponent component, PointLightUpdateEvent args)
{
if (component.TreeUpdateQueued) return;
QueueLightUpdate(component);
}
private void HandleSpriteUpdate(EntityUid uid, SpriteComponent component, SpriteUpdateEvent args)
{
if (component.TreeUpdateQueued) return;
QueueSpriteUpdate(component);
}
private void AnythingMoved(MoveEvent args)
{
AnythingMovedSubHandler(args.Sender.Transform);
}
private void AnythingMovedSubHandler(ITransformComponent sender)
{
// To avoid doing redundant updates (and we don't need to update a grid's children ever)
if (!_checkedChildren.Add(sender.Owner.Uid) ||
sender.Owner.HasComponent<MapGridComponent>() ||
sender.Owner.HasComponent<MapComponent>()) return;
// This recursive search is needed, as MoveEvent is defined to not care about indirect events like children.
// WHATEVER YOU DO, DON'T REPLACE THIS WITH SPAMMING EVENTS UNLESS YOU HAVE A GUARANTEE IT WON'T LAG THE GC.
// (Struct-based events ok though)
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
@@ -73,17 +117,12 @@ namespace Robust.Client.GameObjects
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, RenderTreeRemoveSpriteEvent args)
private void RemoveSprite(EntityUid uid, SpriteComponent component, ComponentRemove args)
{
ClearSprite(component);
}
@@ -108,22 +147,6 @@ namespace Robust.Client.GameObjects
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
@@ -133,11 +156,6 @@ namespace Robust.Client.GameObjects
QueueLightUpdate(component);
}
private void LightMoved(EntityUid uid, PointLightComponent component, MoveEvent args)
{
QueueLightUpdate(component);
}
private void LightParentChanged(EntityUid uid, PointLightComponent component, EntParentChangedMessage args)
{
QueueLightUpdate(component);
@@ -173,22 +191,6 @@ namespace Robust.Client.GameObjects
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
@@ -263,10 +265,19 @@ namespace Robust.Client.GameObjects
public override void FrameUpdate(float frameTime)
{
_checkedChildren.Clear();
foreach (var sprite in _spriteQueue)
{
sprite.TreeUpdateQueued = false;
var mapId = sprite.Owner.Transform.MapID;
if (!sprite.Visible || sprite.ContainerOccluded)
{
ClearSprite(sprite);
continue;
}
// If we're on a new map then clear the old one.
if (sprite.IntersectingMapId != mapId)
{
@@ -302,14 +313,19 @@ namespace Robust.Client.GameObjects
sprite.IntersectingGrids.Add(gridId);
}
sprite.TreeUpdateQueued = false;
}
foreach (var light in _lightQueue)
{
light.TreeUpdateQueued = false;
var mapId = light.Owner.Transform.MapID;
if (!light.Enabled || light.ContainerOccluded)
{
ClearLight(light);
continue;
}
// If we're on a new map then clear the old one.
if (light.IntersectingMapId != mapId)
{
@@ -325,7 +341,7 @@ namespace Robust.Client.GameObjects
var intersectingGrids = _mapManager.FindGridIdsIntersecting(mapId, aabb, true).ToList();
// Remove from old
foreach (var gridId in intersectingGrids)
foreach (var gridId in light.IntersectingGrids)
{
if (intersectingGrids.Contains(gridId)) continue;
mapTree[gridId].LightTree.Remove(light);
@@ -344,8 +360,6 @@ namespace Robust.Client.GameObjects
mapTree[gridId].LightTree.AddOrUpdate(light, translated);
light.IntersectingGrids.Add(gridId);
}
light.TreeUpdateQueued = false;
}
_spriteQueue.Clear();
@@ -380,18 +394,6 @@ namespace Robust.Client.GameObjects
}
}
internal class RenderTreeRemoveSpriteEvent : EntityEventArgs
{
public RenderTreeRemoveSpriteEvent(SpriteComponent sprite, MapId map)
{
Sprite = sprite;
Map = map;
}
public SpriteComponent Sprite { get; }
public MapId Map { get; }
}
internal class RenderTreeRemoveLightEvent : EntityEventArgs
{
public RenderTreeRemoveLightEvent(PointLightComponent light, MapId map)

View File

@@ -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);
@@ -393,7 +394,7 @@ namespace Robust.Client.GameStates
private List<EntityUid> ApplyGameState(GameState curState, GameState? nextState)
{
_config.TickProcessMessages();
_mapManager.ApplyGameStatePre(curState.MapData);
_mapManager.ApplyGameStatePre(curState.MapData, curState.EntityStates);
var createdEntities = ApplyEntityStates(curState.EntityStates, curState.EntityDeletions,
nextState?.EntityStates);
_players.ApplyPlayerStates(curState.PlayerStates);

View File

@@ -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();
@@ -183,32 +187,6 @@ namespace Robust.Client.Graphics.Clyde
if (handles.filterHandle != 0) EFX.DeleteFilter(handles.filterHandle);
}
public AudioStream LoadAudioRaw(short[] samples, int channels, int sampleRate)
{
var buffer = AL.GenBuffer();
unsafe
{
fixed (short* ptr = samples)
{
AL.BufferData(
buffer,
channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16,
(IntPtr) ptr,
samples.Length * 2,
sampleRate);
}
}
_checkAlError();
var handle = new ClydeHandle(_audioSampleBuffers.Count);
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
// ReSharper disable once PossibleLossOfFraction
var length = TimeSpan.FromSeconds(samples.Length / channels / (double) sampleRate);
return new AudioStream(handle, length, channels);
}
public void SetMasterVolume(float newVolume)
{
AL.Listener(ALListenerf.Gain, _baseGain * newVolume);
@@ -237,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);
}
}
@@ -356,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;
@@ -407,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
@@ -433,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();
}
}
@@ -448,7 +455,7 @@ namespace Robust.Client.Graphics.Clyde
{
_checkDisposed();
AL.Source(SourceHandle, ALSourceb.SourceRelative, true);
_checkAlError();
_master._checkAlError();
}
public void SetVolume(float decibels)
@@ -462,10 +469,10 @@ 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 decibels)
public void SetVolumeDirect(float scale)
{
_checkDisposed();
var priorOcclusion = 1f;
@@ -474,10 +481,9 @@ namespace Robust.Client.Graphics.Clyde
AL.GetSource(SourceHandle, ALSourcef.Gain, out var priorGain);
priorOcclusion = priorGain / _gain;
}
_gain = decibels;
_gain = scale;
AL.Source(SourceHandle, ALSourcef.Gain, _gain * priorOcclusion);
_checkAlError();
_master._checkAlError();
}
public void SetOcclusion(float blocks)
@@ -494,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)
@@ -514,7 +520,7 @@ namespace Robust.Client.Graphics.Clyde
{
_checkDisposed();
AL.Source(SourceHandle, ALSourcef.SecOffset, seconds);
_checkAlError();
_master._checkAlError();
}
public bool SetPosition(Vector2 position)
@@ -540,7 +546,7 @@ namespace Robust.Client.Graphics.Clyde
#endif
AL.Source(SourceHandle, ALSource3f.Position, x, y, 0);
_checkAlError();
_master._checkAlError();
return true;
}
@@ -567,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()
@@ -600,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;
@@ -650,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()
@@ -658,7 +664,7 @@ namespace Robust.Client.Graphics.Clyde
_checkDisposed();
// ReSharper disable once PossibleInvalidOperationException
AL.SourceStop(SourceHandle!.Value);
_checkAlError();
_master._checkAlError();
}
public bool IsPlaying
@@ -684,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()
@@ -703,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)
@@ -721,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)
@@ -741,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)
@@ -758,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;
}
@@ -785,22 +805,7 @@ namespace Robust.Client.Graphics.Clyde
AL.Source(SourceHandle!.Value, ALSource3f.Velocity, x, y, 0);
_checkAlError();
}
public void SetVolumeDirect(float masterVolumeDecay)
{
_checkDisposed();
var priorOcclusion = 1f;
if (!IsEfxSupported)
{
AL.GetSource(SourceHandle!.Value, ALSourcef.Gain, out var priorGain);
priorOcclusion = priorGain / _gain;
}
_gain = masterVolumeDecay;
AL.Source(SourceHandle!.Value, ALSourcef.Gain, _gain * priorOcclusion);
_checkAlError();
_master._checkAlError();
}
public void SetPitch(float pitch)
@@ -808,7 +813,7 @@ namespace Robust.Client.Graphics.Clyde
_checkDisposed();
// ReSharper disable once PossibleInvalidOperationException
AL.Source(SourceHandle!.Value, ALSourcef.Pitch, pitch);
_checkAlError();
_master._checkAlError();
}
~BufferedAudioSource()
@@ -839,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;

View File

@@ -387,12 +387,6 @@ namespace Robust.Client.Graphics.Clyde
ref RefList<(SpriteComponent sprite, Matrix3 matrix, Angle worldRot, float yWorldPos)> state,
in SpriteComponent value) =>
{
// TODO: Probably value in storing this as its own DynamicTree
if (value.ContainerOccluded || !value.Visible)
{
return true;
}
var entity = value.Owner;
var transform = entity.Transform;

View File

@@ -149,16 +149,16 @@ namespace Robust.Client.Graphics.Clyde
// FOV FBO.
_fovRenderTarget = CreateRenderTarget((FovMapSize, 2),
new RenderTargetFormatParameters(_hasGLFloatFramebuffers ? RenderTargetColorFormat.RG32F : RenderTargetColorFormat.Rgba8, true),
new TextureSampleParameters {WrapMode = TextureWrapMode.Repeat},
new TextureSampleParameters { WrapMode = TextureWrapMode.Repeat },
nameof(_fovRenderTarget));
if (_hasGLSamplerObjects)
{
_fovFilterSampler = new GLHandle(GL.GenSampler());
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMagFilter, (int) All.Linear);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMinFilter, (int) All.Linear);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapS, (int) All.Repeat);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapT, (int) All.Repeat);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMagFilter, (int)All.Linear);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMinFilter, (int)All.Linear);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapS, (int)All.Repeat);
GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapT, (int)All.Repeat);
CheckGlError();
}
@@ -180,20 +180,17 @@ namespace Robust.Client.Graphics.Clyde
_fovCalculationProgram = _compileProgram(depthVert, depthFrag, attribLocations, "Shadow Depth Program");
var debugShader = _resourceCache.GetResource<ShaderSourceResource>("/Shaders/Internal/depth-debug.swsl");
_fovDebugShaderInstance = (ClydeShaderInstance) InstanceShader(debugShader.ClydeHandle);
_fovDebugShaderInstance = (ClydeShaderInstance)InstanceShader(debugShader.ClydeHandle);
ClydeHandle LoadShaderHandle(string path)
{
try
if (_resourceCache.TryGetResource(path, out ShaderSourceResource? resource))
{
var shaderSource = _resourceCache.GetResource<ShaderSourceResource>(path);
return shaderSource.ClydeHandle;
}
catch (Exception ex)
{
Logger.Warning($"Can't load shader {path}\n{ex.GetType().Name}: {ex.Message}");
return default;
return resource.ClydeHandle;
}
Logger.Warning($"Can't load shader {path}\n");
return default;
}
_lightSoftShaderHandle = LoadShaderHandle("/Shaders/Internal/light-soft.swsl");
@@ -214,7 +211,7 @@ namespace Robust.Client.Graphics.Clyde
{
// Calculate maximum distance for the projection based on screen size.
var screenSizeCut = viewport.Size / EyeManager.PixelsPerMeter;
var maxDist = (float) Math.Max(screenSizeCut.X, screenSizeCut.Y);
var maxDist = (float)Math.Max(screenSizeCut.X, screenSizeCut.Y);
// FOV is rendered twice.
// Once with back face culling like regular lighting.
@@ -524,12 +521,6 @@ namespace Robust.Client.Graphics.Clyde
return false;
}
// TODO: Don't insert into trees for these, same as sprites.
if (!light.Enabled || light.ContainerOccluded)
{
return true;
}
var lightPos = transform.WorldMatrix.Transform(light.Offset);
var circle = new Circle(lightPos, light.Radius);
@@ -590,7 +581,7 @@ namespace Robust.Client.Graphics.Clyde
SetupGlobalUniformsImmediate(shader, viewport.LightRenderTarget.Texture);
shader.SetUniformMaybe("size", (Vector2) viewport.WallBleedIntermediateRenderTarget1.Size);
shader.SetUniformMaybe("size", (Vector2)viewport.WallBleedIntermediateRenderTarget1.Size);
shader.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);
var size = viewport.WallBleedIntermediateRenderTarget1.Size;
@@ -809,7 +800,7 @@ namespace Robust.Client.Graphics.Clyde
occluderTree.QueryAabb((in OccluderComponent sOccluder) =>
{
var occluder = (ClientOccluderComponent) sOccluder;
var occluder = (ClientOccluderComponent)sOccluder;
var transform = occluder.Owner.Transform;
if (!occluder.Enabled)
{
@@ -893,11 +884,11 @@ namespace Robust.Client.Graphics.Clyde
// DddD
// HHhh
// deflection
arrayVIBuffer[avi++] = (byte) ((((vi + 1) & 2) != 0) ? 0 : 255);
arrayVIBuffer[avi++] = (byte)((((vi + 1) & 2) != 0) ? 0 : 255);
// height
arrayVIBuffer[avi++] = (byte) (((vi & 2) != 0) ? 0 : 255);
arrayVIBuffer[avi++] = (byte)(((vi & 2) != 0) ? 0 : 255);
}
QuadBatchIndexWrite(indexBuffer, ref ii, (ushort) aiBase);
QuadBatchIndexWrite(indexBuffer, ref ii, (ushort)aiBase);
}
// North face (TL/TR)
@@ -931,7 +922,7 @@ namespace Robust.Client.Graphics.Clyde
arrayMaskBuffer[ami + 3] = new Vector2(blX, blY);
// Generate mask indices.
QuadBatchIndexWrite(indexMaskBuffer, ref imi, (ushort) ami);
QuadBatchIndexWrite(indexMaskBuffer, ref imi, (ushort)ami);
ami += 4;
@@ -973,7 +964,7 @@ namespace Robust.Client.Graphics.Clyde
var lightMapSize = GetLightMapSize(viewport.Size);
var lightMapSizeQuart = GetLightMapSize(viewport.Size, true);
var lightMapColorFormat = _hasGLFloatFramebuffers ? RenderTargetColorFormat.R11FG11FB10F : RenderTargetColorFormat.Rgba8;
var lightMapSampleParameters = new TextureSampleParameters {Filter = true};
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };
viewport.LightRenderTarget?.Dispose();
viewport.WallMaskRenderTarget?.Dispose();
@@ -1010,14 +1001,14 @@ namespace Robust.Client.Graphics.Clyde
private Vector2i GetLightMapSize(Vector2i screenSize, bool furtherDivide = false)
{
var divider = (float) _lightmapDivider;
var divider = (float)_lightmapDivider;
if (furtherDivide)
{
divider *= 2;
}
var w = (int) Math.Ceiling(screenSize.X / divider);
var h = (int) Math.Ceiling(screenSize.Y / divider);
var w = (int)Math.Ceiling(screenSize.X / divider);
var h = (int)Math.Ceiling(screenSize.Y / divider);
return (w, h);
}
@@ -1043,7 +1034,7 @@ namespace Robust.Client.Graphics.Clyde
// Shadow FBO.
_shadowRenderTarget = CreateRenderTarget((ShadowMapSize, _maxLightsPerScene),
new RenderTargetFormatParameters(_hasGLFloatFramebuffers ? RenderTargetColorFormat.RG32F : RenderTargetColorFormat.Rgba8, true),
new TextureSampleParameters {WrapMode = TextureWrapMode.Repeat, Filter = true},
new TextureSampleParameters { WrapMode = TextureWrapMode.Repeat, Filter = true },
nameof(_shadowRenderTarget));
}

View File

@@ -248,9 +248,10 @@ namespace Robust.Client.Graphics.Clyde
return new(default, default, 1, name);
}
public AudioStream LoadAudioRaw(short[] samples, int channels, int sampleRate)
public AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null)
{
throw new NotImplementedException();
// TODO: Might wanna actually load this so the length gets reported correctly.
return new(default, default, channels, name);
}
public IClydeAudioSource CreateAudioSource(AudioStream stream)
@@ -328,6 +329,11 @@ namespace Robust.Client.Graphics.Clyde
// Nada.
}
public void SetVolumeDirect(float scale)
{
// Nada.
}
public void SetOcclusion(float blocks)
{
// Nada.
@@ -342,11 +348,6 @@ namespace Robust.Client.Graphics.Clyde
{
// Nada.
}
public void SetVolumeDirect(float masterVolumeDecay)
{
// Nada.
}
}
private sealed class DummyBufferedAudioSource : DummyAudioSource, IClydeBufferedAudioSource

View File

@@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using Robust.Client.Audio;
namespace Robust.Client.Graphics
@@ -8,7 +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(short[] samples, int channels, int sampleRate);
AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null);
void SetMasterVolume(float newVolume);

View File

@@ -18,9 +18,9 @@ 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);
void SetVolumeDirect(float masterVolumeDecay);
}
}

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Maths;
namespace Robust.Client.Graphics
{
public interface IRenderHandle
internal interface IRenderHandle
{
DrawingHandleScreen DrawingHandleScreen { get; }
DrawingHandleWorld DrawingHandleWorld { get; }

View File

@@ -1,72 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Robust.Client.Map
{
internal class ClientMapManager : MapManager, IClientMapManager
{
[Dependency] private readonly INetManager _netManager = default!;
public void ApplyGameStatePre(GameStateMapData? data)
public void ApplyGameStatePre(GameStateMapData? data, EntityState[]? entityStates)
{
// There was no map data this tick, so nothing to do.
if(data == null)
return;
var createdGrids = data.CreatedGrids != null
? new Dictionary<GridId, GameStateMapData.GridCreationDatum>(data.CreatedGrids)
: null;
// First we need to figure out all the NEW MAPS.
if(data.CreatedMaps != null)
{
DebugTools.Assert(entityStates is not null, "Received new maps, but no entity state.");
foreach (var mapId in data.CreatedMaps)
{
// map already exists from a previous state.
if (_maps.Contains(mapId))
{
continue;
}
CreateMap(mapId);
EntityUid mapEuid = default;
//get shared euid of map comp entity
foreach (var entityState in entityStates!)
{
if(entityState.ComponentStates is null)
continue;
foreach (var compState in entityState.ComponentStates)
{
if (compState is not MapComponentState mapCompState || mapCompState.MapId != mapId)
continue;
mapEuid = entityState.Uid;
goto BreakMapEntSearch;
}
}
BreakMapEntSearch:
DebugTools.Assert(mapEuid != default, $"Could not find corresponding entity state for new map {mapId}.");
CreateMap(mapId, mapEuid);
}
}
// Then make all the grids.
if(data.CreatedGrids != null)
{
var gridData = data.GridData != null
? new Dictionary<GridId, GameStateMapData.GridDatum>(data.GridData)
: null;
DebugTools.AssertNotNull(createdGrids);
DebugTools.Assert(data.GridData is not null, "Received new grids, but GridData was null.");
foreach (var (gridId, creationDatum) in data.CreatedGrids)
{
if (_grids.ContainsKey(gridId))
{
continue;
EntityUid gridEuid = default;
//get shared euid of map comp entity
foreach (var entityState in entityStates!)
{
if(entityState.ComponentStates is null)
continue;
foreach (var compState in entityState.ComponentStates)
{
if (compState is not MapGridComponentState gridCompState || gridCompState.GridIndex != gridId)
continue;
gridEuid = entityState.Uid;
goto BreakGridEntSearch;
}
}
BreakGridEntSearch:
DebugTools.Assert(gridEuid != default, $"Could not find corresponding entity state for new grid {gridId}.");
MapId gridMapId = default;
foreach (var kvData in data.GridData!)
{
if (kvData.Key != gridId)
continue;
gridMapId = kvData.Value.Coordinates.MapId;
break;
}
CreateGrid(gridData![gridId].Coordinates.MapId, gridId, creationDatum.ChunkSize);
DebugTools.Assert(gridMapId != default, $"Could not find corresponding gridData for new grid {gridId}.");
CreateGrid(gridMapId, gridId, creationDatum.ChunkSize, gridEuid);
}
}
// Process all grid updates.
if(data.GridData != null)
{
SuppressOnTileChanged = true;
// Ok good all the grids and maps exist now.
foreach (var (gridId, gridDatum) in data.GridData)
{
var grid = _grids[gridId];
if (grid.ParentMapId != gridDatum.Coordinates.MapId)
{
@@ -112,99 +151,9 @@ namespace Robust.Client.Map
public void ApplyGameStatePost(GameStateMapData? data)
{
DebugTools.Assert(_netManager.IsClient, "Only the client should call this.");
if(data == null) // if there is no data, there is nothing to do!
return;
// maps created on the client in pre-state are linked to client entities
// resolve new maps with their shared component that the server just gave us
// and delete the client entities
if (data.CreatedMaps != null)
{
foreach (var mapId in data.CreatedMaps)
{
// CreateMap should have set this
DebugTools.Assert(_mapEntities.ContainsKey(mapId));
// this was already linked in a previous state.
if(!_mapEntities[mapId].IsClientSide())
continue;
// get the existing client entity for the map.
var cEntity = EntityManager.GetEntity(_mapEntities[mapId]);
// locate the entity that represents this map that was just sent to us
IEntity? sharedMapEntity = null;
var mapComps = EntityManager.ComponentManager.EntityQuery<IMapComponent>(true);
foreach (var mapComp in mapComps)
{
if (!mapComp.Owner.Uid.IsClientSide() && mapComp.WorldMap == mapId)
{
sharedMapEntity = mapComp.Owner;
_mapEntities[mapId] = mapComp.Owner.Uid;
Logger.DebugS("map", $"Map {mapId} pivoted bound entity from {cEntity.Uid} to {mapComp.Owner.Uid}.");
break;
}
}
// verify shared entity was found (the server sent us one)
DebugTools.AssertNotNull(sharedMapEntity);
DebugTools.Assert(!_mapEntities[mapId].IsClientSide());
// Transfer client child grids made in GameStatePre to the shared component
// so they are not deleted
foreach (var childGridTrans in cEntity.Transform.Children.ToList())
{
childGridTrans.AttachParent(sharedMapEntity!);
}
// remove client entity
var cGridComp = cEntity.GetComponent<IMapComponent>();
cGridComp.ClearMapId();
cEntity.Delete();
}
}
// grids created on the client in pre-state are linked to client entities
// resolve new grids with their shared component that the server just gave us
// and delete the client entities
if (data.CreatedGrids != null)
{
foreach (var kvNewGrid in data.CreatedGrids)
{
var grid = _grids[kvNewGrid.Key];
// this was already linked in a previous state.
if(!grid.GridEntityId.IsClientSide())
continue;
// remove the existing client entity.
var cEntity = EntityManager.GetEntity(grid.GridEntityId);
var cGridComp = cEntity.GetComponent<IMapGridComponent>();
// prevents us from deleting the grid when deleting the grid entity
if(cEntity.Uid.IsClientSide())
cGridComp.ClearGridId();
cEntity.Delete(); // normal entities are already parented to the shared comp, client comp has no children
var gridComps = EntityManager.ComponentManager.EntityQuery<IMapGridComponent>(true);
foreach (var gridComp in gridComps)
{
if (gridComp.GridIndex == kvNewGrid.Key)
{
grid.GridEntityId = gridComp.Owner.Uid;
Logger.DebugS("map", $"Grid {grid.Index} pivoted bound entity from {cEntity.Uid} to {grid.GridEntityId}.");
break;
}
}
DebugTools.Assert(!grid.GridEntityId.IsClientSide());
}
}
if(data.DeletedGrids != null)
{
foreach (var grid in data.DeletedGrids)

View File

@@ -1,3 +1,4 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
@@ -7,7 +8,7 @@ namespace Robust.Client.Map
{
// Two methods here, so that new grids etc can be made BEFORE entities get states applied,
// but old ones can be deleted after.
void ApplyGameStatePre(GameStateMapData? data);
void ApplyGameStatePre(GameStateMapData? data, EntityState[]? entityStates);
void ApplyGameStatePost(GameStateMapData? data);
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.GameObjects;
@@ -25,7 +25,6 @@ namespace Robust.Client.Placement
{
public partial class PlacementManager : IPlacementManager, IDisposable
{
[Dependency] public readonly IPhysicsManager PhysicsManager = default!;
[Dependency] private readonly IClientNetManager NetworkManager = default!;
[Dependency] public readonly IPlayerManager PlayerManager = default!;
[Dependency] public readonly IResourceCache ResourceCache = default!;
@@ -156,7 +155,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>())

View File

@@ -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;
@@ -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 />

View File

@@ -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;

View File

@@ -463,7 +463,7 @@ namespace Robust.Client.UserInterface
{
}
public virtual void DrawInternal(IRenderHandle renderHandle)
internal virtual void DrawInternal(IRenderHandle renderHandle)
{
Draw(renderHandle.DrawingHandleScreen);
}

View File

@@ -1,4 +1,4 @@
using Robust.Client.GameObjects;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Maths;
@@ -41,14 +41,14 @@ namespace Robust.Client.UserInterface.Controls
return (32, 32) * Scale;
}
public override void DrawInternal(IRenderHandle renderHandle)
internal override void DrawInternal(IRenderHandle renderHandle)
{
if (Sprite == null || Sprite.Deleted)
{
return;
}
renderHandle.DrawEntity(Sprite.Owner, GlobalPixelPosition + PixelSize / 2, Scale, OverrideDirection);
renderHandle.DrawEntity(Sprite.Owner, GlobalPixelPosition + PixelSize / 2, Scale * UIScale, OverrideDirection);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
@@ -165,6 +165,8 @@ namespace Robust.Client.UserInterface.CustomControls
protected internal override void MouseExited()
{
base.MouseExited();
if (Resizable && CurrentDrag == DragMode.None)
{
DefaultCursorShape = CursorShape.Arrow;

View File

@@ -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}";
}
}
}

View File

@@ -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)

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime;
@@ -217,6 +217,28 @@ 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;
}
}
ProgramShared.PrintRuntimeInfo(_log.RootSawmill);
SelfLog.Enable(s => { System.Console.WriteLine("SERILOG ERROR: {0}", s); });
if (!SetupLoki())
@@ -330,6 +352,7 @@ namespace Robust.Server
_watchdogApi.Initialize();
AddFinalStringsToSerializer();
_stringSerializer.LockStrings();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _config.GetCVar(CVars.SysWinTickPeriod) >= 0)
@@ -342,6 +365,29 @@ 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);
}
using var extraMappedStrings = typeof(BaseServer).Assembly
.GetManifestResourceStream("Robust.Server.ExtraMappedSerializerStrings.txt");
if (extraMappedStrings != null)
{
using var sr = new StreamReader(extraMappedStrings);
string? line;
while ((line = sr.ReadLine()) != null)
{
_stringSerializer.AddString(line);
}
}
}
private bool SetupLoki()
{
var enabled = _config.GetCVar(CVars.LokiEnabled);

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -14,7 +14,7 @@ namespace Robust.Server.Debugging
public void Initialize()
{
_net.RegisterNetMessage<MsgRay>(MsgRay.NAME);
_net.RegisterNetMessage<MsgRay>();
// TODO _physics.DebugDrawRay += data => PhysicsOnDebugDrawRay(data);
}

View File

@@ -0,0 +1 @@
fixture-0

View File

@@ -9,18 +9,8 @@ namespace Robust.Server.GameObjects
{
public override string Name => "Actor";
[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();
}
[ViewVariables]
public IPlayerSession PlayerSession { get; internal set; } = default!;
}
/// <summary>
@@ -52,26 +42,4 @@ namespace Robust.Server.GameObjects
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; }
}
}

View 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;
}
}
}

View File

@@ -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,18 @@ 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);
var aabb = _lookup.GetWorldAabbFromEntity(entity);
// 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);
// Need to clip the aabb as anything with an edge intersecting another tile might be picked up, such as walls.
return aabb.Scale(0.98f);
}
public override void Initialize()
{
base.Initialize();
#if DEBUG
SubscribeNetworkEvent<RequestGridTileLookupMessage>(HandleRequest);
#endif
SubscribeLocalEvent<MoveEvent>(HandleEntityMove);
SubscribeLocalEvent<EntityInitializedMessage>(HandleEntityInitialized);
SubscribeLocalEvent<EntityDeletedMessage>(HandleEntityDeleted);
@@ -225,6 +228,14 @@ namespace Robust.Server.GameObjects
_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);

View File

@@ -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;
@@ -233,6 +232,7 @@ namespace Robust.Server.GameObjects
var msg = message.SystemMessage;
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(player), msg)!;
ReceivedSystemMessage?.Invoke(this, msg);
ReceivedSystemMessage?.Invoke(this, sessionMsg);
return;
}

View File

@@ -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()

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -107,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;

View File

@@ -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<ActorComponent>();
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<ActorComponent>(out var actor))
if (!detachPlayer.Result)
{
AttachedEntity.SendMessage(actor, new PlayerDetachedMsg(this));
AttachedEntity.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PlayerDetachedSystemMessage(AttachedEntity));
AttachedEntity.RemoveComponent<ActorComponent>();
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;

View File

@@ -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)

View File

@@ -29,6 +29,9 @@
<Content Include="server_config.toml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="ExtraMappedSerializerStrings.txt">
<LogicalName>Robust.Server.ExtraMappedSerializerStrings.txt</LogicalName>
</EmbeddedResource>
</ItemGroup>
<Import Project="..\MSBuild\Robust.Engine.targets" />
</Project>

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -1,45 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace Robust.Shared.Maths
{
[Obsolete("Use MathHelper instead.")]
public static class FloatMath
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Clamp01(float val)
{
return MathHelper.Clamp01(val);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Clamp<T>(T val, T min, T max) where T : IComparable<T>
{
return MathHelper.Clamp(val, min, max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Clamp(float val, float min, float max)
{
return MathHelper.Clamp(val, min, max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Clamp(double val, double min, double max)
{
return MathHelper.Clamp(val, min, max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool CloseTo(float a, float b, double tolerance = .00001)
{
return MathHelper.CloseTo(a, b, tolerance);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Lerp(float a, float b, float blend)
{
return MathHelper.Lerp(a, b, blend);
}
}
}

View File

@@ -463,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);
}
}

View File

@@ -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)

View File

@@ -145,7 +145,7 @@ namespace Robust.Shared.Containers
{
DebugTools.Assert(!Deleted);
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new EntInsertedIntoContainerMessage(toinsert, this));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new EntInsertedIntoContainerMessage(toinsert, this));
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new UpdateContainerOcclusionMessage(toinsert));
Manager.Owner.SendMessage(Manager, new ContainerContentsModifiedMessage(this, toinsert, false));
Manager.Dirty();
@@ -162,7 +162,7 @@ namespace Robust.Shared.Containers
DebugTools.AssertNotNull(toremove);
DebugTools.Assert(toremove.IsValid());
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new EntRemovedFromContainerMessage(toremove, this));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new EntRemovedFromContainerMessage(toremove, this));
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new UpdateContainerOcclusionMessage(toremove));
Manager.Owner.SendMessage(Manager, new ContainerContentsModifiedMessage(this, toremove, true));
Manager.Dirty();

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -21,6 +21,8 @@ namespace Robust.Shared.GameObjects
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
#endif
public IComponentFactory ComponentFactory => _componentFactory;
private const int TypeCapacity = 32;
private const int ComponentCollectionCapacity = 1024;
private const int EntityCapacity = 1024;

View File

@@ -30,12 +30,6 @@ namespace Robust.Shared.GameObjects
void CollideWith(Fixture ourFixture, Fixture otherFixture, in Manifold manifold);
}
public interface ICollideSpecial
{
[Obsolete("Use PreventCollideEvent instead")]
bool PreventCollide(IPhysBody collidedwith);
}
[Serializable, NetSerializable]
public enum BodyStatus: byte
{

View File

@@ -24,6 +24,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Containers;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -163,11 +164,11 @@ namespace Robust.Shared.GameObjects
if (value)
{
_sleepTime = 0.0f;
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PhysicsWakeMessage(this));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PhysicsWakeMessage(this));
}
else
{
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PhysicsSleepMessage(this));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PhysicsSleepMessage(this));
ResetDynamics();
_sleepTime = 0.0f;
}
@@ -261,10 +262,7 @@ namespace Robust.Shared.GameObjects
{
fixture.Body = this;
fixture.ComputeProperties();
if (string.IsNullOrEmpty(fixture.Name))
{
fixture.Name = GetFixtureName(fixture);
}
fixture.ID = GetFixtureName(fixture);
}
ResetMassData();
@@ -285,7 +283,7 @@ namespace Robust.Shared.GameObjects
joints.Add(je.Joint);
}
return new PhysicsComponentState(_canCollide, _sleepingAllowed, _fixedRotation, _bodyStatus, _fixtures, joints, _mass, LinearVelocity, AngularVelocity, BodyType);
return new PhysicsComponentState(_canCollide, _sleepingAllowed, _fixedRotation, _bodyStatus, _fixtures, joints, LinearVelocity, AngularVelocity, BodyType);
}
/// <inheritdoc />
@@ -304,60 +302,76 @@ namespace Robust.Shared.GameObjects
// We will pray that this deferred joint is handled properly.
// TODO: Crude as FUCK diffing here as well, fine for now.
/*
* -- Joints --
*/
var existingJoints = new List<Joint>();
// TODO: Iterating like this is inefficient and bloated as fuck but on the other hand the linked-list is very convenient
// for bodies with a large number of fixtures / joints.
// Probably store them in Dictionaries but still store the linked-list stuff on the fixture / joint itself.
var existingJoints = Joints.ToList();
var toAddJoints = new List<Joint>();
var toRemoveJoints = new List<Joint>();
for (var je = JointEdges; je != null; je = je.Next)
foreach (var newJoint in newState.Joints)
{
existingJoints.Add(je.Joint);
}
var jointFound = false;
var jointsDiff = true;
if (existingJoints.Count == newState.Joints.Count)
{
var anyDiff = false;
for (var i = 0; i < existingJoints.Count; i++)
foreach (var joint in existingJoints)
{
var existing = existingJoints[i];
var newJoint = newState.Joints[i];
if (!existing.Equals(newJoint))
if (joint.ID.Equals(newJoint.ID))
{
anyDiff = true;
if (!newJoint.Equals(joint) && TrySetupNetworkedJoint(newJoint))
{
toAddJoints.Add(newJoint);
toRemoveJoints.Add(joint);
}
jointFound = true;
break;
}
}
if (!anyDiff)
if (!jointFound && TrySetupNetworkedJoint(newJoint))
{
jointsDiff = false;
toAddJoints.Add(newJoint);
}
}
if (jointsDiff)
foreach (var joint in existingJoints)
{
ClearJoints();
var jointFound = false;
foreach (var joint in newState.Joints)
foreach (var newJoint in newState.Joints)
{
joint.EdgeA = new JointEdge();
joint.EdgeB = new JointEdge();
// Defer joints given it relies on 2 bodies.
AddJoint(joint);
if (joint.ID.Equals(newJoint.ID))
{
jointFound = true;
break;
}
}
if (jointFound) continue;
toRemoveJoints.Add(joint);
}
foreach (var joint in toRemoveJoints)
{
RemoveJoint(joint);
}
foreach (var joint in toAddJoints)
{
AddJoint(joint);
}
/*
* -- Fixtures --
*/
var toAdd = new List<Fixture>();
var toRemove = new List<Fixture>();
var toAddFixtures = new List<Fixture>();
var toRemoveFixtures = new List<Fixture>();
var computeProperties = false;
// Given a bunch of data isn't serialized need to sort of re-initialise it
@@ -377,12 +391,12 @@ namespace Robust.Shared.GameObjects
foreach (var existing in _fixtures)
{
if (!fixture.Name.Equals(existing.Name)) continue;
if (!fixture.ID.Equals(existing.ID)) continue;
if (!fixture.Equals(existing))
{
toAdd.Add(fixture);
toRemove.Add(existing);
toAddFixtures.Add(fixture);
toRemoveFixtures.Add(existing);
}
found = true;
@@ -391,7 +405,7 @@ namespace Robust.Shared.GameObjects
if (!found)
{
toAdd.Add(fixture);
toAddFixtures.Add(fixture);
}
}
@@ -402,7 +416,7 @@ namespace Robust.Shared.GameObjects
foreach (var fixture in newFixtures)
{
if (fixture.Name.Equals(existing.Name))
if (fixture.ID.Equals(existing.ID))
{
found = true;
break;
@@ -411,18 +425,18 @@ namespace Robust.Shared.GameObjects
if (!found)
{
toRemove.Add(existing);
toRemoveFixtures.Add(existing);
}
}
foreach (var fixture in toRemove)
foreach (var fixture in toRemoveFixtures)
{
computeProperties = true;
RemoveFixture(fixture);
}
// TODO: We also still need event listeners for shapes (Probably need C# events)
foreach (var fixture in toAdd)
foreach (var fixture in toAddFixtures)
{
computeProperties = true;
AddFixture(fixture);
@@ -446,6 +460,29 @@ namespace Robust.Shared.GameObjects
Predict = false;
}
private bool TrySetupNetworkedJoint(Joint joint)
{
// This can fail if we've already deleted the entity or remove physics from it I think?
if (!Owner.EntityManager.TryGetEntity(joint.BodyAUid, out var entityA) ||
!entityA.TryGetComponent(out PhysicsComponent? bodyA))
{
return false;
}
if (!Owner.EntityManager.TryGetEntity(joint.BodyBUid, out var entityB) ||
!entityB.TryGetComponent(out PhysicsComponent? bodyB))
{
return false;
}
joint.BodyA = bodyA;
joint.BodyB = bodyB;
joint.EdgeA = new JointEdge();
joint.EdgeB = new JointEdge();
return true;
}
public Fixture? GetFixture(string name)
{
// Sooo I'd rather have fixtures as a list in serialization but there's not really an easy way to have it as a
@@ -455,7 +492,7 @@ namespace Robust.Shared.GameObjects
// If we really need it then you just deserialize onto a dummy field that then just never gets used again.
foreach (var fixture in _fixtures)
{
if (fixture.Name.Equals(name))
if (fixture.ID.Equals(name))
{
return fixture;
}
@@ -477,35 +514,23 @@ namespace Robust.Shared.GameObjects
Dirty();
}
public Box2 GetWorldAABB(IMapManager? mapManager = null)
public Box2 GetWorldAABB(Vector2? worldPos = null, Angle? worldRot = null)
{
mapManager ??= IoCManager.Resolve<IMapManager>();
var bounds = new Box2();
worldPos ??= Owner.Transform.WorldPosition;
worldRot ??= Owner.Transform.WorldRotation;
var worldPosValue = worldPos.Value;
var worldRotValue = worldRot.Value;
var bounds = new Box2(worldPosValue, worldPosValue);
foreach (var fixture in _fixtures)
{
foreach (var (gridId, proxies) in fixture.Proxies)
{
Vector2 offset;
if (gridId == GridId.Invalid)
{
offset = Vector2.Zero;
}
else
{
offset = mapManager.GetGrid(gridId).WorldPosition;
}
foreach (var proxy in proxies)
{
var shapeBounds = proxy.AABB.Translated(offset);
bounds = bounds.IsEmpty() ? shapeBounds : bounds.Union(shapeBounds);
}
}
var boundy = fixture.Shape.CalculateLocalBounds(worldRotValue);
bounds = bounds.Union(boundy.Translated(worldPosValue));
}
return bounds.IsEmpty() ? Box2.UnitCentered.Translated(Owner.Transform.WorldPosition) : bounds;
return bounds;
}
/// <inheritdoc />
@@ -546,7 +571,6 @@ namespace Robust.Shared.GameObjects
return;
_canCollide = value;
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new CollisionChangeMessage(this, Owner.Uid, _canCollide));
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PhysicsUpdateMessage(this));
Dirty();
@@ -968,12 +992,46 @@ namespace Robust.Shared.GameObjects
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new FixtureUpdateMessage(this, fixture));
}
internal string GetFixtureName(Fixture fixture)
private string GetFixtureName(Fixture fixture)
{
if (!string.IsNullOrEmpty(fixture.ID)) return fixture.ID;
// For any fixtures that aren't named in the code we will assign one.
return $"fixture-{_fixtures.IndexOf(fixture)}";
}
private string GetJointName(Joint joint)
{
var id = joint.ID;
if (!string.IsNullOrEmpty(id)) return id;
var jointCount = Joints.Count();
for (var i = 0; i < jointCount + 1; i++)
{
id = $"joint-{i}";
if (GetJoint(id) != null) continue;
return id;
}
Logger.WarningS("physics", $"Unable to get a joint ID; using its hashcode instead.");
return joint.GetHashCode().ToString();
}
/// <summary>
/// Get a joint with the specified ID.
/// </summary>
public Joint? GetJoint(string id)
{
foreach (var joint in Joints)
{
if (joint.ID == id) return joint;
}
return null;
}
internal Transform GetTransform()
{
return new(Owner.Transform.WorldPosition, (float) Owner.Transform.WorldRotation.Theta);
@@ -1121,15 +1179,10 @@ namespace Robust.Shared.GameObjects
else
{
// TODO: Probably a bad idea but ehh future sloth's problem; namely that we have to duplicate code between here and CanCollide.
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new CollisionChangeMessage(this, Owner.Uid, _canCollide));
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new PhysicsUpdateMessage(this));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new CollisionChangeMessage(this, Owner.Uid, _canCollide));
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PhysicsUpdateMessage(this));
}
}
if (EntitySystem.Get<SharedPhysicsSystem>().Maps.TryGetValue(Owner.Transform.MapID, out var map))
{
PhysicsMap = map;
}
}
public void ClearJoints()
@@ -1181,12 +1234,23 @@ namespace Robust.Shared.GameObjects
public void AddJoint(Joint joint)
{
var id = GetJointName(joint);
foreach (var existing in Joints)
{
// This can happen if a server created joint is sent and applied before the client can create it locally elsewhere
if (existing.ID.Equals(id)) return;
}
PhysicsMap.AddJoint(joint);
joint.ID = id;
Logger.DebugS("physics", $"Added joint id: {joint.ID} type: {joint.GetType().Name} to {Owner}");
}
public void RemoveJoint(Joint joint)
{
PhysicsMap.RemoveJoint(joint);
Logger.DebugS("physics", $"Removed joint id: {joint.ID} type: {joint.GetType().Name} from {Owner}");
}
public override void OnRemove()
@@ -1294,17 +1358,10 @@ namespace Robust.Shared.GameObjects
if (preventCollideMessage.Cancelled) return false;
#pragma warning disable 618
foreach (var comp in Owner.GetAllComponents<ICollideSpecial>())
{
if (comp.PreventCollide(other)) return false;
}
preventCollideMessage = new PreventCollideEvent(other, this);
Owner.EntityManager.EventBus.RaiseLocalEvent(other.Owner.Uid, preventCollideMessage);
foreach (var comp in other.Owner.GetAllComponents<ICollideSpecial>())
{
if (comp.PreventCollide(this)) return false;
}
#pragma warning restore 618
if (preventCollideMessage.Cancelled) return false;
return true;
}

View File

@@ -18,10 +18,6 @@ namespace Robust.Shared.GameObjects
public readonly List<Fixture> Fixtures;
public readonly List<Joint> Joints;
/// <summary>
/// Current mass of the entity, stored in grams.
/// </summary>
public readonly int Mass;
public readonly Vector2 LinearVelocity;
public readonly float AngularVelocity;
public readonly BodyType BodyType;
@@ -35,7 +31,6 @@ namespace Robust.Shared.GameObjects
/// <param name="status"></param>
/// <param name="fixtures"></param>
/// <param name="joints"></param>
/// <param name="mass">Current Mass of the entity.</param>
/// <param name="linearVelocity">Current linear velocity of the entity in meters per second.</param>
/// <param name="angularVelocity">Current angular velocity of the entity in radians per sec.</param>
/// <param name="bodyType"></param>
@@ -46,7 +41,6 @@ namespace Robust.Shared.GameObjects
BodyStatus status,
List<Fixture> fixtures,
List<Joint> joints,
float mass,
Vector2 linearVelocity,
float angularVelocity,
BodyType bodyType)
@@ -61,7 +55,6 @@ namespace Robust.Shared.GameObjects
LinearVelocity = linearVelocity;
AngularVelocity = angularVelocity;
Mass = (int) Math.Round(mass * 1000); // rounds kg to nearest gram
BodyType = bodyType;
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using Robust.Shared.Physics;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
@@ -32,7 +33,7 @@ namespace Robust.Shared.GameObjects
}
}
private void RaiseStateChange()
internal void RaiseStateChange()
{
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new CollisionWakeStateMessage(), false);
}

View File

@@ -115,7 +115,7 @@ namespace Robust.Shared.GameObjects
// Set _nextRotation to null to break any active lerps if this is a client side prediction.
_nextRotation = null;
SetRotation(value);
_localRotation = value;
Dirty();
if (!DeferUpdates)
@@ -258,17 +258,51 @@ namespace Robust.Shared.GameObjects
var valid = _parent.IsValid();
return new EntityCoordinates(valid ? _parent : Owner.Uid, valid ? LocalPosition : Vector2.Zero);
}
// NOTE: This setter must be callable from before initialize (inheriting from AttachParent's note)
set
{
var oldPosition = Coordinates;
_localPosition = value.Position;
var changedParent = false;
if (value.EntityId != _parent)
{
var newEntity = Owner.EntityManager.GetEntity(value.EntityId);
AttachParent(newEntity);
changedParent = true;
var newParentEnt = Owner.EntityManager.GetEntity(value.EntityId);
var newParent = newParentEnt.Transform;
DebugTools.Assert(newParent != this,
$"Can't parent a {nameof(ITransformComponent)} to itself.");
// That's already our parent, don't bother attaching again.
var oldParent = Parent;
var oldConcrete = (TransformComponent?) oldParent;
var uid = Owner.Uid;
oldConcrete?._children.Remove(uid);
var newConcrete = (TransformComponent) newParent;
newConcrete._children.Add(uid);
var oldParentOwner = oldParent?.Owner;
var entMessage = new EntParentChangedMessage(Owner, oldParentOwner);
var compMessage = new ParentChangedMessage(newParentEnt, oldParentOwner);
// offset position from world to parent
_parent = newParentEnt.Uid;
ChangeMapId(newConcrete.MapID);
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, entMessage);
Owner.SendMessage(this, compMessage);
GridID = GetGridIndex();
}
// These conditions roughly emulate the effects of the code before I changed things,
// in regards to when to rebuild matrices.
// This may not in fact be the right thing.
if (changedParent || !DeferUpdates)
RebuildMatrices();
Dirty();
if (!DeferUpdates)
@@ -276,7 +310,6 @@ namespace Robust.Shared.GameObjects
//TODO: This is a hack, look into WHY we can't call GridPosition before the comp is Running
if (Running)
{
RebuildMatrices();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new MoveEvent(Owner, oldPosition, Coordinates));
}
}
@@ -304,7 +337,7 @@ namespace Robust.Shared.GameObjects
_nextPosition = null;
var oldGridPos = Coordinates;
SetPosition(value);
_localPosition = value;
Dirty();
if (!DeferUpdates)
@@ -556,49 +589,22 @@ namespace Robust.Shared.GameObjects
}
/// <summary>
/// Sets another entity as the parent entity.
/// Sets another entity as the parent entity, maintaining world position.
/// </summary>
/// <param name="newParent"></param>
public virtual void AttachParent(ITransformComponent newParent)
{
//NOTE: This function must be callable from before initialize
// nothing to attach to.
// don't attach to something we're already attached to
if (ParentUid == newParent.Owner.Uid)
return;
DebugTools.Assert(newParent != this,
$"Can't parent a {nameof(ITransformComponent)} to itself.");
// That's already our parent, don't bother attaching again.
var newParentEnt = newParent.Owner;
if (newParentEnt.Uid == _parent)
{
return;
}
var oldParent = Parent;
var oldConcrete = (TransformComponent?) oldParent;
var uid = Owner.Uid;
oldConcrete?._children.Remove(uid);
var newConcrete = (TransformComponent) newParent;
newConcrete._children.Add(uid);
var oldParentOwner = oldParent?.Owner;
var entMessage = new EntParentChangedMessage(Owner, oldParentOwner);
var compMessage = new ParentChangedMessage(newParentEnt, oldParentOwner);
// offset position from world to parent
SetPosition(newParent.InvWorldMatrix.Transform(WorldPosition));
_parent = newParentEnt.Uid;
ChangeMapId(newConcrete.MapID);
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, entMessage);
Owner.SendMessage(this, compMessage);
RebuildMatrices();
Dirty();
GridID = GetGridIndex();
// offset position from world to parent, and set
Coordinates = new EntityCoordinates(newParent.Owner.Uid, newParent.InvWorldMatrix.Transform(WorldPosition));
}
internal void ChangeMapId(MapId newMapId)
@@ -713,14 +719,14 @@ namespace Robust.Shared.GameObjects
if (LocalRotation != newState.Rotation)
{
SetRotation(newState.Rotation);
_localRotation = newState.Rotation;
rebuildMatrices = true;
}
if (!_localPosition.EqualsApprox(newState.LocalPosition, 0.0001))
{
var oldPos = Coordinates;
SetPosition(newState.LocalPosition);
_localPosition = newState.LocalPosition;
var ev = new MoveEvent(Owner, oldPos, Coordinates);
EntitySystem.Get<SharedTransformSystem>().DeferMoveEvent(ev);
@@ -755,17 +761,6 @@ namespace Robust.Shared.GameObjects
}
}
protected virtual void SetPosition(Vector2 position)
{
// DebugTools.Assert(!float.IsNaN(position.X) && !float.IsNaN(position.Y));
_localPosition = position;
}
protected virtual void SetRotation(Angle rotation)
{
_localRotation = rotation;
}
public Matrix3 GetLocalMatrix()
{
return _localMatrix;

View File

@@ -99,6 +99,7 @@ namespace Robust.Shared.GameObjects
private class EventTables : IDisposable
{
private IEntityManager _entMan;
private IComponentFactory _comFac;
// eUid -> EventType -> { CompType1, ... CompTypeN }
private Dictionary<EntityUid, Dictionary<Type, HashSet<Type>>> _eventTables;
@@ -112,6 +113,7 @@ namespace Robust.Shared.GameObjects
public EventTables(IEntityManager entMan)
{
_entMan = entMan;
_comFac = entMan.ComponentManager.ComponentFactory;
_entMan.EntityAdded += OnEntityAdded;
_entMan.EntityDeleted += OnEntityDeleted;
@@ -194,18 +196,21 @@ namespace Robust.Shared.GameObjects
{
var eventTable = _eventTables[euid];
if (!_subscriptions.TryGetValue(compType, out var compSubs))
return;
foreach (var kvSub in compSubs)
foreach (var type in GetReferences(compType))
{
if(!eventTable.TryGetValue(kvSub.Key, out var subscribedComps))
{
subscribedComps = new HashSet<Type>();
eventTable.Add(kvSub.Key, subscribedComps);
}
if (!_subscriptions.TryGetValue(type, out var compSubs))
continue;
subscribedComps.Add(compType);
foreach (var kvSub in compSubs)
{
if(!eventTable.TryGetValue(kvSub.Key, out var subscribedComps))
{
subscribedComps = new HashSet<Type>();
eventTable.Add(kvSub.Key, subscribedComps);
}
subscribedComps.Add(type);
}
}
}
@@ -213,15 +218,18 @@ namespace Robust.Shared.GameObjects
{
var eventTable = _eventTables[euid];
if (!_subscriptions.TryGetValue(compType, out var compSubs))
return;
foreach (var kvSub in compSubs)
foreach (var type in GetReferences(compType))
{
if (!eventTable.TryGetValue(kvSub.Key, out var subscribedComps))
return;
if (!_subscriptions.TryGetValue(type, out var compSubs))
continue;
subscribedComps.Remove(compType);
foreach (var kvSub in compSubs)
{
if (!eventTable.TryGetValue(kvSub.Key, out var subscribedComps))
return;
subscribedComps.Remove(type);
}
}
}
@@ -241,19 +249,23 @@ namespace Robust.Shared.GameObjects
return;
var component = _entMan.ComponentManager.GetComponent(euid, compType);
handler(euid, component, args);
}
}
public void DispatchComponent(EntityUid euid, IComponent component, Type eventType, EntityEventArgs args)
{
if (!_subscriptions.TryGetValue(component.GetType(), out var compSubs))
return;
foreach (var type in GetReferences(component.GetType()))
{
if (!_subscriptions.TryGetValue(type, out var compSubs))
continue;
if (!compSubs.TryGetValue(eventType, out var handler))
return;
if (!compSubs.TryGetValue(eventType, out var handler))
continue;
handler(euid, component, args);
handler(euid, component, args);
}
}
public void ClearEntities()
@@ -281,6 +293,11 @@ namespace Robust.Shared.GameObjects
_eventTables = null!;
_subscriptions = null!;
}
private IEnumerable<Type> GetReferences(Type type)
{
return _comFac.GetRegistration(type).References;
}
}
/// <inheritdoc />

View File

@@ -142,6 +142,11 @@ namespace Robust.Shared.GameObjects
#region Entity Management
public IEntity CreateEntityUninitialized(string? prototypeName, EntityUid? euid)
{
return CreateEntity(prototypeName, euid);
}
/// <inheritdoc />
public virtual IEntity CreateEntityUninitialized(string? prototypeName)
{

View File

@@ -9,11 +9,23 @@ using Robust.Shared.Log;
using Robust.Shared.Reflection;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
#if EXCEPTION_TOLERANCE
using Robust.Shared.Exceptions;
#endif
namespace Robust.Shared.GameObjects
{
public class EntitySystemManager : IEntitySystemManager
{
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly IDynamicTypeFactoryInternal _typeFactory = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
#if EXCEPTION_TOLERANCE
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
#endif
private static readonly Histogram _tickUsageHistogram = Metrics.CreateHistogram("robust_entity_systems_update_usage",
"Amount of time spent processing each entity system", new HistogramConfiguration
{
@@ -21,12 +33,6 @@ namespace Robust.Shared.GameObjects
Buckets = Histogram.ExponentialBuckets(0.000_001, 1.5, 25)
});
#pragma warning disable 649
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly IDynamicTypeFactoryInternal _typeFactory = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
[ViewVariables]
private readonly List<Type> _extraLoadedTypes = new();
@@ -268,7 +274,7 @@ namespace Robust.Shared.GameObjects
}
catch (Exception e)
{
Logger.ErrorS("entsys", e.ToString());
_runtimeLog.LogException(e, "entsys");
}
#endif
@@ -293,7 +299,7 @@ namespace Robust.Shared.GameObjects
}
catch (Exception e)
{
Logger.ErrorS("entsys", e.ToString());
_runtimeLog.LogException(e, "entsys");
}
#endif
}

View File

@@ -252,5 +252,7 @@ namespace Robust.Shared.GameObjects
/// Culls all components from the collection that are marked as deleted. This needs to be called often.
/// </summary>
void CullRemovedComponents();
IComponentFactory ComponentFactory { get; }
}
}

View File

@@ -37,6 +37,8 @@ namespace Robust.Shared.GameObjects
event EventHandler<EntityUid>? EntityStarted;
event EventHandler<EntityUid>? EntityDeleted;
IEntity CreateEntityUninitialized(string? prototypeName, EntityUid? euid);
IEntity CreateEntityUninitialized(string? prototypeName);
IEntity CreateEntityUninitialized(string? prototypeName, EntityCoordinates coordinates);

View File

@@ -12,13 +12,23 @@ namespace Robust.Shared.GameObjects
void MapInit();
}
/// <summary>
/// Raised directed on an entity when the map is initialized.
/// </summary>
public class MapInitEvent : EntityEventArgs
{
}
public static class MapInitExt
{
private static readonly MapInitEvent MapInit = new MapInitEvent();
public static void RunMapInit(this IEntity entity)
{
DebugTools.Assert(entity.LifeStage == EntityLifeStage.Initialized);
entity.LifeStage = EntityLifeStage.MapInitialized;
entity.EntityManager.EventBus.RaiseLocalEvent(entity.Uid, MapInit, false);
foreach (var init in entity.GetAllComponents<IMapInit>())
{
init.MapInit();

View File

@@ -1,33 +1,61 @@
using System.Linq;
using Robust.Shared.Physics;
namespace Robust.Shared.GameObjects
{
public class CollisionWakeSystem : EntitySystem
public sealed class CollisionWakeSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PhysicsWakeMessage>(HandleWake);
SubscribeLocalEvent<PhysicsSleepMessage>(HandleSleep);
SubscribeLocalEvent<CollisionWakeComponent, EntityInitializedMessage>(HandleInitialize);
SubscribeLocalEvent<CollisionWakeComponent, PhysicsWakeMessage>(HandleWake);
SubscribeLocalEvent<CollisionWakeComponent, PhysicsSleepMessage>(HandleSleep);
SubscribeLocalEvent<CollisionWakeComponent, CollisionWakeStateMessage>(HandleCollisionWakeState);
SubscribeLocalEvent<CollisionWakeComponent, JointAddedEvent>(HandleJointAdd);
SubscribeLocalEvent<CollisionWakeComponent, JointRemovedEvent>(HandleJointRemove);
}
private void HandleWake(PhysicsWakeMessage message)
private void HandleInitialize(EntityUid uid, CollisionWakeComponent component, EntityInitializedMessage args)
{
if (!message.Body.Owner.TryGetComponent<CollisionWakeComponent>(out var comp) || !comp.Enabled) return;
message.Body.CanCollide = true;
component.RaiseStateChange();
}
private void HandleSleep(PhysicsSleepMessage message)
private void HandleJointRemove(EntityUid uid, CollisionWakeComponent component, JointRemovedEvent args)
{
if (!message.Body.Owner.TryGetComponent<CollisionWakeComponent>(out var comp) || !comp.Enabled) return;
message.Body.CanCollide = false;
if (component.Owner.TryGetComponent(out PhysicsComponent? body) && body.Joints.Any()) return;
// Force an update
component.RaiseStateChange();
}
private void HandleJointAdd(EntityUid uid, CollisionWakeComponent component, JointAddedEvent args)
{
if (!ComponentManager.TryGetComponent(uid, out PhysicsComponent body)) return;
body.CanCollide = true;
}
private void HandleWake(EntityUid uid, CollisionWakeComponent component, PhysicsWakeMessage args)
{
if (!component.Enabled) return;
args.Body.CanCollide = true;
}
private void HandleSleep(EntityUid uid, CollisionWakeComponent component, PhysicsSleepMessage args)
{
if (!component.Enabled) return;
args.Body.CanCollide = false;
}
private void HandleCollisionWakeState(EntityUid uid, CollisionWakeComponent component, CollisionWakeStateMessage args)
{
if(ComponentManager.TryGetComponent<IPhysBody>(uid, out var body))
body.CanCollide = !component.Enabled || body.Awake;
if (!ComponentManager.TryGetComponent<PhysicsComponent>(uid, out var body)) return;
body.CanCollide = !component.Enabled || body.Awake || body.Joints.Any();
}
}

View File

@@ -278,7 +278,7 @@ namespace Robust.Shared.GameObjects
{
if (entity.TryGetComponent<IPhysBody>(out var component))
{
return GetEntitiesIntersecting(entity.Transform.MapID, component.GetWorldAABB(_mapManager), approximate);
return GetEntitiesIntersecting(entity.Transform.MapID, component.GetWorldAABB(), approximate);
}
return GetEntitiesIntersecting(entity.Transform.Coordinates, approximate);
@@ -295,7 +295,7 @@ namespace Robust.Shared.GameObjects
{
if (entity.TryGetComponent(out IPhysBody? component))
{
if (component.GetWorldAABB(_mapManager).Contains(mapPosition))
if (component.GetWorldAABB().Contains(mapPosition))
return true;
}
else
@@ -341,7 +341,7 @@ namespace Robust.Shared.GameObjects
{
if (entity.TryGetComponent<IPhysBody>(out var component))
{
return GetEntitiesInRange(entity.Transform.MapID, component.GetWorldAABB(_mapManager), range, approximate);
return GetEntitiesInRange(entity.Transform.MapID, component.GetWorldAABB(), range, approximate);
}
return GetEntitiesInRange(entity.Transform.Coordinates, range, approximate);
@@ -476,10 +476,11 @@ namespace Robust.Shared.GameObjects
if (ent.Deleted)
return new Box2(0, 0, 0, 0);
if (ent.TryGetComponent(out IPhysBody? collider))
return collider.GetWorldAABB(_mapManager);
var pos = ent.Transform.WorldPosition;
if (ent.TryGetComponent(out IPhysBody? collider))
return collider.GetWorldAABB(pos);
return new Box2(pos, pos);
}

View File

@@ -0,0 +1,37 @@
#if DEBUG
using System;
using System.Collections.Generic;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
namespace Robust.Shared.GameObjects
{
[Serializable, NetSerializable]
public sealed class RequestGridTileLookupMessage : EntityEventArgs
{
public GridId GridId;
public Vector2i Indices;
public RequestGridTileLookupMessage(GridId gridId, Vector2i indices)
{
GridId = gridId;
Indices = indices;
}
}
[Serializable, NetSerializable]
public sealed class SendGridTileLookupMessage : EntityEventArgs
{
public GridId GridId;
public Vector2i Indices;
public List<EntityUid> Entities { get; }
public SendGridTileLookupMessage(GridId gridId, Vector2i indices, List<EntityUid> entities)
{
Entities = entities;
}
}
}
#endif

View File

@@ -33,6 +33,8 @@ namespace Robust.Shared.Input
/// </summary>
/// <param name="function">Function to remove.</param>
void RemoveFunction(BoundKeyFunction function);
string Name { get; }
}
/// <inheritdoc />
@@ -40,20 +42,25 @@ namespace Robust.Shared.Input
{
private readonly List<BoundKeyFunction> _commands = new();
private readonly IInputCmdContext? _parent;
public string Name { get; }
/// <summary>
/// Creates a new instance of <see cref="InputCmdContext"/>.
/// </summary>
/// <param name="parent">Parent context.</param>
internal InputCmdContext(IInputCmdContext? parent)
internal InputCmdContext(IInputCmdContext? parent, string name)
{
_parent = parent;
Name = name;
}
/// <summary>
/// Creates a instance of <see cref="InputCmdContext"/> with no parent.
/// </summary>
internal InputCmdContext() { }
internal InputCmdContext(string name)
{
Name = name;
}
/// <inheritdoc />
public void AddFunction(BoundKeyFunction function)

View File

@@ -121,7 +121,7 @@ namespace Robust.Shared.Input
{
var icc = _deferredContextSwitch;
_deferredContextSwitch = null;
_setActiveContextImmediately(icc);
_setActiveContextImmediately( icc);
}
}
}
@@ -132,7 +132,7 @@ namespace Robust.Shared.Input
/// </summary>
public InputContextContainer()
{
_contexts.Add(DefaultContextName, new InputCmdContext());
_contexts.Add(DefaultContextName, new InputCmdContext(DefaultContextName));
SetActiveContext(DefaultContextName);
}
@@ -151,7 +151,7 @@ namespace Robust.Shared.Input
if (_contexts.ContainsKey(uniqueName))
throw new ArgumentException($"Context with name {uniqueName} already exists.", nameof(uniqueName));
var newContext = new InputCmdContext(parentContext);
var newContext = new InputCmdContext(parentContext, uniqueName);
_contexts.Add(uniqueName, newContext);
return newContext;
}
@@ -168,7 +168,7 @@ namespace Robust.Shared.Input
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var newContext = new InputCmdContext(parent);
var newContext = new InputCmdContext(parent, uniqueName);
_contexts.Add(uniqueName, newContext);
return newContext;
}

View File

@@ -104,6 +104,23 @@ namespace Robust.Shared.IoC
_container.Value!.Register<TInterface, TImplementation>(overwrite);
}
/// <summary>
/// Register an implementation, to make it accessible to <see cref="Resolve{T}"/>
/// </summary>
/// <typeparam name="T">The type that will be resolvable and implementation.</typeparam>
/// <param name="overwrite">
/// If true, do not throw an <see cref="InvalidOperationException"/> if an interface is already registered,
/// replace the current implementation instead.
/// </param>
/// <exception cref="InvalidOperationException">
/// Thrown if <paramref name="overwrite"/> is false and <typeparamref name="T"/> has been registered before,
/// or if an already instantiated interface (by <see cref="BuildGraph"/>) is attempting to be overwritten.
/// </exception>
public static void Register<T>(bool overwrite = false) where T : class
{
Register<T, T>(overwrite);
}
/// <summary>
/// Registers an interface to an implementation, to make it accessible to <see cref="Resolve{T}"/>
/// <see cref="BuildGraph"/> MUST be called after this method to make the new interface available.

View File

@@ -1,9 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Fluent.Net;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Localization;
using Robust.Shared.Utility;
namespace Robust.Shared.Localization
{
@@ -11,23 +14,49 @@ namespace Robust.Shared.Localization
{
private void AddBuiltinFunctions(MessageContext context)
{
// Grammatical gender
// Grammatical gender / pronouns
AddCtxFunction(context, "GENDER", FuncGender);
AddCtxFunction(context, "SUBJECT", FuncSubject);
AddCtxFunction(context, "OBJECT", FuncObject);
AddCtxFunction(context, "POSS-ADJ", FuncPossAdj);
AddCtxFunction(context, "POSS-PRONOUN", FuncPossPronoun);
AddCtxFunction(context, "REFLEXIVE", FuncReflexive);
// Conjugation
AddCtxFunction(context, "CONJUGATE-BE", FuncConjugateBe);
AddCtxFunction(context, "CONJUGATE-HAVE", FuncConjugateHave);
// Proper nouns
AddCtxFunction(context, "PROPER", FuncProper);
// Misc Attribs
AddCtxFunction(context, "ATTRIB", args => FuncAttrib(context, args));
AddCtxFunction(context, "THE", FuncThe);
// Misc
AddCtxFunction(context, "ATTRIB", args => FuncAttrib(context, args));
AddCtxFunction(context, "CAPITALIZE", FuncCapitalize);
}
/// <summary>
/// Returns the name of the entity passed in, prepended with "the" if it is not a proper noun.
/// </summary>
private ILocValue FuncThe(LocArgs args)
{
return new LocValueString(GetString("zzzz-the", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the string passed in, with the first letter capitalized.
/// </summary>
private ILocValue FuncCapitalize(LocArgs args)
{
var input = args.Args[0].Format(new LocContext());
if (!String.IsNullOrEmpty(input))
return new LocValueString(input.First().ToString().ToUpper() + input.Substring(1));
else return new LocValueString("");
}
/// <summary>
/// Returns the gender of the entity passed in; either Male, Female, Neuter or Epicene.
/// </summary>
private ILocValue FuncGender(LocArgs args)
{
if (args.Args.Count < 1) return new LocValueString(nameof(Gender.Neuter));
@@ -51,6 +80,62 @@ namespace Robust.Shared.Localization
return new LocValueString(nameof(Gender.Neuter));
}
/// <summary>
/// Returns the respective subject pronoun (he, she, they, it) for the entity's gender.
/// </summary>
private ILocValue FuncSubject(LocArgs args)
{
return new LocValueString(GetString("zzzz-subject-pronoun", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective object pronoun (him, her, them, it) for the entity's gender.
/// </summary>
private ILocValue FuncObject(LocArgs args)
{
return new LocValueString(GetString("zzzz-object-pronoun", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective possessive adjective (his, her, their, its) for the entity's gender.
/// </summary>
private ILocValue FuncPossAdj(LocArgs args)
{
return new LocValueString(GetString("zzzz-possessive-adjective", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective possessive pronoun (his, hers, theirs, its) for the entity's gender.
/// </summary>
private ILocValue FuncPossPronoun(LocArgs args)
{
return new LocValueString(GetString("zzzz-possessive-pronoun", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective reflexive pronoun (himself, herself, themselves, itself) for the entity's gender.
/// </summary>
private ILocValue FuncReflexive(LocArgs args)
{
return new LocValueString(GetString("zzzz-reflexive-pronoun", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective conjugated form of "to be" (is for male/female/neuter, are for epicene) for the entity's gender.
/// </summary>
private ILocValue FuncConjugateBe(LocArgs args)
{
return new LocValueString(GetString("zzzz-conjugate-be", ("ent", args.Args[0])));
}
/// <summary>
/// Returns the respective conjugated form of "to have" (has for male/female/neuter, have for epicene) for the entity's gender.
/// </summary>
private ILocValue FuncConjugateHave(LocArgs args)
{
return new LocValueString(GetString("zzzz-conjugate-have", ("ent", args.Args[0])));
}
private ILocValue FuncAttrib(MessageContext context, LocArgs args)
{
if (args.Args.Count < 2) return new LocValueString("other");
@@ -69,6 +154,9 @@ namespace Robust.Shared.Localization
return new LocValueString("other");
}
/// <summary>
/// Returns whether the passed in entity's name is proper or not.
/// </summary>
private ILocValue FuncProper(LocArgs args)
{
if (args.Args.Count < 1) return new LocValueString("false");

View File

@@ -220,6 +220,11 @@ namespace Robust.Shared.Map
public MapId CreateMap(MapId? mapID = null)
{
return CreateMap(mapID, null);
}
public MapId CreateMap(MapId? mapID, EntityUid? entityUid)
{
#if DEBUG
DebugTools.Assert(_dbgGuardRunning);
#endif
@@ -269,7 +274,7 @@ namespace Robust.Shared.Map
}
else
{
var newEnt = (Entity) _entityManager.CreateEntityUninitialized(null, EntityCoordinates.Invalid);
var newEnt = (Entity) _entityManager.CreateEntityUninitialized(null, entityUid);
_mapEntities.Add(actualID, newEnt.Uid);
var mapComp = newEnt.AddComponent<MapComponent>();
@@ -400,10 +405,15 @@ namespace Robust.Shared.Map
public IMapGrid CreateGrid(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, true);
return CreateGridImpl(currentMapID, gridID, chunkSize, true, null);
}
private IMapGridInternal CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, bool createEntity)
public IMapGrid CreateGrid(MapId currentMapID, GridId gridID, ushort chunkSize, EntityUid euid)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, true, euid);
}
private IMapGridInternal CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, bool createEntity, EntityUid? euid)
{
#if DEBUG
DebugTools.Assert(_dbgGuardRunning);
@@ -455,20 +465,23 @@ namespace Robust.Shared.Map
}
else
{
var newEnt =
(Entity) _entityManager.CreateEntityUninitialized(null,
new MapCoordinates(Vector2.Zero, currentMapID));
grid.GridEntityId = newEnt.Uid;
var gridEnt = (Entity) EntityManager.CreateEntityUninitialized(null, euid);
grid.GridEntityId = gridEnt.Uid;
Logger.DebugS("map", $"Binding grid {actualID} to entity {grid.GridEntityId}");
var gridComp = newEnt.AddComponent<MapGridComponent>();
var gridComp = gridEnt.AddComponent<MapGridComponent>();
gridComp.GridIndex = grid.Index;
//TODO: This is a hack to get TransformComponent.MapId working before entity states
//are applied. After they are applied the parent may be different, but the MapId will
//be the same. This causes TransformComponent.ParentUid of a grid to be unsafe to
//use in transform states anytime before the state parent is properly set.
gridEnt.Transform.AttachParent(GetMapEntity(currentMapID));
newEnt.Transform.AttachParent(_entityManager.GetEntity(_mapEntities[currentMapID]));
newEnt.InitializeComponents();
newEnt.StartAllComponents();
gridEnt.InitializeComponents();
gridEnt.StartAllComponents();
}
}
else
@@ -482,7 +495,7 @@ namespace Robust.Shared.Map
public IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, false);
return CreateGridImpl(currentMapID, gridID, chunkSize, false, null);
}
public IMapGrid GetGrid(GridId gridID)

View File

@@ -128,10 +128,25 @@ namespace Robust.Shared.Network
/// The side of the network this message is accepted on.
/// If we are not on the side specified, the receive callback will not be registered even if provided.
/// </param>
[Obsolete("Use the method without a name argument instead")]
void RegisterNetMessage<T>(string name, ProcessMessage<T>? rxCallback = null,
NetMessageAccept accept = NetMessageAccept.Both)
where T : NetMessage;
/// <summary>
/// Registers a NetMessage to be sent or received.
/// </summary>
/// <typeparam name="T">Type to register.</typeparam>
/// <param name="name">String ID of the message.</param>
/// <param name="rxCallback">Callback function to process the received message.</param>
/// <param name="accept">
/// The side of the network this message is accepted on.
/// If we are not on the side specified, the receive callback will not be registered even if provided.
/// </param>
void RegisterNetMessage<T>(ProcessMessage<T>? rxCallback = null,
NetMessageAccept accept = NetMessageAccept.Both)
where T : NetMessage, new();
/// <summary>
/// Creates a new NetMessage to be sent.
/// </summary>

View File

@@ -6,9 +6,9 @@ namespace Robust.Shared.Network.Messages.Handshake
{
internal sealed class MsgEncryptionRequest : NetMessage
{
public MsgEncryptionRequest() : base("", MsgGroups.Core)
{
}
public override string MsgName => string.Empty;
public override MsgGroups MsgGroup => MsgGroups.Core;
public byte[] VerifyToken;
public byte[] PublicKey;

View File

@@ -7,9 +7,9 @@ namespace Robust.Shared.Network.Messages.Handshake
{
internal sealed class MsgEncryptionResponse : NetMessage
{
public MsgEncryptionResponse() : base("", MsgGroups.Core)
{
}
public override string MsgName => string.Empty;
public override MsgGroups MsgGroup => MsgGroups.Core;
public Guid UserId;
public byte[] SharedSecret;

View File

@@ -10,9 +10,9 @@ namespace Robust.Shared.Network.Messages.Handshake
// **NOTE**: This is a special message sent during the client<->server handshake.
// It doesn't actually get sent normally and as such doesn't have the "normal" boilerplate.
// It's basically just a sane way to encapsulate the message write/read logic.
public MsgLoginStart() : base("", MsgGroups.Core)
{
}
public override string MsgName => string.Empty;
public override MsgGroups MsgGroup => MsgGroups.Core;
public string UserName;
public ImmutableArray<byte> HWId;

View File

@@ -7,10 +7,9 @@ namespace Robust.Shared.Network.Messages.Handshake
internal sealed class MsgLoginSuccess : NetMessage
{
// Same deal as MsgLogin, helper for NetManager only.
public override string MsgName => string.Empty;
public MsgLoginSuccess() : base("", MsgGroups.Core)
{
}
public override MsgGroups MsgGroup => MsgGroups.Core;
public NetUserData UserData;
public LoginType Type;

View File

@@ -6,11 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgConCmd : NetMessage
{
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Command;
public static readonly string NAME = nameof(MsgConCmd);
public MsgConCmd(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.Core;
public string Text { get; set; }

View File

@@ -6,11 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgConCmdAck : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.String;
public static readonly string NAME = nameof(MsgConCmdAck);
public MsgConCmdAck(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.String;
public string Text { get; set; }
public bool Error { get; set; }

View File

@@ -7,11 +7,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgConCmdReg : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.String;
public static readonly string NAME = nameof(MsgConCmdReg);
public MsgConCmdReg(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.String;
public Command[] Commands { get; set; }

View File

@@ -13,11 +13,7 @@ namespace Robust.Shared.Network.Messages
private const int MaxNameSize = 4 * 32; // UTF8 Max char size is 4 bytes, 32 chars.
private const int MaxStringValSize = 4 * 256; // UTF8 Max char size is 4 bytes, 256 chars.
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Command;
public static readonly string NAME = nameof(MsgConVars);
public MsgConVars(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.String;
public GameTick Tick;
public List<(string name, object value)> NetworkedVars = null!;

View File

@@ -1,10 +1,10 @@
using System;
using Lidgren.Network;
using Robust.Shared.GameObjects;
using System.IO;
using Robust.Shared.IoC;
using System.Collections.Generic;
using System.IO;
using Lidgren.Network;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
@@ -14,11 +14,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgEntity : NetMessage
{
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.EntityEvent;
public static readonly string NAME = nameof(MsgEntity);
public MsgEntity(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
public EntityMessageType Type { get; set; }

View File

@@ -4,7 +4,6 @@ using Robust.Shared.Serialization;
namespace Robust.Shared.Network.Messages
{
/// <summary>
/// The client part of the string-exchange handshake, sent after the
/// client receives the mapping hash and after the client receives a
@@ -21,11 +20,7 @@ namespace Robust.Shared.Network.Messages
[UsedImplicitly]
internal class MsgMapStrClientHandshake : NetMessage
{
public MsgMapStrClientHandshake(INetChannel ch)
: base(nameof(MsgMapStrClientHandshake), MsgGroups.Core)
{
}
public override MsgGroups MsgGroup => MsgGroups.Core;
/// <value>
/// <c>true</c> if the client needs a new copy of the mapping,
@@ -38,7 +33,5 @@ namespace Robust.Shared.Network.Messages
public override void WriteToBuffer(NetOutgoingMessage buffer)
=> buffer.Write(NeedsStrings);
}
}

View File

@@ -5,7 +5,6 @@ using Robust.Shared.Serialization;
namespace Robust.Shared.Network.Messages
{
/// <summary>
/// The server part of the string-exchange handshake. Sent as the
/// first message in the handshake. Tells the client the hash of
@@ -16,11 +15,7 @@ namespace Robust.Shared.Network.Messages
[UsedImplicitly]
internal class MsgMapStrServerHandshake : NetMessage
{
public MsgMapStrServerHandshake(INetChannel ch)
: base(nameof(MsgMapStrServerHandshake), MsgGroups.Core)
{
}
public override MsgGroups MsgGroup => MsgGroups.Core;
/// <value>
/// The hash of the current string mapping held by the server.
@@ -48,7 +43,5 @@ namespace Robust.Shared.Network.Messages
buffer.WriteVariableInt32(Hash.Length);
buffer.Write(Hash);
}
}
}

View File

@@ -15,11 +15,7 @@ namespace Robust.Shared.Network.Messages
[UsedImplicitly]
internal class MsgMapStrStrings : NetMessage
{
public MsgMapStrStrings(INetChannel ch)
: base(nameof(MsgMapStrStrings), MsgGroups.Core)
{
}
public override MsgGroups MsgGroup => MsgGroups.Core;
/// <value>
/// The raw bytes of the string mapping held by the server.
@@ -48,7 +44,5 @@ namespace Robust.Shared.Network.Messages
throw new InvalidOperationException("Not all of the bytes were written to the message.");
}
}
}
}

View File

@@ -11,11 +11,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgPlacement : NetMessage
{
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Command;
public static readonly string NAME = nameof(MsgPlacement);
public MsgPlacement(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public PlacementManagerMessage PlaceType { get; set; }
public string Align { get; set; }

View File

@@ -9,11 +9,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgPlayerList : NetMessage
{
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Core;
public static readonly string NAME = nameof(MsgPlayerList);
public MsgPlayerList(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.Core;
public byte PlyCount { get; set; }
public List<PlayerState> Plyrs { get; set; }

View File

@@ -6,11 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgPlayerListReq : NetMessage
{
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Core;
public static readonly string NAME = nameof(MsgPlayerListReq);
public MsgPlayerListReq(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override MsgGroups MsgGroup => MsgGroups.Core;
public override void ReadFromBuffer(NetIncomingMessage buffer)
{

View File

@@ -7,16 +7,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgRay : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgRay);
public MsgRay(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public Vector2 RayOrigin { get; set; }
public Vector2 RayHit { get; set; }

View File

@@ -5,16 +5,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgReloadPrototypes : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgReloadPrototypes);
public MsgReloadPrototypes(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public ResourcePath[] Paths = default!;

View File

@@ -6,16 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgScriptEval : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgScriptEval);
public MsgScriptEval(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public int ScriptSession { get; set; }
public string Code { get; set; }

View File

@@ -10,16 +10,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgScriptResponse : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgScriptResponse);
public MsgScriptResponse(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public int ScriptSession { get; set; }
public bool WasComplete { get; set; }

View File

@@ -6,16 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgScriptStart : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgScriptStart);
public MsgScriptStart(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public int ScriptSession { get; set; }

View File

@@ -6,16 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgScriptStartAck : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgScriptStartAck);
public MsgScriptStartAck(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public bool WasAccepted { get; set; }
public int ScriptSession { get; set; }

View File

@@ -6,16 +6,7 @@ namespace Robust.Shared.Network.Messages
{
public class MsgScriptStop : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgScriptStop);
public MsgScriptStop(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Command;
public int ScriptSession { get; set; }

View File

@@ -1,8 +1,8 @@
using System;
using System.IO;
using Lidgren.Network;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using System.IO;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
@@ -17,16 +17,7 @@ namespace Robust.Shared.Network.Messages
// (due to being in many parts).
public const int ReliableThreshold = 1300;
#region REQUIRED
public static readonly MsgGroups GROUP = MsgGroups.Entity;
public static readonly string NAME = nameof(MsgState);
public MsgState(INetChannel channel) : base(NAME, GROUP)
{
}
#endregion
public override MsgGroups MsgGroup => MsgGroups.Entity;
public GameState State;

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