Skip to content

Commit

Permalink
[феатуре] ms paint (#279)
Browse files Browse the repository at this point in the history
* genuinely disappointed

* +

* cleanup

* Update Content.Client/_White/Overlays/CrayonPreviewOverlay.cs

* 123

* 456

* забыл

* ой блять

---------

Co-authored-by: Remuchi <[email protected]>
  • Loading branch information
RedFoxIV and Remuchi authored Mar 5, 2025
1 parent 84daa7a commit efca951
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 56 deletions.
4 changes: 3 additions & 1 deletion Content.Client/Crayon/CrayonComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;

/* // WWDP EDIT - DEFUNCT - Merged into one shared CrayonComponent.
namespace Content.Client.Crayon
{
[RegisterComponent]
public sealed partial class CrayonComponent : SharedCrayonComponent
{
[ViewVariables(VVAccess.ReadWrite)] public bool UIUpdateNeeded;
[ViewVariables] public int Charges { get; set; }
[ViewVariables] public int Capacity { get; set; }
}
}
*/
69 changes: 60 additions & 9 deletions Content.Client/Crayon/CrayonSystem.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
using Content.Client._White.Overlays;
using Content.Client.Hands.Systems;
using Content.Client.Items;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Crayon;
using Content.Shared.Hands;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
Expand All @@ -13,25 +21,68 @@ namespace Content.Client.Crayon;

public sealed class CrayonSystem : SharedCrayonSystem
{
// Didn't do in shared because I don't think most of the server stuff can be predicted.
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
[Dependency] private readonly HandsSystem _hands = default!;

// Didn't do in shared because I don't think most of the server stuff can be predicted. // if i had arms long enough to reach around the globe i would strangle you.
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState);
// SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState); // WWDP EDIT - DEFUNCT - Moved to using AutoState system.
Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent));

// WWDP EDIT START
SubscribeLocalEvent<CrayonComponent, AfterAutoHandleStateEvent>(CrayonAfterAutoState);
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(CrayonAfterInteract);
SubscribeLocalEvent<CrayonComponent, ComponentRemove>(CrayonRemoved);
SubscribeLocalEvent<CrayonComponent, EntityTerminatingEvent>(CrayonEntRemoved);
// WWDP EDIT END
}

// WWDP EDIT START
private void CrayonAfterInteract(EntityUid uid, CrayonComponent comp, AfterInteractEvent args)
{
if (comp.Charges <= 1)
_ui.CloseUi(uid, CrayonComponent.CrayonUiKey.Key, args.User);
}

private void CrayonRemoved(EntityUid uid, CrayonComponent comp, ComponentRemove args)
{
if (_player.LocalEntity is not EntityUid player ||
uid != _hands.GetActiveItem(player))
return;
_overlay.RemoveOverlay<CrayonPreviewOverlay>();
}

private static void OnCrayonHandleState(EntityUid uid, CrayonComponent component, ref ComponentHandleState args)
private void CrayonEntRemoved(EntityUid uid, CrayonComponent comp, EntityTerminatingEvent args)
{
if (args.Current is not CrayonComponentState state) return;
if (_player.LocalEntity is not EntityUid player ||
uid != _hands.GetActiveItem(player))
return;
_overlay.RemoveOverlay<CrayonPreviewOverlay>();
}

component.Color = state.Color;
component.SelectedState = state.State;
component.Charges = state.Charges;
component.Capacity = state.Capacity;
private void CrayonAfterAutoState(EntityUid uid, CrayonComponent comp, AfterAutoHandleStateEvent args)
{
comp.UIUpdateNeeded = true;
}

component.UIUpdateNeeded = true;
protected override void OnCrayonHandSelected(EntityUid uid, CrayonComponent component, HandSelectedEvent args) // WWDP EDIT
{
base.OnCrayonHandSelected(uid, component, args);
_overlay.RemoveOverlay<CrayonPreviewOverlay>(); // if i still fucked up somewhere and did not remove the event when i should've, this will catch it.
_overlay.AddOverlay(new CrayonPreviewOverlay(_sprite, component));
}

protected override void OnCrayonHandDeselected(EntityUid uid, CrayonComponent component, HandDeselectedEvent args) // WWDP EDIT
{
base.OnCrayonHandDeselected(uid, component, args);
_overlay.RemoveOverlay<CrayonPreviewOverlay>();
}
// WWDP EDIT END

