Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
828a2dc
One year anniversary statue
RHSvenson Aug 19, 2025
1f95fcb
Revert to other description that I liked more
RHSvenson Aug 19, 2025
f7719e8
TransferInit
CringeCursed Aug 19, 2025
d59796d
ifuckinghateui
CringeCursed Aug 19, 2025
6ee5137
ehh
CringeCursed Aug 19, 2025
9845a4c
MakeTransferFromATMnotShit
CringeCursed Aug 19, 2025
eee58b6
ebalay
CringeCursed Aug 19, 2025
0027e42
revert rollback
Happyrobot33 Aug 19, 2025
206fdbb
fix
StarlightHost Aug 19, 2025
30ec442
Merge pull request #1399 from Happyrobot33/setup-correct-history-for-dev
StarlightHost Aug 19, 2025
f33f814
Update changelog for PR #1399 [skip ci]
github-actions[bot] Aug 19, 2025
a09e676
Merge pull request #1400 from ss14Starlight/hitscan_fix
Happyrobot33 Aug 19, 2025
edf70b3
Update changelog for PR #1400 [skip ci]
github-actions[bot] Aug 19, 2025
65a8355
fixes wizard to actually load (since it is a loadmap not a loadgrid a…
walksanatora Aug 19, 2025
68d57a0
Merge pull request #1401 from walksanatora/wizard-fix
Happyrobot33 Aug 19, 2025
00b9741
Update changelog for PR #1401 [skip ci]
github-actions[bot] Aug 19, 2025
d68fac5
fixes the infinite client-sided cheese that spawns from the wizard.
walksanatora Aug 20, 2025
7191617
de-indent
walksanatora Aug 20, 2025
86666c5
Merge pull request #1387 from CringeCursed/AtmTransfer
StarlightHost Aug 20, 2025
0f50501
Update changelog for PR #1387 [skip ci]
github-actions[bot] Aug 20, 2025
3727b9a
Merge pull request #1403 from walksanatora/no-client-cheese
Happyrobot33 Aug 20, 2025
779610c
Update changelog for PR #1403 [skip ci]
github-actions[bot] Aug 20, 2025
cb3e526
Merge pull request #1384 from RHSvenson/OneYearAnniversaryStatue
Happyrobot33 Aug 20, 2025
3c261b2
Update changelog for PR #1384 [skip ci]
github-actions[bot] Aug 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@
- changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
- all-globs-to-all-files: "!**/*.cs"

"Changes: C#":
- changed-files:
- any-glob-to-any-file: '**/*.cs'
7 changes: 4 additions & 3 deletions .github/workflows/auto-assign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ jobs:
"Changes: Sprites": ["BORTBORTBORTBORTBORT"],
"Changes: Map": ["PubliclyExecutedPig"],
"Changes: UI": ["ss14-Starlight"],
"Changes: Shaders": ["ss14-Starlight"],
"Changes: Audio": ["ss14-Starlight"],
"Changes: No C#": ["ss14-Starlight"],
"Changes: Shaders": ["ss14-Starlight, Happyrobot33, FoxxoTrystan"],
"Changes: Audio": ["ss14-Starlight, Happyrobot33, FoxxoTrystan"],
"Changes: No C#": ["ss14-Starlight, Happyrobot33, FoxxoTrystan"],
"Changes: C#": ["ss14-Starlight, Happyrobot33, FoxxoTrystan"],
};

const labels = context.payload.pull_request.labels.map(label => label.name);
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:

update-changelog:
name: Publish Changelogs
needs: build
# needs: build
runs-on: ubuntu-latest
environment: prod
steps:
Expand Down
32 changes: 32 additions & 0 deletions .github/workflows/target-branch-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Check PR Target Branch

on:
pull_request:
types: [opened, synchronize, reopened, edited]

jobs:
check-target-branch:
runs-on: ubuntu-latest

steps:
- name: Check if PR targets starlight-dev
run: |
SOURCE_BRANCH="${{ github.event.pull_request.head.ref }}"
TARGET_BRANCH="${{ github.event.pull_request.base.ref }}"
echo "PR from: $SOURCE_BRANCH -> $TARGET_BRANCH"

# Allow starlight-dev to starlight PRs in both directions
if [[ ("$SOURCE_BRANCH" == "starlight-dev" && "$TARGET_BRANCH" == "starlight") ||
("$SOURCE_BRANCH" == "starlight" && "$TARGET_BRANCH" == "starlight-dev") ]]; then
echo "Allowed: PR between starlight-dev and starlight branches"
exit 0
fi

