Merge remote-tracking branch 'upstream/master'
@@ -3,7 +3,7 @@ namespace Content.Client.SurveillanceCamera;
|
||||
[RegisterComponent]
|
||||
public sealed partial class ActiveSurveillanceCameraMonitorVisualsComponent : Component
|
||||
{
|
||||
public float TimeLeft = 10f;
|
||||
public float TimeLeft = 0.5f;
|
||||
|
||||
public Action? OnFinish;
|
||||
}
|
||||
|
||||
@@ -14,18 +14,30 @@ public sealed class SurveillanceCameraMonitorBoundUserInterface : BoundUserInter
|
||||
|
||||
[ViewVariables]
|
||||
private EntityUid? _currentCamera;
|
||||
private readonly IEntityManager _entManager;
|
||||
|
||||
public SurveillanceCameraMonitorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
_eyeLerpingSystem = EntMan.System<EyeLerpingSystem>();
|
||||
_surveillanceCameraMonitorSystem = EntMan.System<SurveillanceCameraMonitorSystem>();
|
||||
IoCManager.InjectDependencies(this);
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new SurveillanceCameraMonitorWindow();
|
||||
// Sunrise-start
|
||||
EntityUid? gridUid = null;
|
||||
|
||||
if (_entManager.TryGetComponent<TransformComponent>(Owner, out var xform))
|
||||
{
|
||||
gridUid = xform.GridUid;
|
||||
}
|
||||
|
||||
_window = new SurveillanceCameraMonitorWindow(gridUid);
|
||||
// Sunrise-end
|
||||
|
||||
if (State != null)
|
||||
{
|
||||
@@ -35,7 +47,6 @@ public sealed class SurveillanceCameraMonitorBoundUserInterface : BoundUserInter
|
||||
_window.OpenCentered();
|
||||
|
||||
_window.CameraSelected += OnCameraSelected;
|
||||
_window.SubnetOpened += OnSubnetRequest;
|
||||
_window.CameraRefresh += OnCameraRefresh;
|
||||
_window.SubnetRefresh += OnSubnetRefresh;
|
||||
_window.OnClose += Close;
|
||||
@@ -43,14 +54,9 @@ public sealed class SurveillanceCameraMonitorBoundUserInterface : BoundUserInter
|
||||
_window.CameraDisconnect += OnCameraDisconnect;
|
||||
}
|
||||
|
||||
private void OnCameraSelected(string address)
|
||||
private void OnCameraSelected(NetEntity camera)
|
||||
{
|
||||
SendMessage(new SurveillanceCameraMonitorSwitchMessage(address));
|
||||
}
|
||||
|
||||
private void OnSubnetRequest(string subnet)
|
||||
{
|
||||
SendMessage(new SurveillanceCameraMonitorSubnetRequestMessage(subnet));
|
||||
SendMessage(new SurveillanceCameraMonitorSwitchMessage(camera));
|
||||
}
|
||||
|
||||
private void OnCameraSwitchTimer()
|
||||
@@ -82,9 +88,11 @@ public sealed class SurveillanceCameraMonitorBoundUserInterface : BoundUserInter
|
||||
|
||||
var active = EntMan.GetEntity(cast.ActiveCamera);
|
||||
|
||||
_entManager.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||
|
||||
if (active == null)
|
||||
{
|
||||
_window.UpdateState(null, cast.Subnets, cast.ActiveAddress, cast.ActiveSubnet, cast.Cameras);
|
||||
_window.UpdateState(null, cast.ActiveAddress, cast.ActiveCamera);
|
||||
|
||||
if (_currentCamera != null)
|
||||
{
|
||||
@@ -109,9 +117,11 @@ public sealed class SurveillanceCameraMonitorBoundUserInterface : BoundUserInter
|
||||
|
||||
if (EntMan.TryGetComponent<EyeComponent>(active, out var eye))
|
||||
{
|
||||
_window.UpdateState(eye.Eye, cast.Subnets, cast.ActiveAddress, cast.ActiveSubnet, cast.Cameras);
|
||||
_window.UpdateState(eye.Eye, cast.ActiveAddress, cast.ActiveCamera);
|
||||
}
|
||||
}
|
||||
|
||||
_window.ShowCameras(cast.Cameras, xform?.Coordinates);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:viewport="clr-namespace:Content.Client.Viewport"
|
||||
Title="{Loc 'surveillance-camera-monitor-ui-window'}">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<BoxContainer Orientation="Vertical" MinWidth="350" VerticalExpand="True">
|
||||
<!-- lazy -->
|
||||
<OptionButton Name="SubnetSelector" />
|
||||
<Button Name="SubnetRefreshButton" Text="{Loc 'surveillance-camera-monitor-ui-refresh-subnets'}" />
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<ItemList Name="SubnetList" />
|
||||
</ScrollContainer>
|
||||
<Button Name="CameraRefreshButton" Text="{Loc 'surveillance-camera-monitor-ui-refresh-cameras'}" />
|
||||
<Button Name="CameraDisconnectButton" Text="{Loc 'surveillance-camera-monitor-ui-disconnect'}" />
|
||||
<Label Name="CameraStatus" />
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:viewport="clr-namespace:Content.Client.Viewport"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:ui="clr-namespace:Content.Client.SurveillanceCamera.UI"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Title="{Loc 'surveillance-camera-monitor-ui-window'}"
|
||||
Resizable="False"
|
||||
MinSize="1300 750">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
|
||||
<ui:SurveillanceCameraNavMapControl Name="NavMap" HorizontalExpand="True" VerticalExpand="True" MinSize="600 700" VerticalAlignment="Top"/>
|
||||
<customControls:VSeparator/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Control VerticalExpand="True" HorizontalExpand="True" Margin="5 5 5 5" Name="CameraViewBox">
|
||||
<viewport:ScalingViewport Name="CameraView"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="700 700"
|
||||
MouseFilter="Ignore" />
|
||||
<TextureRect VerticalExpand="True" HorizontalExpand="True" MinSize="700 700" Name="CameraViewBackground" />
|
||||
</Control>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Button Name="SubnetRefreshButton" Text="{Loc 'surveillance-camera-monitor-ui-refresh-subnets'}" />
|
||||
<Button Name="CameraRefreshButton" Text="{Loc 'surveillance-camera-monitor-ui-refresh-cameras'}" />
|
||||
<Button Name="CameraDisconnectButton" Text="{Loc 'surveillance-camera-monitor-ui-disconnect'}" />
|
||||
<Label Name="CameraStatus" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="LowDivider" />
|
||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc 'surveillance-camera-monitor-ui-flavor-left'}" StyleClasses="WindowFooterText" />
|
||||
<Label Text="{Loc 'surveillance-camera-monitor-ui-flavor-right'}" StyleClasses="WindowFooterText"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<Control VerticalExpand="True" HorizontalExpand="True" Margin="5 5 5 5" Name="CameraViewBox">
|
||||
<viewport:ScalingViewport Name="CameraView"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="500 500"
|
||||
MouseFilter="Ignore" />
|
||||
<TextureRect VerticalExpand="True" HorizontalExpand="True" MinSize="500 500" Name="CameraViewBackground" />
|
||||
</Control>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
</controls:FancyWindow>
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Pinpointer.UI;
|
||||
using Content.Client.Resources;
|
||||
using Content.Client.Viewport;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.SurveillanceCamera;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.SurveillanceCamera.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
||||
public sealed partial class SurveillanceCameraMonitorWindow : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
private readonly IPrototypeManager _prototypeManager;
|
||||
private readonly IEntityManager _entManager;
|
||||
|
||||
public event Action<string>? CameraSelected;
|
||||
public event Action<string>? SubnetOpened;
|
||||
public event Action<NetEntity>? CameraSelected;
|
||||
public event Action? CameraRefresh;
|
||||
public event Action? SubnetRefresh;
|
||||
public event Action? CameraSwitchTimer;
|
||||
@@ -30,110 +31,96 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
||||
private string _currentAddress = string.Empty;
|
||||
private bool _isSwitching;
|
||||
private readonly FixedEye _defaultEye = new();
|
||||
private readonly Dictionary<string, int> _subnetMap = new();
|
||||
private Dictionary<NetEntity, CameraData> _cameras = new();
|
||||
private Texture? _blipTexture;
|
||||
private NetEntity? _trackedEntity;
|
||||
|
||||
private string? SelectedSubnet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SubnetSelector.ItemCount == 0
|
||||
|| SubnetSelector.SelectedMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) SubnetSelector.SelectedMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
public SurveillanceCameraMonitorWindow()
|
||||
public SurveillanceCameraMonitorWindow(EntityUid? mapUid)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var spriteSystem = _entManager.System<SpriteSystem>();
|
||||
|
||||
// This could be done better. I don't want to deal with stylesheets at the moment.
|
||||
var texture = _resourceCache.GetTexture("/Textures/Interface/Nano/square_black.png");
|
||||
var texture = resourceCache.GetTexture("/Textures/Interface/Nano/square_black.png");
|
||||
var shader = _prototypeManager.Index<ShaderPrototype>("CameraStatic").Instance().Duplicate();
|
||||
|
||||
_blipTexture = spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
|
||||
|
||||
CameraView.ViewportSize = new Vector2i(500, 500);
|
||||
CameraView.Eye = _defaultEye; // sure
|
||||
CameraViewBackground.Stretch = TextureRect.StretchMode.Scale;
|
||||
CameraViewBackground.Texture = texture;
|
||||
CameraViewBackground.ShaderOverride = shader;
|
||||
|
||||
SubnetList.OnItemSelected += OnSubnetListSelect;
|
||||
|
||||
SubnetSelector.OnItemSelected += args =>
|
||||
{
|
||||
// piss
|
||||
SubnetOpened!((string) args.Button.GetItemMetadata(args.Id)!);
|
||||
};
|
||||
SubnetRefreshButton.OnPressed += _ => SubnetRefresh!();
|
||||
CameraRefreshButton.OnPressed += _ => CameraRefresh!();
|
||||
CameraDisconnectButton.OnPressed += _ => CameraDisconnect!();
|
||||
|
||||
NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
|
||||
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (_entManager.TryGetComponent<TransformComponent>(mapUid, out var xform))
|
||||
NavMap.MapUid = xform.GridUid;
|
||||
else
|
||||
NavMap.Visible = false;
|
||||
}
|
||||
|
||||
// Sunrise-start
|
||||
private void SetTrackedEntityFromNavMap(NetEntity? netEntity)
|
||||
{
|
||||
NavMap.Focus = _trackedEntity;
|
||||
|
||||
if (netEntity != null)
|
||||
{
|
||||
CameraSelected!(netEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowCameras(Dictionary<NetEntity, CameraData> cameras, EntityCoordinates? monitorCoords)
|
||||
{
|
||||
ClearAllCamerasPoint();
|
||||
|
||||
_cameras = cameras;
|
||||
|
||||
foreach (var camera in cameras)
|
||||
{
|
||||
NavMap.LocalizedNames.TryAdd(camera.Key, camera.Value.Name);
|
||||
|
||||
var coordinates = _entManager.GetCoordinates(camera.Value.Coordinates);
|
||||
|
||||
if (NavMap.Visible && _blipTexture != null)
|
||||
{
|
||||
NavMap.TrackedEntities.TryAdd(camera.Key,
|
||||
new NavMapBlip(coordinates,
|
||||
_blipTexture,
|
||||
camera.Key == _trackedEntity ? Color.LimeGreen : camera.Value.SubnetColor,
|
||||
camera.Key == _trackedEntity));
|
||||
|
||||
NavMap.Focus = _trackedEntity;
|
||||
}
|
||||
}
|
||||
|
||||
// Show monitor point
|
||||
if (monitorCoords != null)
|
||||
NavMap.TrackedCoordinates.Add(monitorCoords.Value, (true, StyleNano.PointMagenta));
|
||||
}
|
||||
// Sunrise-end
|
||||
|
||||
|
||||
// The UI class should get the eye from the entity, and then
|
||||
// pass it here so that the UI can change its view.
|
||||
public void UpdateState(IEye? eye, HashSet<string> subnets, string activeAddress, string activeSubnet, Dictionary<string, string> cameras)
|
||||
public void UpdateState(IEye? eye, string activeAddress, NetEntity? activeCamera)
|
||||
{
|
||||
_currentAddress = activeAddress;
|
||||
_trackedEntity = activeCamera;
|
||||
SetCameraView(eye);
|
||||
|
||||
if (subnets.Count == 0)
|
||||
{
|
||||
SubnetSelector.AddItem(Loc.GetString("surveillance-camera-monitor-ui-no-subnets"));
|
||||
SubnetSelector.Disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubnetSelector.Disabled && subnets.Count != 0)
|
||||
{
|
||||
SubnetSelector.Clear();
|
||||
SubnetSelector.Disabled = false;
|
||||
}
|
||||
|
||||
// That way, we have *a* subnet selected if this is ever opened.
|
||||
if (string.IsNullOrEmpty(activeSubnet))
|
||||
{
|
||||
SubnetOpened!(subnets.First());
|
||||
return;
|
||||
}
|
||||
|
||||
// if the subnet count is unequal, that means
|
||||
// we have to rebuild the subnet selector
|
||||
if (SubnetSelector.ItemCount != subnets.Count)
|
||||
{
|
||||
SubnetSelector.Clear();
|
||||
_subnetMap.Clear();
|
||||
|
||||
foreach (var subnet in subnets)
|
||||
{
|
||||
var id = AddSubnet(subnet);
|
||||
_subnetMap.Add(subnet, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (_subnetMap.TryGetValue(activeSubnet, out var subnetId))
|
||||
{
|
||||
SubnetSelector.Select(subnetId);
|
||||
}
|
||||
|
||||
PopulateCameraList(cameras);
|
||||
}
|
||||
|
||||
private void PopulateCameraList(Dictionary<string, string> cameras)
|
||||
{
|
||||
SubnetList.Clear();
|
||||
|
||||
foreach (var (address, name) in cameras)
|
||||
{
|
||||
AddCameraToList(name, address);
|
||||
}
|
||||
|
||||
SubnetList.SortItemsByText();
|
||||
}
|
||||
|
||||
private void SetCameraView(IEye? eye)
|
||||
{
|
||||
@@ -173,28 +160,9 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
||||
("address", _currentAddress));
|
||||
}
|
||||
|
||||
private int AddSubnet(string subnet)
|
||||
private void ClearAllCamerasPoint()
|
||||
{
|
||||
var name = subnet;
|
||||
if (_prototypeManager.TryIndex<DeviceFrequencyPrototype>(subnet, out var frequency))
|
||||
{
|
||||
name = Loc.GetString(frequency.Name ?? subnet);
|
||||
}
|
||||
|
||||
SubnetSelector.AddItem(name);
|
||||
SubnetSelector.SetItemMetadata(SubnetSelector.ItemCount - 1, subnet);
|
||||
|
||||
return SubnetSelector.ItemCount - 1;
|
||||
}
|
||||
|
||||
private void AddCameraToList(string name, string address)
|
||||
{
|
||||
var item = SubnetList.AddItem($"{name}: {address}");
|
||||
item.Metadata = address;
|
||||
}
|
||||
|
||||
private void OnSubnetListSelect(ItemList.ItemListSelectedEventArgs args)
|
||||
{
|
||||
CameraSelected!((string) SubnetList[args.ItemIndex].Metadata!);
|
||||
NavMap.TrackedCoordinates.Clear();
|
||||
NavMap.TrackedEntities.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using Content.Client.Pinpointer.UI;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.SurveillanceCamera.UI;
|
||||
|
||||
public sealed partial class SurveillanceCameraNavMapControl : NavMapControl
|
||||
{
|
||||
public NetEntity? Focus;
|
||||
public Dictionary<NetEntity, string> LocalizedNames = new();
|
||||
|
||||
private Label _trackedEntityLabel;
|
||||
private PanelContainer _trackedEntityPanel;
|
||||
|
||||
public SurveillanceCameraNavMapControl()
|
||||
{
|
||||
WallColor = new Color(192, 122, 196);
|
||||
TileColor = new(71, 42, 72);
|
||||
BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity));
|
||||
|
||||
_trackedEntityLabel = new Label
|
||||
{
|
||||
Margin = new Thickness(10f, 8f),
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
Modulate = Color.White,
|
||||
};
|
||||
|
||||
_trackedEntityPanel = new PanelContainer
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat
|
||||
{
|
||||
BackgroundColor = BackgroundColor,
|
||||
},
|
||||
|
||||
Margin = new Thickness(5f, 45f),
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
VerticalAlignment = VAlignment.Bottom,
|
||||
Visible = false,
|
||||
};
|
||||
|
||||
_trackedEntityPanel.AddChild(_trackedEntityLabel);
|
||||
AddChild(_trackedEntityPanel);
|
||||
VerticalExpand = true;
|
||||
VerticalAlignment = VAlignment.Stretch;
|
||||
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (Focus == null)
|
||||
{
|
||||
_trackedEntityLabel.Text = string.Empty;
|
||||
_trackedEntityPanel.Visible = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ((var netEntity, var blip) in TrackedEntities)
|
||||
{
|
||||
if (netEntity != Focus)
|
||||
continue;
|
||||
|
||||
if (!LocalizedNames.TryGetValue(netEntity, out var name))
|
||||
name = "Unknown";
|
||||
|
||||
var message = name + "\nLocation: [x = " + MathF.Round(blip.Coordinates.X) + ", y = " + MathF.Round(blip.Coordinates.Y) + "]";
|
||||
|
||||
_trackedEntityLabel.Text = message;
|
||||
_trackedEntityPanel.Visible = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_trackedEntityLabel.Text = string.Empty;
|
||||
_trackedEntityPanel.Visible = false;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Radio;
|
||||
using Content.Server.SurveillanceCamera;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.Emp;
|
||||
using Content.Shared.Examine;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Content.Server._White.SurveillanceCamera;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[Access(typeof(SurveillanceCameraSystem), typeof(SurveillanceBodyCameraSystem))]
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.SurveillanceCamera;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[Access(typeof(SurveillanceCameraMonitorSystem))]
|
||||
@@ -29,14 +32,10 @@ public sealed partial class SurveillanceCameraMonitorComponent : Component
|
||||
// Set of viewers currently looking at this monitor.
|
||||
public HashSet<EntityUid> Viewers { get; } = new();
|
||||
|
||||
// Current active subnet.
|
||||
[ViewVariables]
|
||||
public string ActiveSubnet { get; set; } = default!;
|
||||
|
||||
// Known cameras in this subnet by address with name values.
|
||||
// This is cleared when the subnet is changed.
|
||||
[ViewVariables]
|
||||
public Dictionary<string, string> KnownCameras { get; } = new();
|
||||
public Dictionary<NetEntity, CameraData> KnownCameras { get; } = new();
|
||||
|
||||
[ViewVariables]
|
||||
// The subnets known by this camera monitor.
|
||||
|
||||
@@ -28,4 +28,9 @@ public sealed partial class SurveillanceCameraRouterComponent : Component
|
||||
|
||||
[DataField("setupAvailableNetworks", customTypeSerializer:typeof(PrototypeIdListSerializer<DeviceFrequencyPrototype>))]
|
||||
public List<string> AvailableNetworks { get; private set; } = new();
|
||||
|
||||
// Sunrise-start
|
||||
[DataField("subnetColor")]
|
||||
public Color SubnetColor;
|
||||
// Sunrise-end
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Speech;
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Server.SurveillanceCamera.Components;
|
||||
using Robust.Shared.Player;
|
||||
using static Content.Server.Chat.Systems.ChatSystem;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Systems;
|
||||
|
||||
public sealed class SurveillanceCameraMicrophoneSystem : EntitySystem
|
||||
{
|
||||
|
||||
@@ -2,13 +2,16 @@ using System.Linq;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.SurveillanceCamera.Components;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.UserInterface;
|
||||
using Content.Shared.SurveillanceCamera;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Systems;
|
||||
|
||||
public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
{
|
||||
@@ -28,7 +31,6 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
subs.Event<SurveillanceCameraRefreshCamerasMessage>(OnRefreshCamerasMessage);
|
||||
subs.Event<SurveillanceCameraRefreshSubnetsMessage>(OnRefreshSubnetsMessage);
|
||||
subs.Event<SurveillanceCameraDisconnectMessage>(OnDisconnectMessage);
|
||||
subs.Event<SurveillanceCameraMonitorSubnetRequestMessage>(OnSubnetRequest);
|
||||
subs.Event<SurveillanceCameraMonitorSwitchMessage>(OnSwitchMessage);
|
||||
subs.Event<BoundUIClosedEvent>(OnBoundUiClose);
|
||||
});
|
||||
@@ -87,15 +89,6 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
RefreshSubnets(uid, component);
|
||||
}
|
||||
|
||||
private void OnSubnetRequest(EntityUid uid, SurveillanceCameraMonitorComponent component,
|
||||
SurveillanceCameraMonitorSubnetRequestMessage args)
|
||||
{
|
||||
if (args.Session.AttachedEntity != null)
|
||||
{
|
||||
SetActiveSubnet(uid, args.Subnet, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPacketReceived(EntityUid uid, SurveillanceCameraMonitorComponent component,
|
||||
DeviceNetworkPacketEvent args)
|
||||
{
|
||||
@@ -127,28 +120,48 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
case SurveillanceCameraSystem.CameraDataMessage:
|
||||
if (!args.Data.TryGetValue(SurveillanceCameraSystem.CameraNameData, out string? name)
|
||||
|| !args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out string? subnetData)
|
||||
|| !args.Data.TryGetValue(SurveillanceCameraSystem.CameraAddressData, out string? address))
|
||||
|| !args.Data.TryGetValue(SurveillanceCameraSystem.CameraAddressData, out string? address)
|
||||
|| !args.Data.TryGetValue(SurveillanceCameraSystem.CameraUid, out EntityUid cameraUid)
|
||||
|| !args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetColor, out Color color))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.ActiveSubnet != subnetData)
|
||||
if (!component.KnownSubnets.TryGetValue(subnetData, out var subnetAddress))
|
||||
{
|
||||
DisconnectFromSubnet(uid, subnetData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!component.KnownCameras.ContainsKey(address))
|
||||
var netEntCamera = GetNetEntity(cameraUid);
|
||||
|
||||
if (!component.KnownCameras.ContainsKey(netEntCamera))
|
||||
{
|
||||
component.KnownCameras.Add(address, name);
|
||||
var coordinates = EntityCoordinates.Invalid;
|
||||
|
||||
if (TryComp<TransformComponent>(cameraUid, out var transform))
|
||||
{
|
||||
if (transform.GridUid != null)
|
||||
{
|
||||
coordinates = transform.Coordinates;
|
||||
}
|
||||
}
|
||||
|
||||
component.KnownCameras.Add(netEntCamera,
|
||||
new CameraData {
|
||||
Name = name,
|
||||
CameraAddress = address,
|
||||
SubnetAddress = subnetAddress,
|
||||
SubnetColor = color,
|
||||
Coordinates = GetNetCoordinates(coordinates)
|
||||
});
|
||||
}
|
||||
|
||||
UpdateUserInterface(uid, component);
|
||||
break;
|
||||
case SurveillanceCameraSystem.CameraSubnetData:
|
||||
if (args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out string? subnet)
|
||||
&& !component.KnownSubnets.ContainsKey(subnet))
|
||||
if (args.Data.TryGetValue(SurveillanceCameraSystem.CameraSubnetData, out string? subnet))
|
||||
{
|
||||
component.KnownSubnets.Add(subnet, args.SenderAddress);
|
||||
component.KnownSubnets.TryAdd(subnet, args.SenderAddress);
|
||||
}
|
||||
|
||||
UpdateUserInterface(uid, component);
|
||||
@@ -161,13 +174,30 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
SurveillanceCameraDisconnectMessage message)
|
||||
{
|
||||
DisconnectCamera(uid, true, component);
|
||||
// Sunrise-start
|
||||
foreach (var subnet in component.KnownSubnets)
|
||||
{
|
||||
DisconnectFromSubnet(uid, subnet.Key);
|
||||
component.KnownCameras.Clear();
|
||||
UpdateUserInterface(uid, component);
|
||||
ConnectToSubnet(uid, subnet.Key);
|
||||
}
|
||||
// Sunrise-end
|
||||
}
|
||||
|
||||
private void OnRefreshCamerasMessage(EntityUid uid, SurveillanceCameraMonitorComponent component,
|
||||
SurveillanceCameraRefreshCamerasMessage message)
|
||||
{
|
||||
component.KnownCameras.Clear();
|
||||
RequestActiveSubnetInfo(uid, component);
|
||||
// Sunrise-start
|
||||
foreach (var subnet in component.KnownSubnets)
|
||||
{
|
||||
DisconnectFromSubnet(uid, subnet.Key);
|
||||
DisconnectCamera(uid, true, component);
|
||||
component.KnownCameras.Clear();
|
||||
UpdateUserInterface(uid, component);
|
||||
ConnectToSubnet(uid, subnet.Key);
|
||||
}
|
||||
// Sunrise-end
|
||||
}
|
||||
|
||||
private void OnRefreshSubnetsMessage(EntityUid uid, SurveillanceCameraMonitorComponent component,
|
||||
@@ -181,7 +211,7 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
// there would be a null check here, but honestly
|
||||
// whichever one is the "latest" switch message gets to
|
||||
// do the switch
|
||||
TrySwitchCameraByAddress(uid, message.Address, component);
|
||||
TrySwitchCameraByUid(uid, GetEntity(message.CameraNetEntity), component);
|
||||
}
|
||||
|
||||
private void OnPowerChanged(EntityUid uid, SurveillanceCameraMonitorComponent component, ref PowerChangedEvent args)
|
||||
@@ -190,7 +220,6 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
{
|
||||
RemoveActiveCamera(uid, component);
|
||||
component.NextCameraAddress = null;
|
||||
component.ActiveSubnet = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,20 +237,17 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
|
||||
private void OnBoundUiClose(EntityUid uid, SurveillanceCameraMonitorComponent component, BoundUIClosedEvent args)
|
||||
{
|
||||
if (args.Session.AttachedEntity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveViewer(uid, args.Session.AttachedEntity.Value, component);
|
||||
RemoveViewer(uid, args.Entity, component);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void SendHeartbeat(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null)
|
||||
{
|
||||
if (!Resolve(uid, ref monitor)
|
||||
|| monitor.LastHeartbeatSent < _heartbeatDelay
|
||||
|| !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var subnetAddress))
|
||||
|| monitor.ActiveCamera == null
|
||||
|| !monitor.KnownCameras.TryGetValue(GetNetEntity(monitor.ActiveCamera.Value), out var cameraData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -232,7 +258,7 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
{ SurveillanceCameraSystem.CameraAddressData, monitor.ActiveCameraAddress }
|
||||
};
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(uid, subnetAddress, payload);
|
||||
_deviceNetworkSystem.QueuePacket(uid, cameraData.SubnetAddress, payload);
|
||||
}
|
||||
|
||||
private void DisconnectCamera(EntityUid uid, bool removeViewers, SurveillanceCameraMonitorComponent? monitor = null)
|
||||
@@ -278,28 +304,10 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload);
|
||||
}
|
||||
|
||||
private void SetActiveSubnet(EntityUid uid, string subnet,
|
||||
SurveillanceCameraMonitorComponent? monitor = null)
|
||||
private void RequestSubnetInfo(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null)
|
||||
{
|
||||
if (!Resolve(uid, ref monitor)
|
||||
|| !monitor.KnownSubnets.ContainsKey(subnet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DisconnectFromSubnet(uid, monitor.ActiveSubnet);
|
||||
DisconnectCamera(uid, true, monitor);
|
||||
monitor.ActiveSubnet = subnet;
|
||||
monitor.KnownCameras.Clear();
|
||||
UpdateUserInterface(uid, monitor);
|
||||
|
||||
ConnectToSubnet(uid, subnet);
|
||||
}
|
||||
|
||||
private void RequestActiveSubnetInfo(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null)
|
||||
{
|
||||
if (!Resolve(uid, ref monitor)
|
||||
|| !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var address))
|
||||
|| !monitor.KnownSubnets.TryGetValue(subnet, out var address))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -325,7 +333,7 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
};
|
||||
_deviceNetworkSystem.QueuePacket(uid, address, payload);
|
||||
|
||||
RequestActiveSubnetInfo(uid);
|
||||
RequestSubnetInfo(uid, subnet, monitor);
|
||||
}
|
||||
|
||||
private void DisconnectFromSubnet(EntityUid uid, string subnet, SurveillanceCameraMonitorComponent? monitor = null)
|
||||
@@ -415,11 +423,12 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
UpdateUserInterface(uid, monitor);
|
||||
}
|
||||
|
||||
private void TrySwitchCameraByAddress(EntityUid uid, string address,
|
||||
private void TrySwitchCameraByAddress(EntityUid uid,
|
||||
string camera,
|
||||
string subnet,
|
||||
SurveillanceCameraMonitorComponent? monitor = null)
|
||||
{
|
||||
if (!Resolve(uid, ref monitor)
|
||||
|| !monitor.KnownSubnets.TryGetValue(monitor.ActiveSubnet, out var subnetAddress))
|
||||
if (!Resolve(uid, ref monitor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -427,11 +436,11 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
{DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraConnectMessage},
|
||||
{SurveillanceCameraSystem.CameraAddressData, address}
|
||||
{SurveillanceCameraSystem.CameraAddressData, camera}
|
||||
};
|
||||
|
||||
monitor.NextCameraAddress = address;
|
||||
_deviceNetworkSystem.QueuePacket(uid, subnetAddress, payload);
|
||||
monitor.NextCameraAddress = camera;
|
||||
_deviceNetworkSystem.QueuePacket(uid, subnet, payload);
|
||||
}
|
||||
|
||||
// Attempts to switch over the current viewed camera on this monitor
|
||||
@@ -486,7 +495,7 @@ public sealed class SurveillanceCameraMonitorSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
var state = new SurveillanceCameraMonitorUiState(GetNetEntity(monitor.ActiveCamera), monitor.KnownSubnets.Keys.ToHashSet(), monitor.ActiveCameraAddress, monitor.ActiveSubnet, monitor.KnownCameras);
|
||||
var state = new SurveillanceCameraMonitorUiState(GetNetEntity(monitor.ActiveCamera), monitor.KnownSubnets.Keys.ToHashSet(), monitor.ActiveCameraAddress, monitor.KnownCameras);
|
||||
_userInterface.TrySetUiState(uid, SurveillanceCameraMonitorUiKey.Key, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.SurveillanceCamera;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.SurveillanceCamera;
|
||||
@@ -10,7 +12,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Systems;
|
||||
|
||||
public sealed class SurveillanceCameraRouterSystem : EntitySystem
|
||||
{
|
||||
@@ -244,7 +246,8 @@ public sealed class SurveillanceCameraRouterSystem : EntitySystem
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
{ DeviceNetworkConstants.Command, SurveillanceCameraSystem.CameraPingMessage },
|
||||
{ SurveillanceCameraSystem.CameraSubnetData, router.SubnetName }
|
||||
{ SurveillanceCameraSystem.CameraSubnetData, router.SubnetName },
|
||||
{ SurveillanceCameraSystem.CameraSubnetColor, router.SubnetColor}
|
||||
};
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(uid, null, payload, router.SubnetFrequency);
|
||||
@@ -257,6 +260,10 @@ public sealed class SurveillanceCameraRouterSystem : EntitySystem
|
||||
{
|
||||
return;
|
||||
}
|
||||
payload[SurveillanceCameraSystem.CameraSubnetData] = router.SubnetFrequencyId;
|
||||
payload[SurveillanceCameraSystem.CameraSubnetColor] = router.SubnetColor;
|
||||
|
||||
payload[SurveillanceCameraSystem.CameraSubnetData] = router.SubnetFrequencyId;
|
||||
|
||||
foreach (var address in router.MonitorRoutes)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using Content.Shared.Speech;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// This handles speech for surveillance camera monitors.
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Emp;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.SurveillanceCamera.Components;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.SurveillanceCamera;
|
||||
@@ -12,7 +13,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.SurveillanceCamera;
|
||||
namespace Content.Server.SurveillanceCamera.Systems;
|
||||
|
||||
public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
{
|
||||
@@ -47,8 +48,10 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
public const string CameraSubnetDisconnectMessage = "surveillance_camera_subnet_disconnect";
|
||||
|
||||
public const string CameraAddressData = "surveillance_camera_data_origin";
|
||||
public const string CameraUid = "surveillance_camera_data_uid";
|
||||
public const string CameraNameData = "surveillance_camera_data_name";
|
||||
public const string CameraSubnetData = "surveillance_camera_data_subnet";
|
||||
public const string CameraSubnetColor = "surveillance_camera_color_subnet";
|
||||
|
||||
public const int CameraNameLimit = 32;
|
||||
|
||||
@@ -84,7 +87,9 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
{ DeviceNetworkConstants.Command, string.Empty },
|
||||
{ CameraAddressData, deviceNet.Address },
|
||||
{ CameraNameData, component.CameraId },
|
||||
{ CameraSubnetData, string.Empty }
|
||||
{ CameraSubnetData, string.Empty },
|
||||
{ CameraSubnetColor, new Color() },
|
||||
{ CameraUid, uid }
|
||||
};
|
||||
|
||||
var dest = string.Empty;
|
||||
@@ -92,60 +97,50 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
switch (command)
|
||||
{
|
||||
case CameraConnectMessage:
|
||||
if (!args.Data.TryGetValue(CameraAddressData, out dest)
|
||||
|| string.IsNullOrEmpty(args.Address))
|
||||
{
|
||||
if (!args.Data.TryGetValue(CameraAddressData, out dest) || string.IsNullOrEmpty(args.Address))
|
||||
return;
|
||||
}
|
||||
|
||||
payload[DeviceNetworkConstants.Command] = CameraConnectMessage;
|
||||
break;
|
||||
|
||||
case CameraHeartbeatMessage:
|
||||
if (!args.Data.TryGetValue(CameraAddressData, out dest)
|
||||
|| string.IsNullOrEmpty(args.Address))
|
||||
{
|
||||
if (!args.Data.TryGetValue(CameraAddressData, out dest) || string.IsNullOrEmpty(args.Address))
|
||||
return;
|
||||
}
|
||||
|
||||
payload[DeviceNetworkConstants.Command] = CameraHeartbeatMessage;
|
||||
break;
|
||||
|
||||
case CameraPingMessage:
|
||||
if (!args.Data.TryGetValue(CameraSubnetData, out string? subnet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.Data.TryGetValue(CameraSubnetColor, out Color color))
|
||||
return;
|
||||
|
||||
dest = args.SenderAddress;
|
||||
payload[CameraSubnetData] = subnet;
|
||||
payload[CameraSubnetColor] = color;
|
||||
payload[CameraUid] = uid;
|
||||
payload[DeviceNetworkConstants.Command] = CameraDataMessage;
|
||||
break;
|
||||
}
|
||||
|
||||
_deviceNetworkSystem.QueuePacket(
|
||||
uid,
|
||||
dest,
|
||||
payload);
|
||||
_deviceNetworkSystem.QueuePacket(uid, dest, payload);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddVerbs(EntityUid uid, SurveillanceCameraComponent component, GetVerbsEvent<AlternativeVerb> verbs)
|
||||
{
|
||||
if (!_actionBlocker.CanInteract(verbs.User, uid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryComp<SurveillanceBodyCameraComponent>(uid, out _)) // WD EDIT
|
||||
{
|
||||
if (HasComp<SurveillanceBodyCameraComponent>(uid)) // WD EDIT
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.NameSet && component.NetworkSet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AlternativeVerb verb = new();
|
||||
var verb = new AlternativeVerb();
|
||||
verb.Text = Loc.GetString("surveillance-camera-setup");
|
||||
verb.Act = () => OpenSetupInterface(uid, verbs.User, component);
|
||||
verbs.Verbs.Add(verb);
|
||||
@@ -181,21 +176,14 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
private void OnSetNetwork(EntityUid uid, SurveillanceCameraComponent component,
|
||||
SurveillanceCameraSetupSetNetwork args)
|
||||
{
|
||||
if (args.UiKey is not SurveillanceCameraSetupUiKey key
|
||||
|| key != SurveillanceCameraSetupUiKey.Camera)
|
||||
{
|
||||
if (args.UiKey is not SurveillanceCameraSetupUiKey key || key != SurveillanceCameraSetupUiKey.Camera)
|
||||
return;
|
||||
}
|
||||
if (args.Network < 0 || args.Network >= component.AvailableNetworks.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_prototypeManager.TryIndex<DeviceFrequencyPrototype>(component.AvailableNetworks[args.Network],
|
||||
out var frequency))
|
||||
{
|
||||
if (args.Network < 0 || args.Network >= component.AvailableNetworks.Count)
|
||||
return;
|
||||
|
||||
if (!_prototypeManager.TryIndex<DeviceFrequencyPrototype>(component.AvailableNetworks[args.Network], out var frequency))
|
||||
return;
|
||||
}
|
||||
|
||||
_deviceNetworkSystem.SetReceiveFrequency(uid, frequency.Frequency);
|
||||
component.NetworkSet = true;
|
||||
@@ -206,6 +194,7 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
{
|
||||
if (!Resolve(uid, ref camera) || !Resolve(player, ref actor))
|
||||
return;
|
||||
|
||||
if (!_userInterface.TryGetUi(uid, SurveillanceCameraSetupUiKey.Camera, out var bui))
|
||||
return;
|
||||
|
||||
@@ -216,9 +205,7 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
public void UpdateSetupInterface(EntityUid uid, SurveillanceCameraComponent? camera = null, DeviceNetworkComponent? deviceNet = null)
|
||||
{
|
||||
if (!Resolve(uid, ref camera, ref deviceNet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera.NameSet && camera.NetworkSet && !TryComp<SurveillanceBodyCameraComponent>(uid, out _)) // WD EDIT
|
||||
{
|
||||
@@ -249,9 +236,7 @@ public sealed class SurveillanceCameraSystem : EntitySystem
|
||||
private void Deactivate(EntityUid camera, SurveillanceCameraComponent? component = null)
|
||||
{
|
||||
if (!Resolve(camera, ref component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ev = new SurveillanceCameraDeactivateEvent(camera);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.PowerCell;
|
||||
using Content.Server.SurveillanceCamera;
|
||||
using Content.Server.SurveillanceCamera.Components;
|
||||
using Content.Server.SurveillanceCamera.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Clothing.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
|
||||
@@ -1047,21 +1047,21 @@ namespace Content.Shared.CCVar
|
||||
/// Divisor from maxForce (pressureDifference * 2.25f) to force applied on objects.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SpaceWindPressureForceDivisorPush =
|
||||
CVarDef.Create("atmos.space_wind_pressure_force_divisor_push", 2500f, CVar.SERVERONLY);
|
||||
CVarDef.Create("atmos.space_wind_pressure_force_divisor_push", 1700f, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum velocity (not force) that may be applied to an object by atmospheric pressure differences.
|
||||
/// Useful to prevent clipping through objects.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SpaceWindMaxVelocity =
|
||||
CVarDef.Create("atmos.space_wind_max_velocity", 15f, CVar.SERVERONLY);
|
||||
CVarDef.Create("atmos.space_wind_max_velocity", 7f, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum force that may be applied to an object by pushing (i.e. not throwing) atmospheric pressure differences.
|
||||
/// A "throwing" atmospheric pressure difference ignores this limit, but not the max. velocity limit.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SpaceWindMaxPushForce =
|
||||
CVarDef.Create("atmos.space_wind_max_push_force", 20f, CVar.SERVERONLY);
|
||||
CVarDef.Create("atmos.space_wind_max_push_force", 17f, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// If an object's mass is below this number, then this number is used in place of mass to determine whether air pressure can throw an object.
|
||||
@@ -1079,7 +1079,7 @@ namespace Content.Shared.CCVar
|
||||
/// If an object's inverse mass is lower than this, it is capped at this. Basically, an upper limit to how heavy an object can be before it stops resisting space wind more.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SpaceWindMaximumCalculatedInverseMass =
|
||||
CVarDef.Create("atmos.space_wind_maximum_calculated_inverse_mass", 0.04f, CVar.SERVERONLY);
|
||||
CVarDef.Create("atmos.space_wind_maximum_calculated_inverse_mass", 0.08f, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Whether monstermos tile equalization is enabled.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.SurveillanceCamera;
|
||||
@@ -17,30 +18,39 @@ public sealed class SurveillanceCameraMonitorUiState : BoundUserInterfaceState
|
||||
|
||||
public string ActiveAddress;
|
||||
|
||||
// Currently active subnet.
|
||||
public string ActiveSubnet { get; }
|
||||
|
||||
// Known cameras, by address and name.
|
||||
public Dictionary<string, string> Cameras { get; }
|
||||
public Dictionary<NetEntity, CameraData> Cameras { get; }
|
||||
|
||||
public SurveillanceCameraMonitorUiState(NetEntity? activeCamera, HashSet<string> subnets, string activeAddress, string activeSubnet, Dictionary<string, string> cameras)
|
||||
public SurveillanceCameraMonitorUiState(NetEntity? activeCamera, HashSet<string> subnets, string activeAddress, Dictionary<NetEntity, CameraData> cameras)
|
||||
{
|
||||
ActiveCamera = activeCamera;
|
||||
Subnets = subnets;
|
||||
ActiveAddress = activeAddress;
|
||||
ActiveSubnet = activeSubnet;
|
||||
Cameras = cameras;
|
||||
}
|
||||
}
|
||||
|
||||
// Sunrise-start
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public partial class CameraData
|
||||
{
|
||||
public string CameraAddress { get; set; }
|
||||
public string SubnetAddress { get; set; }
|
||||
public string Name { get; set; }
|
||||
public NetCoordinates Coordinates { get; set; }
|
||||
public Color SubnetColor { get; set; }
|
||||
}
|
||||
// Sunrise-end
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SurveillanceCameraMonitorSwitchMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Address { get; }
|
||||
public NetEntity CameraNetEntity { get; }
|
||||
|
||||
public SurveillanceCameraMonitorSwitchMessage(string address)
|
||||
public SurveillanceCameraMonitorSwitchMessage(NetEntity camera)
|
||||
{
|
||||
Address = address;
|
||||
CameraNetEntity = camera;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
Resources/Changelog/ChangelogSunrise.yml
Normal file
@@ -6785,3 +6785,32 @@
|
||||
id: 419
|
||||
time: '2024-07-26T13:53:25.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/499
|
||||
- author: Warete
|
||||
changes:
|
||||
- message: "\u041A\u0430\u043C\u0435\u0440\u044B \u0441\u0442\u0430\u043B\u0438\
|
||||
\ \u0431\u043E\u043B\u0435\u0435 \u043F\u0440\u0438\u044F\u0442\u043D\u044B\u043C\
|
||||
\u0438 \u0432 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\
|
||||
\u0438\u0438"
|
||||
type: Tweak
|
||||
id: 420
|
||||
time: '2024-07-27T15:47:27.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/501
|
||||
- author: PuroSlavKing
|
||||
changes:
|
||||
- message: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B \u0441\u0442\u0435\
|
||||
\u043A\u043B\u044F\u043D\u043D\u044B\u0435 \u0448\u043B\u044E\u0437\u044B \u0440\
|
||||
\u0430\u0437\u043C\u0435\u0440\u0430\u043C\u0438 \u0432 2\u04451 \u0438 3\u0445\
|
||||
1 \u0442\u0430\u0439\u043B\u0430."
|
||||
type: Add
|
||||
id: 421
|
||||
time: '2024-07-27T15:46:53.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/504
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u0420\u0430\u0437\u0433\u0435\u0440\u043C\u044B \u0441\u0442\u0430\u043B\
|
||||
\u0438 \u044D\u0444\u0444\u0435\u043A\u0442\u043D\u0435\u0435 \u0438 \u0441\u043C\
|
||||
\u0435\u0448\u043D\u0435\u0435"
|
||||
type: Tweak
|
||||
id: 422
|
||||
time: '2024-07-27T15:48:25.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/492
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ent-DoubleGlassAirlock = двойной стеклянный шлюз
|
||||
.desc = { ent-AirlockGlass.desc }
|
||||
.suffix = 2x1
|
||||
|
||||
ent-ThreepleGlassAirlock = тройной стеклянный шлюз
|
||||
.desc = { ent-AirlockGlass.desc }
|
||||
.suffix = 3x1
|
||||
@@ -11,3 +11,6 @@ surveillance-camera-setup = Настроить
|
||||
surveillance-camera-setup-ui-set = Установить
|
||||
surveillance-body-camera-on = { $item } начинает мигать
|
||||
surveillance-body-camera-off = { $item } перестает мигать
|
||||
|
||||
surveillance-camera-monitor-ui-flavor-left = Большой брат смотрит.
|
||||
surveillance-camera-monitor-ui-flavor-right = v1.984
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
- SurveillanceCameraGeneral
|
||||
- SurveillanceCameraMedical
|
||||
- SurveillanceCameraCommand
|
||||
subnetColor: "#088743"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -46,6 +47,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraEngineering
|
||||
subnetColor: "#EFB341"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -54,6 +56,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraSecurity
|
||||
subnetColor: "#DE3A3A"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -62,6 +65,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraScience
|
||||
subnetColor: "#D381C9"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -70,6 +74,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraSupply
|
||||
subnetColor: "#A46106"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -78,6 +83,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraCommand
|
||||
subnetColor: "#052EED"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -86,6 +92,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraService
|
||||
subnetColor: "#9FED58"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -94,6 +101,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraMedical
|
||||
subnetColor: "#52B4E9"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraRouterBase
|
||||
@@ -102,6 +110,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraGeneral
|
||||
subnetColor: "#088743"
|
||||
|
||||
- type: entity
|
||||
parent: [ BaseMachinePowered, ConstructibleMachine ]
|
||||
@@ -136,6 +145,7 @@
|
||||
setupAvailableNetworks:
|
||||
- SurveillanceCameraEntertainment
|
||||
- SurveillanceCameraSecurity
|
||||
subnetColor: "#088743"
|
||||
|
||||
- type: entity
|
||||
parent: SurveillanceCameraWirelessRouterBase
|
||||
@@ -144,6 +154,7 @@
|
||||
components:
|
||||
- type: SurveillanceCameraRouter
|
||||
subnetFrequency: SurveillanceCameraEntertainment
|
||||
subnetColor: "#088743"
|
||||
|
||||
# Body Camera Separate Router
|
||||
- type: entity
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
- type: entity
|
||||
parent: Airlock
|
||||
id: DoubleGlassAirlock
|
||||
components:
|
||||
- type: MeleeSound
|
||||
soundGroups:
|
||||
Brute:
|
||||
collection: GlassSmack
|
||||
- type: Door
|
||||
occludes: false
|
||||
- type: Occluder
|
||||
enabled: false
|
||||
- type: Sprite
|
||||
sprite: White/Structures/Doors/Airlocks/Glass/Wide/glass_2x1.rsi
|
||||
snapCardinals: false
|
||||
offset: 0.5,0
|
||||
- type: AnimationPlayer
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.49,-0.49,1.49,0.49" # 2x1
|
||||
density: 100
|
||||
mask:
|
||||
- FullTileMask
|
||||
layer:
|
||||
- GlassAirlockLayer
|
||||
- type: LayerChangeOnWeld
|
||||
unWeldedLayer: GlassAirlockLayer
|
||||
weldedLayer: GlassLayer
|
||||
- type: Rotatable
|
||||
rotateWhileAnchored: true
|
||||
- type: Transform
|
||||
noRot: false
|
||||
- type: Construction
|
||||
graph: Airlock
|
||||
node: glassAirlock
|
||||
- type: PaintableAirlock
|
||||
group: Glass
|
||||
department: null
|
||||
- type: Tag
|
||||
tags:
|
||||
- GlassAirlock
|
||||
@@ -0,0 +1,43 @@
|
||||
- type: entity
|
||||
parent: Airlock
|
||||
id: ThreepleGlassAirlock
|
||||
components:
|
||||
- type: MeleeSound
|
||||
soundGroups:
|
||||
Brute:
|
||||
collection: GlassSmack
|
||||
- type: Door
|
||||
occludes: false
|
||||
- type: Occluder
|
||||
enabled: false
|
||||
- type: Sprite # TODO: NORMAL 3x1 AIRLOCK SPRITE
|
||||
sprite: White/Structures/Doors/Airlocks/Glass/Wide/glass_3x1.rsi
|
||||
snapCardinals: false
|
||||
- type: AnimationPlayer
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-0.49,1.5,0.49" # 3x1
|
||||
density: 100
|
||||
mask:
|
||||
- FullTileMask
|
||||
layer:
|
||||
- GlassAirlockLayer
|
||||
- type: LayerChangeOnWeld
|
||||
unWeldedLayer: GlassAirlockLayer
|
||||
weldedLayer: GlassLayer
|
||||
- type: Rotatable
|
||||
rotateWhileAnchored: true
|
||||
- type: Transform
|
||||
noRot: false
|
||||
- type: Construction
|
||||
graph: Airlock
|
||||
node: glassAirlock
|
||||
- type: PaintableAirlock
|
||||
group: Glass
|
||||
department: null
|
||||
- type: Tag
|
||||
tags:
|
||||
- GlassAirlock
|
||||
0
Resources/Prototypes/_White/portable_computers.yml
Normal file
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 849 B |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 475 B |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 625 B |
|
After Width: | Height: | Size: 272 B |
|
After Width: | Height: | Size: 272 B |
@@ -0,0 +1,264 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from IDINa_Huy.dmi | Edited by PuroSlavKing (Github)",
|
||||
"size": {
|
||||
"x": 64,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "assembly"
|
||||
},
|
||||
{
|
||||
"name": "assembly-fill"
|
||||
},
|
||||
{
|
||||
"name": "assembly-glass"
|
||||
},
|
||||
{
|
||||
"name": "bolted_unlit"
|
||||
},
|
||||
{
|
||||
"name": "bolted_open_unlit"
|
||||
},
|
||||
{
|
||||
"name": "closed"
|
||||
},
|
||||
{
|
||||
"name": "closed_unlit"
|
||||
},
|
||||
{
|
||||
"name": "closed-fill"
|
||||
},
|
||||
{
|
||||
"name": "closed-glass"
|
||||
},
|
||||
{
|
||||
"name": "panel_closed"
|
||||
},
|
||||
{
|
||||
"name": "closing",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-fill",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-glass",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-panel",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "deny_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "open"
|
||||
},
|
||||
{
|
||||
"name": "open_unlit"
|
||||
},
|
||||
{
|
||||
"name": "panel_open"
|
||||
},
|
||||
{
|
||||
"name": "opening",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-fill",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-glass",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-panel",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_broken",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
1.7
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_damaged",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_open",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "welded"
|
||||
},
|
||||
{
|
||||
"name": "emergency_unlit",
|
||||
"delays": [
|
||||
[
|
||||
1.2,
|
||||
1.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "emergency_open_unlit"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 453 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 870 B |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 467 B |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 100 B |
|
After Width: | Height: | Size: 374 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 315 B |
|
After Width: | Height: | Size: 288 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 403 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 687 B |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1,264 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from IDINa_Huy.dmi | Edited by PuroSlavKing (Github)",
|
||||
"size": {
|
||||
"x": 96,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "assembly"
|
||||
},
|
||||
{
|
||||
"name": "assembly-fill"
|
||||
},
|
||||
{
|
||||
"name": "assembly-glass"
|
||||
},
|
||||
{
|
||||
"name": "bolted_unlit"
|
||||
},
|
||||
{
|
||||
"name": "bolted_open_unlit"
|
||||
},
|
||||
{
|
||||
"name": "closed"
|
||||
},
|
||||
{
|
||||
"name": "closed_unlit"
|
||||
},
|
||||
{
|
||||
"name": "closed-fill"
|
||||
},
|
||||
{
|
||||
"name": "closed-glass"
|
||||
},
|
||||
{
|
||||
"name": "panel_closed"
|
||||
},
|
||||
{
|
||||
"name": "closing",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-fill",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-glass",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closing-panel",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "deny_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "open"
|
||||
},
|
||||
{
|
||||
"name": "open_unlit"
|
||||
},
|
||||
{
|
||||
"name": "panel_open"
|
||||
},
|
||||
{
|
||||
"name": "opening",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening_unlit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-fill",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-glass",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opening-panel",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.07,
|
||||
0.07,
|
||||
0.07,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_broken",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
1.7
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_damaged",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sparks_open",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "welded"
|
||||
},
|
||||
{
|
||||
"name": "emergency_unlit",
|
||||
"delays": [
|
||||
[
|
||||
1.2,
|
||||
1.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "emergency_open_unlit"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 837 B |
|
After Width: | Height: | Size: 687 B |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 105 B |
|
After Width: | Height: | Size: 744 B |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 701 B |
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon"
|
||||
}
|
||||
]
|
||||
}
|
||||