Files
ss14-wl/Content.Server/_WL/Photo/PhotoSystem.cs
T
MishaUnity 11b903d2de Фильтры для фотоаппарата (#530)
* Сущности на сканере масс

* Базовые системы

* Почти завершённый вариант

* Секретка на Багеле

* Revert "Секретка на Багеле"

This reverts commit 1bc7c14a18.

* Небольшие исправления

* Очистка кода

* Изменение системы добавления оверлеев

* Небольшие изменения и очистка кода
2026-04-04 17:44:55 +03:00

171 lines
5.8 KiB
C#

using Content.Server.Hands.Systems;
using Content.Server.Materials;
using Content.Server.Popups;
using Content.Shared._WL.Photo;
using Content.Shared._WL.Photo.Filters;
using Content.Shared.Interaction.Events;
using Content.Shared.Materials;
using Content.Shared.Timing;
using Content.Shared.UserInterface;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
namespace Content.Server._WL.Photo;
public sealed partial class PhotoSystem : SharedPhotoSystem
{
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
[Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly MaterialStorageSystem _material = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly UseDelaySystem _delay = default!;
[Dependency] private readonly AudioSystem _audio = default!;
//96 KB
const int MAX_SIZE = 1024 * 96;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PhotoCameraComponent, ActivatableUIOpenAttemptEvent>(OnOpenCameraInterfaceAttempt);
Subs.BuiEvents<PhotoCameraComponent>(PhotoCameraUiKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnCameraBoundUiClose);
subs.Event<PhotoCameraTakeImageMessage>(OnTakeImageMessage);
});
SubscribeLocalEvent<PhotoCameraComponent, MaterialAmountChangedEvent>(OnPaperInserted);
SubscribeLocalEvent<PhotoCameraComponent, DroppedEvent>(OnCameraDropped);
SubscribeLocalEvent<PhotoCardComponent, AfterActivatableUIOpenEvent>(OnOpenCardInterface);
SubscribeLocalEvent<PhotoCameraComponent, EntInsertedIntoContainerMessage>(OnFilterInserted);
SubscribeLocalEvent<PhotoCameraComponent, EntRemovedFromContainerMessage>(OnFilterRemoved);
}
private void OnOpenCameraInterfaceAttempt(EntityUid uid, PhotoCameraComponent component, ActivatableUIOpenAttemptEvent args)
{
if (component.User != null)
{
args.Cancel();
return;
}
if (!_hands.IsHolding(args.User, uid))
{
_popup.PopupEntity(Loc.GetString("photo-camera-not-holding"), uid, args.User);
args.Cancel();
return;
}
}
private void OnCameraBoundUiClose(EntityUid uid, PhotoCameraComponent component, BoundUIClosedEvent args)
{
if (component.User == null)
return;
RemComp<PhotoCameraUserComponent>(component.User.Value);
component.User = null;
}
private void OnTakeImageMessage(EntityUid uid, PhotoCameraComponent component, PhotoCameraTakeImageMessage message)
{
if (message.Data.Length > MAX_SIZE)
return;
if (!CheckPngSignature(message.Data))
return;
TryTakeImage(uid, component, message.Data);
}
private void OnPaperInserted(EntityUid uid, PhotoCameraComponent component, MaterialAmountChangedEvent args)
{
UpdateCameraInterface(uid, component, component.User);
}
private void OnCameraDropped(EntityUid uid, PhotoCameraComponent component, DroppedEvent args)
{
if (component.User == null || args.User != component.User)
return;
_userInterface.CloseUis(uid);
}
private void TryTakeImage(EntityUid uid, PhotoCameraComponent component, byte[] imageData)
{
if (_delay.IsDelayed(uid))
return;
_delay.TryResetDelay(uid);
if (PrintCard(uid, component, imageData))
_audio.PlayPvs(component.PhotoSound, uid);
else
_audio.PlayPvs(component.ErrorSound, uid);
}
private bool PrintCard(EntityUid uid, PhotoCameraComponent component, byte[] imageData)
{
if (!_material.TryChangeMaterialAmount(uid, component.CardMaterial, -component.CardCost))
{
if (component.User != null)
_popup.PopupEntity(Loc.GetString("photo-camera-no-paper"), uid, component.User.Value);
return false;
}
var card = Spawn(component.CardPrototype);
_transform.SetMapCoordinates(card, _transform.GetMapCoordinates(uid));
if (TryComp<PhotoCardComponent>(card, out var photo))
photo.ImageData = imageData;
if (component.User != null)
_hands.TryPickupAnyHand(component.User.Value, card);
UpdateCameraInterface(uid, component, component.User);
return true;
}
private static bool CheckPngSignature(ReadOnlySpan<byte> data)
{
if (data.Length < 8) return false;
return data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 &&
data[4] == 0x0D && data[5] == 0x0A && data[6] == 0x1A && data[7] == 0x0A;
}
private void OnFilterInserted(EntityUid uid, PhotoCameraComponent component, EntInsertedIntoContainerMessage args)
{
if (!TryComp<PhotoCameraFilterComponent>(args.Entity, out var filter))
return;
if (args.Container.ID != component.FilterSlot)
return;
EntityManager.AddComponents(uid, filter.FilterComponents);
}
private void OnFilterRemoved(EntityUid uid, PhotoCameraComponent component, EntRemovedFromContainerMessage args)
{
if (!TryComp<PhotoCameraFilterComponent>(args.Entity, out var filter))
return;
if (args.Container.ID != component.FilterSlot)
return;
EntityManager.RemoveComponents(uid, filter.FilterComponents);
}
// Photo Card
private void OnOpenCardInterface(EntityUid uid, PhotoCardComponent component, AfterActivatableUIOpenEvent args)
{
var state = new PhotoCardUiState(component.ImageData);
_userInterface.SetUiState(uid, PhotoCardUiKey.Key, state);
}
}