# For all other PRs, require starlight-dev as target
if [ "$TARGET_BRANCH" != "starlight-dev" ]; then
echo "Error: PR must target 'starlight-dev' branch, but targets '$TARGET_BRANCH'"
echo "Please change the target branch to 'starlight-dev'"
exit 1
else
echo "Success: PR correctly targets 'starlight-dev' branch"
fi
9 changes: 6 additions & 3 deletions Content.Client/Actions/ActionsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,12 @@ private void OnWorldTargetAttempt(Entity<WorldTargetActionComponent> ent, ref Ac

private void OnEntityTargetAttempt(Entity<EntityTargetActionComponent> ent, ref ActionTargetAttemptEvent args)
{
if (args.Handled || args.Input.EntityUid is not { Valid: true } entity)
if (args.Handled)
return;

args.Handled = true;

if (args.Input.EntityUid is not { Valid: true } entity)
return;

// let world target component handle it
Expand All @@ -345,8 +350,6 @@ private void OnEntityTargetAttempt(Entity<EntityTargetActionComponent> ent, ref
return;
}

args.Handled = true;

var action = args.Action;
var user = args.User;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Control
xmlns="https://spacestation14.io"
xmlns:viewport="clr-namespace:Content.Client.Viewport"
MouseFilter="Stop">
<PanelContainer StyleClasses="BackgroundDark" Name="AdminCameraWindowRoot" Access="Public">
<BoxContainer Orientation="Vertical" Access="Public">
<!-- Camera -->
<Control VerticalExpand="True" Name="CameraViewBox">
<viewport:ScalingViewport Name="CameraView"
MinSize="100 100"
MouseFilter="Ignore" />
</Control>
<!-- Controller buttons -->
<BoxContainer Orientation="Horizontal" Margin="5 5 5 5">
<Button StyleClasses="OpenRight" Name="FollowButton" HorizontalExpand="True" Access="Public" Text="{Loc 'admin-camera-window-follow'}" />
<Button StyleClasses="OpenLeft" Name="PopControl" HorizontalExpand="True" Access="Public" Text="{Loc 'admin-camera-window-pop-out'}" />
</BoxContainer>
</BoxContainer>
</PanelContainer>
</Control>
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System.Numerics;
using Content.Client.Eye;
using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Timing;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;

namespace Content.Client.Administration.UI.AdminCamera;

[GenerateTypedNameReferences]
public sealed partial class AdminCameraControl : Control
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IClientGameTiming _timing = default!;

public event Action? OnFollow;
public event Action? OnPopoutControl;

private readonly EyeLerpingSystem _eyeLerpingSystem;
private readonly FixedEye _defaultEye = new();
private AdminCameraEuiState? _nextState;

private const float MinimumZoom = 0.1f;
private const float MaximumZoom = 2.0f;

public EntityUid? CurrentCamera;
public float Zoom = 1.0f;

public bool IsPoppedOut;

public AdminCameraControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);

_eyeLerpingSystem = _entManager.System<EyeLerpingSystem>();

CameraView.Eye = _defaultEye;

FollowButton.OnPressed += _ => OnFollow?.Invoke();
PopControl.OnPressed += _ => OnPopoutControl?.Invoke();
CameraView.OnResized += OnResized;
}

private new void OnResized()
{
var width = Math.Max(CameraView.PixelWidth, (int)Math.Floor(CameraView.MinWidth));
var height = Math.Max(CameraView.PixelHeight, (int)Math.Floor(CameraView.MinHeight));

CameraView.ViewportSize = new Vector2i(width, height);
}

protected override void MouseWheel(GUIMouseWheelEventArgs args)
{
base.MouseWheel(args);

if (CameraView.Eye == null)
return;

Zoom = Math.Clamp(Zoom - args.Delta.Y * 0.15f * Zoom, MinimumZoom, MaximumZoom);
CameraView.Eye.Zoom = new Vector2(Zoom, Zoom);
args.Handle();
}

public void SetState(AdminCameraEuiState state)
{
_nextState = state;
}