private sealed class StatusControl : Control
{
Expand Down
14 changes: 14 additions & 0 deletions Content.Client/Hands/Systems/HandsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using Robust.Shared.Graphics;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Content.Shared._White.Hands;

namespace Content.Client.Hands.Systems
{
Expand Down Expand Up @@ -68,10 +69,23 @@ public override void Initialize()

SubscribeLocalEvent<HoldingDropComponent, ComponentInit>(HoldingDropComponentInit); // WWDP
SubscribeLocalEvent<HoldingDropComponent, ComponentShutdown>(HoldingDropComponentShutdown); // WWDP
SubscribeNetworkEvent<HandDeselectedNetworkCrutchWrap>(OnHandDeselectedCrutchWrap); // WWDP

OnHandSetActive += OnHandActivated;
}

// WWDP EDIT START
/// <summary>
/// Throw code doesn't run on client so the HandDeselectedEvent that is raised serverside does not get raised clientside.
/// This is awful, but it fixes the issue.
/// </summary>
/// <param name="ev"></param>
private void OnHandDeselectedCrutchWrap(HandDeselectedNetworkCrutchWrap ev)
{
RaiseLocalEvent(GetEntity(ev.Target), new HandDeselectedEvent(GetEntity(ev.User))); // i think i'm starting to get desensitized to this kind of stuff.
}
// WWDP EDIT END

#region StateHandling
private void HandleComponentState(EntityUid uid, HandsComponent component, ref ComponentHandleState args)
{
Expand Down
81 changes: 81 additions & 0 deletions Content.Client/_White/Overlays/CrayonPreviewOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Content.Client.Crayon;
using Content.Shared._White.Hands.Components;
using Content.Shared.Crayon;
using Content.Shared.Decals;
using Content.Shared.Interaction;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using System.Numerics;

namespace Content.Client._White.Overlays;

public sealed class CrayonPreviewOverlay : Overlay
{
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities;

[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;

private readonly CrayonComponent _crayonComp;
private readonly EntityUid _crayonUid;
private string _currentState;

private Texture _tex;
private readonly SpriteSystem _sprite;

public CrayonPreviewOverlay(SpriteSystem sprite, CrayonComponent comp)
{
IoCManager.InjectDependencies(this);
_sprite = sprite;

_crayonComp = comp;
_crayonUid = comp.Owner;
_currentState = comp.SelectedState;
if (_proto.TryIndex<DecalPrototype>(_currentState, out var proto))
_tex = _sprite.Frame0(proto.Sprite);
else
_tex = Texture.Transparent;
}

protected override void Draw(in OverlayDrawArgs args)
{
if (!_entMan.EntityExists(_crayonUid) || // failsafe
_player.LocalEntity is not EntityUid playerUid ||
_entMan.HasComponent<HoldingDropComponent>(playerUid))
return;

var handle = args.WorldHandle;

if (_currentState != _crayonComp.SelectedState)
{
_currentState = _crayonComp.SelectedState;
if (_proto.TryIndex<DecalPrototype>(_currentState, out var proto))
_tex = _sprite.Frame0(proto.Sprite);
else
_tex = Texture.Transparent;
}

var mouseScreenPos = _input.MouseScreenPosition.Position;

var angle = _crayonComp.Angle - _eye.CurrentEye.Rotation;
var mouseMapPos = _eye.ScreenToMap(mouseScreenPos);
var playerMapPos = _entMan.GetComponent<TransformComponent>(playerUid).MapPosition;

float alpha = 0.6f;
if ((mouseMapPos.Position - playerMapPos.Position).LengthSquared() > SharedInteractionSystem.InteractionRangeSquared)
alpha = 0.1f;


#pragma warning disable RA0002 // ffs
handle.DrawTexture(_tex, mouseMapPos.Position - new Vector2(0.5f, 0.5f), angle, _crayonComp.Color.WithAlpha(alpha));
#pragma warning restore RA0002
}
}

2 changes: 2 additions & 0 deletions Content.Server/Crayon/CrayonComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Audio;

/* // WWDP EDIT - DEFUNCT - Merged into one shared CrayonComponent.
namespace Content.Server.Crayon
{
[RegisterComponent]
Expand All @@ -26,3 +27,4 @@ public sealed partial class CrayonComponent : SharedCrayonComponent
public bool DeleteEmpty = true;
}
}
*/
59 changes: 22 additions & 37 deletions Content.Server/Crayon/CrayonSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Content.Shared.Decals;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Movement.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
Expand All @@ -26,23 +27,26 @@ public sealed class CrayonSystem : SharedCrayonSystem
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrayonComponent, ComponentInit>(OnCrayonInit);
SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI);
SubscribeLocalEvent<CrayonComponent, CrayonColorMessage>(OnCrayonBoundUIColor);
// SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI); // WWDP EDIT - Moved to Shared.
// SubscribeLocalEvent<CrayonComponent, CrayonColorMessage>(OnCrayonBoundUIColor); // WWDP EDIT - Moved to Shared.
SubscribeLocalEvent<CrayonComponent, UseInHandEvent>(OnCrayonUse, before: new[] { typeof(FoodSystem) });
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(OnCrayonAfterInteract, after: new[] { typeof(FoodSystem) });
SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped);
SubscribeLocalEvent<CrayonComponent, ComponentGetState>(OnCrayonGetState);
// SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped); // WWDP EDIT - Moved to Shared.
// SubscribeLocalEvent<CrayonComponent, ComponentGetState>(OnCrayonGetState); // WWDP EDIT - DEFUNCT - Moved to using AutoState system.
}

