Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NVG (Port From _LostParadise) #1128

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Content.Client/Clothing/NightVisionOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;

namespace Content.Client.Clothing;

/// <summary>
/// Made by BL02DL from _LostParadise
/// </summary>

public sealed class NightVisionOverlay : Overlay
{
private readonly IPrototypeManager _prototypeManager;
private readonly NightVisionSystem _nightVisionSystem;

public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;

private readonly ShaderInstance _shader;

public NightVisionOverlay(NightVisionSystem nightVisionSystem)
{
IoCManager.InjectDependencies(this);
_nightVisionSystem = nightVisionSystem;
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
_shader = _prototypeManager.Index<ShaderPrototype>("NightVision").InstanceUnique();
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture == null)
return;

var handle = args.WorldHandle;
var nightcomp = _nightVisionSystem.GetNightComp();

if (nightcomp == null)
{
Logger.Error("Failed to get night vision component from eyes.");
return;
}

_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_shader.SetParameter("tint", nightcomp.Tint);
_shader.SetParameter("luminance_threshold", nightcomp.Strength);
_shader.SetParameter("noise_amount", nightcomp.Noise);

handle.UseShader(_shader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);
}
}
72 changes: 72 additions & 0 deletions Content.Client/Clothing/NightVisionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
using Robust.Client.Player;
using Robust.Client.Graphics;
using Content.Client.Inventory;
using Content.Shared.Inventory.Events;

namespace Content.Client.Clothing;

/// <summary>
/// Made by BL02DL from _LostParadise
/// </summary>

public sealed class NightVisionSystem : SharedNightVisionSystem
{
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly ILightManager _lightManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[Dependency] private readonly IEntityManager _entityManager = default!;


private NightVisionOverlay _overlay = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRestart);
SubscribeLocalEvent<NightVisionComponent, GotUnequippedEvent>(OnGotUnequipped);

_overlay = new(this);
}

public NightVisionComponent? GetNightComp()
{
var playerUid = EntityUid.Parse(_playerManager.LocalPlayer?.ControlledEntity.ToString());
var slot = _entityManager.GetComponent<InventorySlotsComponent>(playerUid);
_entityManager.TryGetComponent<NightVisionComponent>(slot.SlotData["eyes"].HeldEntity, out var nightvision);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_entityManager.TryGetComponent<NightVisionComponent>(slot.SlotData["eyes"].HeldEntity, out var nightvision);
_entityManager.TryGetComponent<NightVisionComponent>(slot.SlotData["eyes"].HeldEntity, out var nightvision);

Oh this is hardcoded in the "eyes" slot here too. This is incredibly cursed. You shouldn't need a "magic string" here to check only the eyes slot. What if I wanted to make a mech that gives you night vision, or a hardsuit helmet with built-in nightvision?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VMSolidus What i need to do to fix this?

Comment on lines +35 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why in the name of all that's unholy does this convert an entity uid to a string and parse it back?!

Below is a better example. It should work, but it was made in webedit and as such may contain a mistake/mistype/whatever.

Suggested change
var playerUid = EntityUid.Parse(_playerManager.LocalPlayer?.ControlledEntity.ToString());
var slot = _entityManager.GetComponent<InventorySlotsComponent>(playerUid);
_entityManager.TryGetComponent<NightVisionComponent>(slot.SlotData["eyes"].HeldEntity, out var nightvision);
var playerUid = _playerManager.LocalPlayer?.ControlledEntity;
if (!TryComp<InventorySlotsComponent>(playerUid, out var slot) || !TryComp<NightVisionComponent>(slot.SlotData["eyes"].HeldEntity, out var nightvision))
return null;

return nightvision;
}

protected override void UpdateNightVisionEffects(EntityUid parent, EntityUid uid, bool state, NightVisionComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

state = state && component.Enabled;

if (state)
{
_lightManager.DrawLighting = false;
_overlayMan.AddOverlay(_overlay);
}
else
{
_lightManager.DrawLighting = true;
_overlayMan.RemoveOverlay(_overlay);
}
}
private void OnGotUnequipped(EntityUid uid, NightVisionComponent component, GotUnequippedEvent args)
{
if (args.Slot == component.Slot)
{
_overlayMan.RemoveOverlay(_overlay);
_lightManager.DrawLighting = true;
}
}
Comment on lines +59 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this needs to account for the case where two or more clothing types grant night vision at the same time.