// I know that this is awful, but I copied this from the solution editor anyways.
// This is needed because EUIs update before the gamestate is applied, which means it will fail to get the uid from the net entity.
// The suggestion from the comment in the solution editor saying to use a BUI is not ideal either:
// - We would need to bind the UI to an entity, but with how BUIs currently work we cannot open it in the same tick as we spawn that entity on the server.
// - We want the UI opened by the user session, not by their currently attached entity. Otherwise it would close in cases where admins move from one entity to another, for example when ghosting.
protected override void FrameUpdate(FrameEventArgs args)
{
if (_nextState == null || _timing.LastRealTick < _nextState.Tick) // make sure the last gamestate has been applied
return;

if (!_entManager.TryGetEntity(_nextState.Camera, out var cameraUid))
return;

if (CurrentCamera == null)
{
_eyeLerpingSystem.AddEye(cameraUid.Value);
CurrentCamera = cameraUid;
}
else if (CurrentCamera != cameraUid)
{
_eyeLerpingSystem.RemoveEye(CurrentCamera.Value);
_eyeLerpingSystem.AddEye(cameraUid.Value);
CurrentCamera = cameraUid;
}

if (_entManager.TryGetComponent<EyeComponent>(CurrentCamera, out var eye))
CameraView.Eye = eye.Eye ?? _defaultEye;
}
}
117 changes: 117 additions & 0 deletions Content.Client/Administration/UI/AdminCamera/AdminCameraEui.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Numerics;
using Content.Client.Eui;
using Content.Shared.Administration;
using Content.Shared.Eui;
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;

namespace Content.Client.Administration.UI.AdminCamera;

/// <summary>
/// Admin Eui for opening a viewport window to observe entities.
/// Use the "Open Camera" admin verb or the "camera" command to open.
/// </summary>
[UsedImplicitly]
public sealed partial class AdminCameraEui : BaseEui
{
private readonly AdminCameraWindow _window;
private readonly AdminCameraControl _control;

// If not null the camera is in "popped out" mode and is in an external window.
private OSWindow? _OSWindow;

// The last location the window was located at in game.
// Is used for getting knowing where to "pop in" external windows.
private Vector2 _lastLocation;

public AdminCameraEui()
{
_window = new AdminCameraWindow();
_control = new AdminCameraControl();

_window.Contents.AddChild(_control);

_control.OnFollow += () => SendMessage(new AdminCameraFollowMessage());
_window.OnClose += () =>
{
if (!_control.IsPoppedOut)
SendMessage(new CloseEuiMessage());
};

_control.OnPopoutControl += () =>
{
if (_control.IsPoppedOut)
PopIn();
else
PopOut();
};
}

// Pop the window out into an external OS window
private void PopOut()
{
_lastLocation = _window.Position;

// TODO: When there is a way to have a minimum window size, enforce something!
_OSWindow = new OSWindow
{
SetSize = _window.Size,
Title = _window.Title ?? Loc.GetString("admin-camera-window-title-placeholder"),
};

_OSWindow.Show();

if (_OSWindow.Root == null)
return;

_control.Orphan();
_OSWindow.Root.AddChild(_control);

_OSWindow.Closed += () =>
{
if (_control.IsPoppedOut)
SendMessage(new CloseEuiMessage());
};

_control.IsPoppedOut = true;
_control.PopControl.Text = Loc.GetString("admin-camera-window-pop-in");

_window.Close();
}

// Pop the window back into the in game window.
private void PopIn()
{
_control.Orphan();
_window.Contents.AddChild(_control);

_window.Open(_lastLocation);

_control.IsPoppedOut = false;
_control.PopControl.Text = Loc.GetString("admin-camera-window-pop-out");

_OSWindow?.Close();
_OSWindow = null;
}

public override void Opened()
{
base.Opened();
_window.OpenCentered();
}

public override void Closed()
{
base.Closed();
_window.Close();
}

public override void HandleState(EuiStateBase baseState)
{
if (baseState is not AdminCameraEuiState state)
return;

_window.SetState(state);
_control.SetState(state);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc admin-camera-window-title-placeholder}"
SetSize="425 550"
MinSize="200 225"
Name="Window">
</DefaultWindow>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;

namespace Content.Client.Administration.UI.AdminCamera;

[GenerateTypedNameReferences]
public sealed partial class AdminCameraWindow : DefaultWindow
{
public AdminCameraWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);

ContentsContainer.Margin = new Thickness(5, 0, 5, 0);
}

public void SetState(AdminCameraEuiState state)
{
Title = Loc.GetString("admin-camera-window-title", ("name", state.Name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<Button Name="FreezeAndMuteToggleButton" Text="{Loc player-panel-freeze-and-mute}" Disabled="True"/>
<Button Name="BanButton" Text="{Loc player-panel-ban}" Disabled="True"/>
<controls:ConfirmButton Name="RejuvenateButton" Text="{Loc player-panel-rejuvenate}" Disabled="True"/>
<Button Name="CameraButton" Text="{Loc player-panel-camera}" Disabled="True"/>
</GridContainer>
</BoxContainer>
</BoxContainer>
Expand Down
Loading
Loading