/* WWDP EDIT - DEFUNCT - Moved to using AutoState system.
private static void OnCrayonGetState(EntityUid uid, CrayonComponent component, ref ComponentGetState args)
{
args.State = new CrayonComponentState(component.Color, component.SelectedState, component.Charges, component.Capacity);
}
*/

private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, AfterInteractEvent args)
{
Expand All @@ -66,10 +70,18 @@ private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, Aft
args.Handled = true;
return;
}

// WWDP EDIT START
Angle rot = 0f;
if (TryComp<InputMoverComponent>(args.User, out var mover))
{
rot = mover.TargetRelativeRotation;
}

if (!_decals.TryAddDecal(component.SelectedState, args.ClickLocation.Offset(new Vector2(-0.5f, -0.5f)), out _, component.Color, cleanable: true))
if (!_decals.TryAddDecal(component.SelectedState, args.ClickLocation.Offset(new Vector2(-0.5f, -0.5f)), out _, component.Color, rot + component.Angle + 0.01f, cleanable: true))
return;

// WWDP EDIT END

if (component.UseSound != null)
_audio.PlayPvs(component.UseSound, uid, AudioParams.Default.WithVariation(0.125f));

Expand All @@ -88,7 +100,7 @@ private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, Aft
if (component.DeleteEmpty && component.Charges <= 0)
UseUpCrayon(uid, args.User);
else
_uiSystem.ServerSendUiMessage(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
_uiSystem.ServerSendUiMessage(uid, CrayonComponent.CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState)); // WWDP EDIT
}

private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
Expand All @@ -97,39 +109,17 @@ private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEven
if (args.Handled)
return;

if (!_uiSystem.HasUi(uid, SharedCrayonComponent.CrayonUiKey.Key))
if (!_uiSystem.HasUi(uid, CrayonComponent.CrayonUiKey.Key)) // WWDP EDIT
{
return;
}

_uiSystem.TryToggleUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
_uiSystem.TryToggleUi(uid, CrayonComponent.CrayonUiKey.Key, args.User); // WWDP EDIT

_uiSystem.SetUiState(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color));
_uiSystem.SetUiState(uid, CrayonComponent.CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color)); // WWDP EDIT
args.Handled = true;
}

private void OnCrayonBoundUI(EntityUid uid, CrayonComponent component, CrayonSelectMessage args)
{
// Check if the selected state is valid
if (!_prototypeManager.TryIndex<DecalPrototype>(args.State, out var prototype) || !prototype.Tags.Contains("crayon"))
return;

component.SelectedState = args.State;

Dirty(uid, component);
}

private void OnCrayonBoundUIColor(EntityUid uid, CrayonComponent component, CrayonColorMessage args)
{
// you still need to ensure that the given color is a valid color
if (!component.SelectableColor || args.Color == component.Color)
return;

component.Color = args.Color;
Dirty(uid, component);

}

private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentInit args)
{
component.Charges = component.Capacity;
Expand All @@ -140,11 +130,6 @@ private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentIni
Dirty(uid, component);
}

private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args)
{
// TODO: Use the existing event.
_uiSystem.CloseUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User);
}

private void UseUpCrayon(EntityUid uid, EntityUid user)
{
Expand Down
7 changes: 6 additions & 1 deletion Content.Server/Hands/Systems/HandsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Robust.Shared.Serialization;
using Content.Shared._White.Hands;

namespace Content.Server.Hands.Systems
{
Expand Down Expand Up @@ -288,7 +290,10 @@ hands.ActiveHandEntity is not { } throwEnt ||
// This can grief the above event so we raise it afterwards
if (IsHolding(player, throwEnt, out _, hands) && !TryDrop(player, throwEnt, handsComp: hands))
return false;

// WWDP EDIT START
var deselEv = new HandDeselectedEvent(player); // because throwcode is serverside, the HandDeselectedEvent doesn't get raised on client.
RaiseNetworkEvent(new HandDeselectedNetworkCrutchWrap(GetNetEntity(throwEnt), GetNetEntity(player))); // This is the best i've came up with.
// WWDP EDIT END
_throwingSystem.TryThrow(ev.ItemUid, ev.Direction, ev.ThrowSpeed, ev.PlayerUid, compensateFriction: !HasComp<LandAtCursorComponent>(ev.ItemUid));

return true;
Expand Down
Loading

0 comments on commit efca951

Please sign in to comment.