private void OnRestart(RoundRestartCleanupEvent ev)
{
_overlayMan.RemoveOverlay(_overlay);
_lightManager.DrawLighting = true;
}
}
31 changes: 31 additions & 0 deletions Content.Server/Clothing/NightVisionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Content.Shared.Clothing;
using Content.Shared.Inventory.Events;

namespace Content.Server.Clothing;

/// <summary>
/// Made by BL02DL from _LostParadise
/// </summary>

public sealed class NightVisionSystem : SharedNightVisionSystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<NightVisionComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<NightVisionComponent, GotUnequippedEvent>(OnGotUnequipped);
}

private void OnGotUnequipped(EntityUid uid, NightVisionComponent component, GotUnequippedEvent args)
{
if (args.Slot == component.Slot)
UpdateNightVisionEffects(args.Equipee, uid, false, component);
}

private void OnGotEquipped(EntityUid uid, NightVisionComponent component, GotEquippedEvent args)
{
if (args.Slot == component.Slot)
UpdateNightVisionEffects(args.Equipee, uid, true, component);
}
Comment on lines +20 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to account for the case where two or more clothings of the same type grant night vision (see solidus' comment about night vision helmets, etc)

}
51 changes: 51 additions & 0 deletions Content.Shared/Clothing/NightVisionComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Clothing;

/// <summary>
/// Made by BL02DL from _LostParadise
/// </summary>

[RegisterComponent, NetworkedComponent(), AutoGenerateComponentState]
[Access(typeof(SharedNightVisionSystem))]
public sealed partial class NightVisionComponent : Component
{
[DataField]
public EntProtoId ToggleAction = "ActionToggleNightVision";

[DataField, AutoNetworkedField]
public EntityUid? ToggleActionEntity;

[DataField, AutoNetworkedField]
public bool Enabled;

[DataField]
public float Tint1 { get; set; } = 0.3f;

[DataField]
public float Tint2 { get; set; } = 0.3f;

[DataField]
public float Tint3 { get; set; } = 0.3f;

public Vector3 Tint
{
get => new(Tint1, Tint2, Tint3);
set
{
Tint1 = value.X;
Tint2 = value.Y;
Tint3 = value.Z;
}
}

[DataField]
public float Strength = 2f;

[DataField]
public float Noise = 0.5f;

[DataField]
public string Slot = "eyes";
}
94 changes: 94 additions & 0 deletions Content.Shared/Clothing/SharedNightVisionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using Content.Shared.Actions;
using Content.Shared.Clothing.EntitySystems;
using Content.Shared.Inventory;
using Content.Shared.Item;
using Content.Shared.Toggleable;
using Content.Shared.Verbs;
using Robust.Shared.Containers;

namespace Content.Shared.Clothing;

/// <summary>
/// Made by BL02DL from _LostParadise
/// </summary>

public abstract class SharedNightVisionSystem : EntitySystem
{
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedActionsSystem _sharedActions = default!;
[Dependency] private readonly SharedActionsSystem _actionContainer = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedContainerSystem _sharedContainer = default!;
[Dependency] private readonly SharedItemSystem _item = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<NightVisionComponent, GetVerbsEvent<ActivationVerb>>(AddToggleVerb);
SubscribeLocalEvent<NightVisionComponent, GetItemActionsEvent>(OnGetActions);
SubscribeLocalEvent<NightVisionComponent, ToggleNightVisionEvent>(OnToggleNightVision);
SubscribeLocalEvent<NightVisionComponent, MapInitEvent>(OnMapInit);
}

private void OnMapInit(EntityUid uid, NightVisionComponent component, MapInitEvent args)
{
_actionContainer.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction);
Dirty(uid, component);
}

