Files
tbd-station-14/Content.Client/Holopad/HolopadSystem.cs
chromiumboy 7780b867ac Holopads (#32711)
* Initial resources commit

* Initial code commit

* Added additional resources

* Continuing to build holopad and telephone systems

* Added hologram shader

* Added hologram system and entity

* Holo calls now have a hologram of the user appear on them

* Initial implementation of holopads transmitting nearby chatter

* Added support for linking across multiple telephones/holopads/entities

* Fixed a bunch of bugs

* Tried simplifying holopad entity dependence, added support for mid-call user switching

* Replaced PVS expansion with manually networked sprite states

* Adjusted volume of ring tone

* Added machine board

* Minor features and tweaks

* Resolving merge conflict

* Recommit audio attributions

* Telephone chat adjustments

* Added support for AI interactions with holopads

* Building the holopad UI

* Holopad UI finished

* Further UI tweaks

* Station AI can hear local chatter when being projected from a holopad

* Minor bug fixes

* Added wire panels to holopads

* Basic broadcasting

* Start of emergency broadcasting code

* Fixing issues with broadcasting

* More work on emergency broadcasting

* Updated holopad visuals

* Added cooldown text to emergency broadcast and control lock out screen

* Code clean up

* Fixed issue with timing

* Broadcasting now requires command access

* Fixed some bugs

* Added multiple holopad prototypes with different ranges

* The AI no longer requires power to interact with holopads

* Fixed some additional issues

* Addressing more issues

* Added emote support for holograms

* Changed the broadcast lockout durations to their proper values

* Added AI vision wire to holopads

* Bug fixes

* AI vision and interaction wires can be added to the same wire panel

* Fixed error

* More bug fixes

* Fixed test fail

* Embellished the emergency call lock out window

* Holopads play borg sounds when speaking

* Borg and AI names are listed as the caller ID on the holopad

* Borg chassis can now be seen on holopad holograms

* Holopad returns to a machine frame when badly damaged

* Clarified some text

* Fix merge conflict

* Fixed merge conflict

* Fixing merge conflict

* Fixing merge conflict

* Fixing merge conflict

* Offset menu on open

* AI can alt click on holopads to activate the projector

* Bug fixes for intellicard interactions

* Fixed speech issue with intellicards

* The UI automatically opens for the AI when it alt-clicks on the holopad

* Simplified shader math

* Telephones will auto hang up 60 seconds after the last person on a call stops speaking

* Added better support for AI requests when multiple AI cores are on the station

* The call controls pop up for the AI when they accept a summons from a holopad

* Compatibility mode fix for the hologram shader

* Further shader fixes for compatibility mode

* File clean up

* More cleaning up

* Removed access requirements from quantum holopads so they can used by nukies

* The title of the holopad window now reflects the name of the device

* Linked telephones will lose their connection if both move out of range of each other
2024-12-17 20:18:15 +01:00

173 lines
6.3 KiB
C#

using Content.Shared.Chat.TypingIndicator;
using Content.Shared.Holopad;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using System.Linq;
namespace Content.Client.Holopad;
public sealed class HolopadSystem : SharedHolopadSystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HolopadHologramComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<HolopadHologramComponent, BeforePostShaderRenderEvent>(OnShaderRender);
SubscribeAllEvent<TypingChangedEvent>(OnTypingChanged);
SubscribeNetworkEvent<PlayerSpriteStateRequest>(OnPlayerSpriteStateRequest);
SubscribeNetworkEvent<PlayerSpriteStateMessage>(OnPlayerSpriteStateMessage);
}
private void OnComponentInit(EntityUid uid, HolopadHologramComponent component, ComponentInit ev)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
UpdateHologramSprite(uid);
}
private void OnShaderRender(EntityUid uid, HolopadHologramComponent component, BeforePostShaderRenderEvent ev)
{
if (ev.Sprite.PostShader == null)
return;
ev.Sprite.PostShader.SetParameter("t", (float)_timing.CurTime.TotalSeconds * component.ScrollRate);
}
private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args)
{
var uid = args.SenderSession.AttachedEntity;
if (!Exists(uid))
return;
if (!HasComp<HolopadUserComponent>(uid))
return;
var netEv = new HolopadUserTypingChangedEvent(GetNetEntity(uid.Value), ev.IsTyping);
RaiseNetworkEvent(netEv);
}
private void OnPlayerSpriteStateRequest(PlayerSpriteStateRequest ev)
{
var targetPlayer = GetEntity(ev.TargetPlayer);
var player = _playerManager.LocalSession?.AttachedEntity;
// Ignore the request if received by a player who isn't the target
if (targetPlayer != player)
return;
if (!TryComp<SpriteComponent>(player, out var playerSprite))
return;
var spriteLayerData = new List<PrototypeLayerData>();
if (playerSprite.Visible)
{
// Record the RSI paths, state names and shader paramaters of all visible layers
for (int i = 0; i < playerSprite.AllLayers.Count(); i++)
{
if (!playerSprite.TryGetLayer(i, out var layer))
continue;
if (!layer.Visible ||
string.IsNullOrEmpty(layer.ActualRsi?.Path.ToString()) ||
string.IsNullOrEmpty(layer.State.Name))
continue;
var layerDatum = new PrototypeLayerData();
layerDatum.RsiPath = layer.ActualRsi.Path.ToString();
layerDatum.State = layer.State.Name;
if (layer.CopyToShaderParameters != null)
{
var key = (string)layer.CopyToShaderParameters.LayerKey;
if (playerSprite.LayerMapTryGet(key, out var otherLayerIdx) &&
playerSprite.TryGetLayer(otherLayerIdx, out var otherLayer) &&
otherLayer.Visible)
{
layerDatum.MapKeys = new() { key };
layerDatum.CopyToShaderParameters = new PrototypeCopyToShaderParameters()
{
LayerKey = key,
ParameterTexture = layer.CopyToShaderParameters.ParameterTexture,
ParameterUV = layer.CopyToShaderParameters.ParameterUV
};
}
}
spriteLayerData.Add(layerDatum);
}
}
// Return the recorded data to the server
var evResponse = new PlayerSpriteStateMessage(ev.TargetPlayer, spriteLayerData.ToArray());
RaiseNetworkEvent(evResponse);
}
private void OnPlayerSpriteStateMessage(PlayerSpriteStateMessage ev)
{
UpdateHologramSprite(GetEntity(ev.SpriteEntity), ev.SpriteLayerData);
}
private void UpdateHologramSprite(EntityUid uid, PrototypeLayerData[]? layerData = null)
{
if (!TryComp<SpriteComponent>(uid, out var hologramSprite))
return;
if (!TryComp<HolopadHologramComponent>(uid, out var holopadhologram))
return;
for (int i = hologramSprite.AllLayers.Count() - 1; i >= 0; i--)
hologramSprite.RemoveLayer(i);
if (layerData == null || layerData.Length == 0)
{
layerData = new PrototypeLayerData[1];
layerData[0] = new PrototypeLayerData()
{
RsiPath = holopadhologram.RsiPath,
State = holopadhologram.RsiState
};
}
for (int i = 0; i < layerData.Length; i++)
{
var layer = layerData[i];
layer.Shader = "unshaded";
hologramSprite.AddLayer(layerData[i], i);
}
UpdateHologramShader(uid, hologramSprite, holopadhologram);
}
private void UpdateHologramShader(EntityUid uid, SpriteComponent sprite, HolopadHologramComponent holopadHologram)
{
// Find the texture height of the largest layer
float texHeight = sprite.AllLayers.Max(x => x.PixelSize.Y);
var instance = _prototypeManager.Index<ShaderPrototype>(holopadHologram.ShaderName).InstanceUnique();
instance.SetParameter("color1", new Vector3(holopadHologram.Color1.R, holopadHologram.Color1.G, holopadHologram.Color1.B));
instance.SetParameter("color2", new Vector3(holopadHologram.Color2.R, holopadHologram.Color2.G, holopadHologram.Color2.B));
instance.SetParameter("alpha", holopadHologram.Alpha);
instance.SetParameter("intensity", holopadHologram.Intensity);
instance.SetParameter("texHeight", texHeight);
instance.SetParameter("t", (float)_timing.CurTime.TotalSeconds * holopadHologram.ScrollRate);
sprite.PostShader = instance;
sprite.RaiseShaderEvent = true;
}
}