private void OnToggleNightVision(EntityUid uid, NightVisionComponent component, ToggleNightVisionEvent args)
{
if (args.Handled)
return;

args.Handled = true;

ToggleNightVision(uid, component);
}

private void ToggleNightVision(EntityUid uid, NightVisionComponent nightvision)
{
nightvision.Enabled = !nightvision.Enabled;

if (_sharedContainer.TryGetContainingContainer(uid, out var container) &&
_inventory.TryGetSlotEntity(container.Owner, "eyes", out var entityUid) && entityUid == uid)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_inventory.TryGetSlotEntity(container.Owner, "eyes", out var entityUid) && entityUid == uid)
_inventory.TryGetSlotEntity(container.Owner, nightvision.Slot, out var entityUid) && entityUid == uid)

UpdateNightVisionEffects(container.Owner, uid, true, nightvision);

if (TryComp<ItemComponent>(uid, out var item))
{
_item.SetHeldPrefix(uid, nightvision.Enabled ? "on" : null, component: item);
_clothing.SetEquippedPrefix(uid, nightvision.Enabled ? "on" : null);
}

_appearance.SetData(uid, ToggleVisuals.Toggled, nightvision.Enabled);
OnChanged(uid, nightvision);
Dirty(uid, nightvision);
}

protected virtual void UpdateNightVisionEffects(EntityUid parent, EntityUid uid, bool state, NightVisionComponent? component) { }

protected void OnChanged(EntityUid uid, NightVisionComponent component)
{
_sharedActions.SetToggled(component.ToggleActionEntity, component.Enabled);
}

private void AddToggleVerb(EntityUid uid, NightVisionComponent component, GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

ActivationVerb verb = new();
verb.Text = Loc.GetString("toggle-nightvision-verb-get-data-text");
verb.Act = () => ToggleNightVision(uid, component);
args.Verbs.Add(verb);
}

private void OnGetActions(EntityUid uid, NightVisionComponent component, GetItemActionsEvent args)
{
args.AddAction(ref component.ToggleActionEntity, component.ToggleAction);
}
}

public sealed partial class ToggleNightVisionEvent : InstantActionEvent {}
17 changes: 17 additions & 0 deletions Resources/Locale/en-US/NightVision/NightVision.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
ent-ActionBaseToggleNightVision = Toggle night vision goggles
.desc = Toggles the night vision goggles on and off.
ent-ActionToggleNightVision = { ent-ActionBaseToggleNightVision }
.desc = { ent-ActionBaseToggleNightVision }
ent-ClothingEyesNVG = night vision goggles
.desc = Now you can see in the dark! It has the label "BL CORP technology".
toggle-nightvision-verb-get-data-text = Toggle Night Vision Goggles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have it placed after/before all of the ent fields for the ease of reading.

ent-ClothingEyesNVG = night vision goggles
.desc = Now you can see in the dark! It has the label "BL CORP technology".
ent-ClothingEyesMesonNVG = engineering night vision goggles
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesMedNVG = medical night vision goggles
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesSecNVG = security night vision goggles
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesDiagnosticNVG = diagnostic night vision goggles
.desc = { ent-ClothingEyesNVG.desc }
15 changes: 15 additions & 0 deletions Resources/Locale/ru-RU/NightVision/NightVision.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ent-ActionBaseToggleNightVision = Переключить ПНВ
.desc = Включате и выключает ПНВ.
ent-ActionToggleNightVision = { ent-ActionBaseToggleNightVision }
.desc = { ent-ActionBaseToggleNightVision }
ent-ClothingEyesNVG = ПНВ
.desc = Теперь ты можешь видеть в темноте! Имеет этикетку "BL CORP technology".
toggle-nightvision-verb-get-data-text = Переключить прибор ночного видения
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have it placed after/before all of the ent fields for the ease of reading.

ent-ClothingEyesMesonNVG = мезонный ПНВ
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesMedNVG = медицинский ПНВ
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesSecNVG = охранный ПНВ
.desc = { ent-ClothingEyesNVG.desc }
ent-ClothingEyesDiagnosticNVG = диагностирующий ПНВ
.desc = { ent-ClothingEyesNVG.desc }
Loading
Loading