mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
414be58480 | ||
|
|
36ee8429c5 | ||
|
|
eaa5cfec1f | ||
|
|
1b4e3dc602 | ||
|
|
368918d46a | ||
|
|
04efdf82f6 | ||
|
|
ac50abeab8 | ||
|
|
c9dbb1c9a1 |
@@ -312,6 +312,3 @@ Resources/MapImages
|
||||
|
||||
# Changelog package lock
|
||||
package-lock.json
|
||||
|
||||
# Discord Bot Config
|
||||
link-config.json
|
||||
@@ -8,14 +8,12 @@ using Content.Shared.CCVar;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.SSDIndicator; // DeltaV - SSD time indicator
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing; // DeltaV - SSD time indicator
|
||||
|
||||
namespace Content.Client.Administration;
|
||||
|
||||
@@ -28,7 +26,6 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
private readonly SharedRoleSystem _roles;
|
||||
private readonly IPrototypeManager _prototypeManager;
|
||||
private readonly IGameTiming _timing; // DeltaV - Add timing
|
||||
private readonly Font _font;
|
||||
private readonly Font _fontBold;
|
||||
private AdminOverlayAntagFormat _overlayFormat;
|
||||
@@ -56,8 +53,7 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
IUserInterfaceManager userInterfaceManager,
|
||||
IConfigurationManager config,
|
||||
SharedRoleSystem roles,
|
||||
IPrototypeManager prototypeManager,
|
||||
IGameTiming timing) // DeltaV - Add timing
|
||||
IPrototypeManager prototypeManager)
|
||||
{
|
||||
_system = system;
|
||||
_entityManager = entityManager;
|
||||
@@ -66,7 +62,6 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
_userInterfaceManager = userInterfaceManager;
|
||||
_roles = roles;
|
||||
_prototypeManager = prototypeManager;
|
||||
_timing = timing; // DeltaV - Add timing
|
||||
ZIndex = 200;
|
||||
// Setting these to a specific ttf would break the antag symbols
|
||||
_font = resourceCache.NotoStack();
|
||||
@@ -236,17 +231,6 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
// DeltaV - SSD Time START
|
||||
if (_entityManager.TryGetComponent<SSDIndicatorComponent>(entity, out var ssdIndicator) && ssdIndicator.IsSSD)
|
||||
{
|
||||
color = Color.MediumPurple;
|
||||
color.A = alpha;
|
||||
var ssdText = Loc.GetString("admin-overlay-ssd-time", ("time", (_timing.CurTime - ssdIndicator.SsdSince).ToString("%hh':'mm':'ss")));
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, ssdText, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
// DeltaV END
|
||||
|
||||
// Determine antag symbol
|
||||
string? symbol;
|
||||
switch (_overlaySymbolStyle)
|
||||
|
||||
@@ -5,7 +5,6 @@ using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing; // DeltaV - SSD time indicator
|
||||
|
||||
namespace Content.Client.Administration.Systems
|
||||
{
|
||||
@@ -20,7 +19,6 @@ namespace Content.Client.Administration.Systems
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!; // DeltaV - added for SSD time indicator
|
||||
|
||||
private AdminNameOverlay _adminNameOverlay = default!;
|
||||
|
||||
@@ -38,8 +36,7 @@ namespace Content.Client.Administration.Systems
|
||||
_userInterfaceManager,
|
||||
_configurationManager,
|
||||
_roles,
|
||||
_proto,
|
||||
_timing); // DeltaV - Add timing
|
||||
_proto);
|
||||
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client._DV.AccountLinking; // DeltaV
|
||||
using Content.Client.UserInterface.Systems.EscapeMenu;
|
||||
using Content.Client.UserInterface.Systems.Guidebook;
|
||||
using Content.Shared.CCVar;
|
||||
@@ -49,18 +48,6 @@ namespace Content.Client.Info
|
||||
changelogButton.OnPressed += args => UserInterfaceManager.GetUIController<ChangelogUIController>().ToggleWindow();
|
||||
buttons.AddChild(changelogButton);
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
var linkAccount = UserInterfaceManager.GetUIController<LinkAccountUIController>();
|
||||
var linkAccountButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("ui-link-discord-account"),
|
||||
};
|
||||
linkAccountButton.OnPressed += _ => linkAccount.ToggleWindow();
|
||||
buttons.AddChild(linkAccountButton);
|
||||
|
||||
AddInfoButton("ui-patreon", CCVars.InfoLinksPatreon);
|
||||
// END DeltaV
|
||||
|
||||
void AddInfoButton(string loc, CVarDef<string> cVar)
|
||||
{
|
||||
var button = new Button { Text = Loc.GetString(loc) };
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Client._DV.AccountLinking; // DeltaV
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
@@ -63,7 +62,6 @@ namespace Content.Client.IoC
|
||||
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
|
||||
collection.Register<TitleWindowManager>();
|
||||
collection.Register<ClientsidePlaytimeTrackingManager>();
|
||||
collection.Register<LinkAccountManager>(); // DeltaV - Discord Linking
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Client._DV.AccountLinking; // DeltaV
|
||||
using Content.Client.Audio;
|
||||
using Content.Client.GameTicking.Managers;
|
||||
using Content.Client.LateJoin;
|
||||
@@ -30,7 +29,6 @@ namespace Content.Client.Lobby
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IVoteManager _voteManager = default!;
|
||||
[Dependency] private readonly ClientsidePlaytimeTrackingManager _playtimeTracking = default!;
|
||||
[Dependency] private readonly LinkAccountManager _linkAccount = default!; // DeltaV - Discord Linking
|
||||
|
||||
private ClientGameTicker _gameTicker = default!;
|
||||
private ContentAudioSystem _contentAudioSystem = default!;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Client._DV.AccountLinking; // DeltaV
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Humanoid;
|
||||
using Content.Client.Inventory;
|
||||
@@ -39,7 +38,6 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly JobRequirementsManager _requirements = default!;
|
||||
[Dependency] private readonly MarkingManager _markings = default!;
|
||||
[Dependency] private readonly LinkAccountManager _linkAccount = default!; // DeltaV - Discord Account Linking
|
||||
[UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||
[UISystemDependency] private readonly ClientInventorySystem _inventory = default!;
|
||||
[UISystemDependency] private readonly StationSpawningSystem _spawn = default!;
|
||||
@@ -77,8 +75,6 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
_configurationManager.OnValueChanged(CCVars.GameRoleLoadoutTimers, _ => RefreshProfileEditor());
|
||||
|
||||
_configurationManager.OnValueChanged(CCVars.GameRoleWhitelist, _ => RefreshProfileEditor());
|
||||
|
||||
_linkAccount.Updated += RefreshProfileEditor; // DeltaV - Discord Account Linking
|
||||
}
|
||||
|
||||
private LobbyCharacterPreviewPanel? GetLobbyPreview()
|
||||
|
||||
@@ -21,8 +21,11 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
|
||||
_window = this.CreateWindow<SignalTimerWindow>();
|
||||
_window.OnStartTimer += StartTimer;
|
||||
_window.OnCurrentTextChanged += OnTextChanged;
|
||||
_window.OnCurrentDelayMinutesChanged += OnDelayChanged;
|
||||
_window.OnCurrentDelaySecondsChanged += OnDelayChanged;
|
||||
// Begin Monolith
|
||||
// _window.OnCurrentDelayMinutesChanged += OnDelayChanged;
|
||||
// _window.OnCurrentDelaySecondsChanged += OnDelayChanged;
|
||||
_window.OnCurrentDelayChanged += OnDelayChanged;
|
||||
// End Monolith
|
||||
}
|
||||
|
||||
public void StartTimer()
|
||||
@@ -35,11 +38,11 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
|
||||
SendMessage(new SignalTimerTextChangedMessage(newText));
|
||||
}
|
||||
|
||||
private void OnDelayChanged(string newDelay)
|
||||
private void OnDelayChanged(TimeSpan newDelay) // Monolith - Change from string to TimeSpan
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
SendMessage(new SignalTimerDelayChangedMessage(_window.GetDelay()));
|
||||
SendMessage(new SignalTimerDelayChangedMessage(newDelay)); // Mono
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,8 +57,11 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
|
||||
return;
|
||||
|
||||
_window.SetCurrentText(cast.CurrentText);
|
||||
_window.SetCurrentDelayMinutes(cast.CurrentDelayMinutes);
|
||||
_window.SetCurrentDelaySeconds(cast.CurrentDelaySeconds);
|
||||
// Begin Monolith
|
||||
// _window.SetCurrentDelayMinutes(cast.CurrentDelayMinutes);
|
||||
// _window.SetCurrentDelaySeconds(cast.CurrentDelaySeconds);
|
||||
_window.SetCurrentDelay(cast.CurrentDelay);
|
||||
// End Monolith
|
||||
_window.SetShowText(cast.ShowText);
|
||||
_window.SetTriggerTime(cast.TriggerTime);
|
||||
_window.SetTimerStarted(cast.TimerStarted);
|
||||
|
||||
@@ -7,10 +7,14 @@
|
||||
</BoxContainer>
|
||||
<BoxContainer Name="DelayEdit" Orientation="Horizontal">
|
||||
<Label Name="CurrentDelay" Text="{Loc signal-timer-menu-delay}" />
|
||||
<!-- Mono: Changed from integer MM:SS to float seconds
|
||||
<LineEdit Name="CurrentDelayEditMinutes" MinWidth="32" />
|
||||
<Label Name="Colon" Text=":" />
|
||||
<LineEdit Name="CurrentDelayEditSeconds" MinWidth="32" />
|
||||
<Label Name="DelayInfo" Text=" (mm:ss)" />
|
||||
-->
|
||||
<FloatSpinBox Name="CurrentDelayEdit" MinWidth="32" />
|
||||
<Label Text="s" />
|
||||
</BoxContainer>
|
||||
<Button Name="StartTimer" Text="{Loc signal-timer-menu-start}" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -15,8 +15,11 @@ public sealed partial class SignalTimerWindow : DefaultWindow
|
||||
private const int MaxTextLength = 5;
|
||||
|
||||
public event Action<string>? OnCurrentTextChanged;
|
||||
public event Action<string>? OnCurrentDelayMinutesChanged;
|
||||
public event Action<string>? OnCurrentDelaySecondsChanged;
|
||||
// Begin Monolith
|
||||
// public event Action<string>? OnCurrentDelayMinutesChanged;
|
||||
// public event Action<string>? OnCurrentDelaySecondsChanged;
|
||||
public event Action<TimeSpan>? OnCurrentDelayChanged;
|
||||
// End Monolith
|
||||
|
||||
private TimeSpan? _triggerTime;
|
||||
|
||||
@@ -30,8 +33,11 @@ public sealed partial class SignalTimerWindow : DefaultWindow
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
CurrentTextEdit.OnTextChanged += e => OnCurrentTextChange(e.Text);
|
||||
CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text);
|
||||
CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text);
|
||||
// Begin Monolith
|
||||
// CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text);
|
||||
// CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text);
|
||||
CurrentDelayEdit.OnValueChanged += e => CurrentDelayChange(TimeSpan.FromSeconds(e.Value));
|
||||
// End Monolith
|
||||
StartTimer.OnPressed += _ => StartTimerWeh();
|
||||
}
|
||||
|
||||
@@ -77,81 +83,93 @@ public sealed partial class SignalTimerWindow : DefaultWindow
|
||||
OnCurrentTextChanged?.Invoke(text);
|
||||
}
|
||||
|
||||
public void OnCurrentDelayMinutesChange(string text)
|
||||
// Begin Monolith
|
||||
// public void OnCurrentDelayMinutesChange(string text)
|
||||
// {
|
||||
// List<char> toRemove = new();
|
||||
|
||||
// foreach (var a in text)
|
||||
// {
|
||||
// if (!char.IsDigit(a))
|
||||
// toRemove.Add(a);
|
||||
// }
|
||||
|
||||
// foreach (var a in toRemove)
|
||||
// {
|
||||
// CurrentDelayEditMinutes.Text = text.Replace(a.ToString(),"");
|
||||
// }
|
||||
|
||||
// if (CurrentDelayEditMinutes.Text == "")
|
||||
// return;
|
||||
|
||||
// while (CurrentDelayEditMinutes.Text[0] == '0' && CurrentDelayEditMinutes.Text.Length > 2)
|
||||
// {
|
||||
// CurrentDelayEditMinutes.Text = CurrentDelayEditMinutes.Text.Remove(0, 1);
|
||||
// }
|
||||
|
||||
// if (CurrentDelayEditMinutes.Text.Length > 2)
|
||||
// {
|
||||
// CurrentDelayEditMinutes.Text = CurrentDelayEditMinutes.Text.Remove(2);
|
||||
// }
|
||||
// OnCurrentDelayMinutesChanged?.Invoke(CurrentDelayEditMinutes.Text);
|
||||
// }
|
||||
|
||||
// public void OnCurrentDelaySecondsChange(string text)
|
||||
// {
|
||||
// List<char> toRemove = new();
|
||||
|
||||
// foreach (var a in text)
|
||||
// {
|
||||
// if (!char.IsDigit(a))
|
||||
// toRemove.Add(a);
|
||||
// }
|
||||
|
||||
// foreach (var a in toRemove)
|
||||
// {
|
||||
// CurrentDelayEditSeconds.Text = text.Replace(a.ToString(), "");
|
||||
// }
|
||||
|
||||
// if (CurrentDelayEditSeconds.Text == "")
|
||||
// return;
|
||||
|
||||
// while (CurrentDelayEditSeconds.Text[0] == '0' && CurrentDelayEditSeconds.Text.Length > 2)
|
||||
// {
|
||||
// CurrentDelayEditSeconds.Text = CurrentDelayEditSeconds.Text.Remove(0, 1);
|
||||
// }
|
||||
|
||||
// if (CurrentDelayEditSeconds.Text.Length > 2)
|
||||
// {
|
||||
// CurrentDelayEditSeconds.Text = CurrentDelayEditSeconds.Text.Remove(2);
|
||||
// }
|
||||
// OnCurrentDelaySecondsChanged?.Invoke(CurrentDelayEditSeconds.Text);
|
||||
// }
|
||||
|
||||
public void CurrentDelayChange(TimeSpan newValue)
|
||||
{
|
||||
List<char> toRemove = new();
|
||||
|
||||
foreach (var a in text)
|
||||
{
|
||||
if (!char.IsDigit(a))
|
||||
toRemove.Add(a);
|
||||
}
|
||||
|
||||
foreach (var a in toRemove)
|
||||
{
|
||||
CurrentDelayEditMinutes.Text = text.Replace(a.ToString(),"");
|
||||
}
|
||||
|
||||
if (CurrentDelayEditMinutes.Text == "")
|
||||
return;
|
||||
|
||||
while (CurrentDelayEditMinutes.Text[0] == '0' && CurrentDelayEditMinutes.Text.Length > 2)
|
||||
{
|
||||
CurrentDelayEditMinutes.Text = CurrentDelayEditMinutes.Text.Remove(0, 1);
|
||||
}
|
||||
|
||||
if (CurrentDelayEditMinutes.Text.Length > 2)
|
||||
{
|
||||
CurrentDelayEditMinutes.Text = CurrentDelayEditMinutes.Text.Remove(2);
|
||||
}
|
||||
OnCurrentDelayMinutesChanged?.Invoke(CurrentDelayEditMinutes.Text);
|
||||
}
|
||||
|
||||
public void OnCurrentDelaySecondsChange(string text)
|
||||
{
|
||||
List<char> toRemove = new();
|
||||
|
||||
foreach (var a in text)
|
||||
{
|
||||
if (!char.IsDigit(a))
|
||||
toRemove.Add(a);
|
||||
}
|
||||
|
||||
foreach (var a in toRemove)
|
||||
{
|
||||
CurrentDelayEditSeconds.Text = text.Replace(a.ToString(), "");
|
||||
}
|
||||
|
||||
if (CurrentDelayEditSeconds.Text == "")
|
||||
return;
|
||||
|
||||
while (CurrentDelayEditSeconds.Text[0] == '0' && CurrentDelayEditSeconds.Text.Length > 2)
|
||||
{
|
||||
CurrentDelayEditSeconds.Text = CurrentDelayEditSeconds.Text.Remove(0, 1);
|
||||
}
|
||||
|
||||
if (CurrentDelayEditSeconds.Text.Length > 2)
|
||||
{
|
||||
CurrentDelayEditSeconds.Text = CurrentDelayEditSeconds.Text.Remove(2);
|
||||
}
|
||||
OnCurrentDelaySecondsChanged?.Invoke(CurrentDelayEditSeconds.Text);
|
||||
OnCurrentDelayChanged?.Invoke(newValue);
|
||||
}
|
||||
// End Monolith
|
||||
|
||||
public void SetCurrentText(string text)
|
||||
{
|
||||
CurrentTextEdit.Text = text;
|
||||
}
|
||||
// Begin Monolith
|
||||
// public void SetCurrentDelayMinutes(string delay)
|
||||
// {
|
||||
// CurrentDelayEditMinutes.Text = delay;
|
||||
// }
|
||||
|
||||
public void SetCurrentDelayMinutes(string delay)
|
||||
// public void SetCurrentDelaySeconds(string delay)
|
||||
// {
|
||||
// CurrentDelayEditSeconds.Text = delay;
|
||||
// }
|
||||
|
||||
public void SetCurrentDelay(TimeSpan delay)
|
||||
{
|
||||
CurrentDelayEditMinutes.Text = delay;
|
||||
CurrentDelayEdit.Value = (float)delay.TotalSeconds;
|
||||
}
|
||||
|
||||
public void SetCurrentDelaySeconds(string delay)
|
||||
{
|
||||
CurrentDelayEditSeconds.Text = delay;
|
||||
}
|
||||
|
||||
// End Monolith
|
||||
public void SetShowText(bool showTime)
|
||||
{
|
||||
TextEdit.Visible = showTime;
|
||||
@@ -176,8 +194,10 @@ public sealed partial class SignalTimerWindow : DefaultWindow
|
||||
public void SetHasAccess(bool hasAccess)
|
||||
{
|
||||
CurrentTextEdit.Editable = hasAccess;
|
||||
CurrentDelayEditMinutes.Editable = hasAccess;
|
||||
CurrentDelayEditSeconds.Editable = hasAccess;
|
||||
// Begin Monolith
|
||||
// CurrentDelayEditMinutes.Editable = hasAccess;
|
||||
// CurrentDelayEditSeconds.Editable = hasAccess;
|
||||
// End Monolith
|
||||
StartTimer.Disabled = !hasAccess;
|
||||
}
|
||||
|
||||
@@ -186,10 +206,13 @@ public sealed partial class SignalTimerWindow : DefaultWindow
|
||||
/// </summary>
|
||||
public TimeSpan GetDelay()
|
||||
{
|
||||
if (!double.TryParse(CurrentDelayEditMinutes.Text, out var minutes))
|
||||
minutes = 0;
|
||||
if (!double.TryParse(CurrentDelayEditSeconds.Text, out var seconds))
|
||||
seconds = 0;
|
||||
return TimeSpan.FromMinutes(minutes) + TimeSpan.FromSeconds(seconds);
|
||||
// Begin Monolith
|
||||
// if (!double.TryParse(CurrentDelayEditMinutes.Text, out var minutes))
|
||||
// minutes = 0;
|
||||
// if (!double.TryParse(CurrentDelayEditSeconds.Text, out var seconds))
|
||||
// seconds = 0;
|
||||
// return TimeSpan.FromMinutes(minutes) + TimeSpan.FromSeconds(seconds);
|
||||
return TimeSpan.FromSeconds(CurrentDelayEdit.Value);
|
||||
// End Monolith
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Client._DV.AccountLinking; // DeltaV
|
||||
using Content.Client.UserInterface.Screens;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared._EE.CCVars; // EE - chat stack
|
||||
@@ -18,7 +17,6 @@ public sealed partial class MiscTab : Control
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly LinkAccountManager _linkAccount = default!; // DeltaV - Discord Account Linking
|
||||
|
||||
public MiscTab()
|
||||
{
|
||||
@@ -50,7 +48,7 @@ public sealed partial class MiscTab : Control
|
||||
|
||||
// Channel can be null in replays so.
|
||||
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
|
||||
ShowOocPatronColor.Visible = _linkAccount.Tier != null; // DeltaV - Discord Account Linking
|
||||
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel?.UserData.PatronTier is { };
|
||||
|
||||
Control.AddOptionDropDown(CVars.InterfaceTheme, DropDownHudTheme, themeEntries);
|
||||
Control.AddOptionDropDown(CCVars.UILayout, DropDownHudLayout, layoutEntries);
|
||||
|
||||
@@ -19,7 +19,6 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly Shared.SSDIndicator.SSDIndicatorSystem _shared = default!; // DeltaV - SSD Recency, don't want to rename the upstream class
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -36,26 +35,13 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
!HasComp<ActiveNPCComponent>(uid) &&
|
||||
HasComp<MindExaminableComponent>(uid))
|
||||
{
|
||||
// Begin DeltaV Additions
|
||||
// Begin DeltaV Addition
|
||||
var ev = new ShowSSDIndicatorEvent();
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
if (ev.Hidden)
|
||||
return;
|
||||
|
||||
// SSD Recency Indicator
|
||||
var stage = _shared.GetStage(new Entity<SSDIndicatorComponent>(uid, component));
|
||||
var icon = stage switch
|
||||
{
|
||||
SsdStage.VeryRecent => component.VeryRecentIcon,
|
||||
SsdStage.Recent => component.RecentIcon,
|
||||
SsdStage.Cryoable => component.Icon,
|
||||
_ => throw new InvalidOperationException($"{ToPrettyString(uid)} has an invalid SSD stage {stage}."),
|
||||
};
|
||||
|
||||
args.StatusIcons.Add(_prototype.Index(icon));
|
||||
// End DeltaV Additions
|
||||
|
||||
// args.StatusIcons.Add(_prototype.Index(component.Icon)); // DeltaV - commented out. status icon now added above
|
||||
// End DeltaV Addition
|
||||
args.StatusIcons.Add(_prototype.Index(component.Icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using Content.Shared._DV.AccountLinking;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Client._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountManager : IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
private readonly List<SharedPatron> _allPatrons = [];
|
||||
|
||||
public SharedPatronTier? Tier { get; private set; }
|
||||
public bool Linked { get; private set; }
|
||||
|
||||
public event Action<Guid>? CodeReceived;
|
||||
public event Action? Updated;
|
||||
|
||||
private void OnCode(LinkAccountCodeMsg message)
|
||||
{
|
||||
CodeReceived?.Invoke(message.Code);
|
||||
}
|
||||
|
||||
private void OnStatus(LinkAccountStatusMsg ev)
|
||||
{
|
||||
Tier = ev.Patron?.Tier;
|
||||
Linked = ev.Patron?.Linked ?? false;
|
||||
Updated?.Invoke();
|
||||
}
|
||||
|
||||
private void OnPatronList(PatronListMsg ev)
|
||||
{
|
||||
_allPatrons.Clear();
|
||||
_allPatrons.AddRange(ev.Patrons);
|
||||
}
|
||||
|
||||
public IReadOnlyList<SharedPatron> GetPatrons()
|
||||
{
|
||||
return _allPatrons;
|
||||
}
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_net.RegisterNetMessage<LinkAccountCodeMsg>(OnCode);
|
||||
_net.RegisterNetMessage<LinkAccountRequestMsg>();
|
||||
_net.RegisterNetMessage<LinkAccountStatusMsg>(OnStatus);
|
||||
_net.RegisterNetMessage<PatronListMsg>(OnPatronList);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
using Content.Shared._DV.AccountLinking;
|
||||
|
||||
namespace Content.Client._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountSystem : EntitySystem;
|
||||
@@ -1,107 +0,0 @@
|
||||
using Content.Client.Lobby.UI;
|
||||
using Content.Client.Message;
|
||||
using Content.Shared._DV.CCVars;
|
||||
using Content.Shared._DV.AccountLinking;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IClipboardManager _clipboard = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly LinkAccountManager _linkAccount = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IUriOpener _uriOpener = default!;
|
||||
|
||||
private LinkAccountWindow? _window;
|
||||
private TimeSpan _disableUntil;
|
||||
|
||||
private Guid _code;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_linkAccount.CodeReceived += OnCode;
|
||||
_linkAccount.Updated += OnUpdated;
|
||||
}
|
||||
|
||||
private void OnCode(Guid code)
|
||||
{
|
||||
_code = code;
|
||||
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.CopyButton.Disabled = false;
|
||||
}
|
||||
|
||||
private void OnUpdated()
|
||||
{
|
||||
if (UIManager.ActiveScreen is not LobbyGui gui)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
public void ToggleWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
{
|
||||
_window = new LinkAccountWindow();
|
||||
_window.OnClose += () => _window = null;
|
||||
_window.Label.SetMarkupPermissive($"{Loc.GetString("ui-link-discord-account-text")}");
|
||||
if (_linkAccount.Linked)
|
||||
_window.Label.SetMarkupPermissive($"{Loc.GetString("ui-link-discord-account-already-linked")}\n\n{Loc.GetString("ui-link-discord-account-text")}");
|
||||
|
||||
_window.CopyButton.OnPressed += _ =>
|
||||
{
|
||||
_clipboard.SetText(_code.ToString());
|
||||
_window.CopyButton.Text = Loc.GetString("ui-link-discord-account-copied");
|
||||
_window.CopyButton.Disabled = true;
|
||||
_disableUntil = _timing.RealTime.Add(TimeSpan.FromSeconds(3));
|
||||
};
|
||||
|
||||
var messageLink = _config.GetCVar(DCCVars.DiscordAccountLinkingMessageLink);
|
||||
if (string.IsNullOrEmpty(messageLink))
|
||||
{
|
||||
_window.LinkButton.Visible = false;
|
||||
_window.CopyButton.RemoveStyleClass("OpenRight");
|
||||
}
|
||||
else
|
||||
{
|
||||
_window.LinkButton.Visible = true;
|
||||
_window.LinkButton.OnPressed += _ => _uriOpener.OpenUri(messageLink);
|
||||
_window.CopyButton.AddStyleClass("OpenRight");
|
||||
}
|
||||
|
||||
_window.OpenCentered();
|
||||
|
||||
if (_code == default)
|
||||
_window.CopyButton.Disabled = true;
|
||||
|
||||
_net.ClientSendMessage(new LinkAccountRequestMsg());
|
||||
return;
|
||||
}
|
||||
|
||||
_window.Close();
|
||||
_window = null;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
var time = _timing.RealTime;
|
||||
if (_disableUntil != default && time > _disableUntil)
|
||||
{
|
||||
_disableUntil = default;
|
||||
_window.CopyButton.Text = Loc.GetString("ui-link-discord-account-copy");
|
||||
_window.CopyButton.Disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<linkAccount:LinkAccountWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:linkAccount="clr-namespace:Content.Client._DV.AccountLinking"
|
||||
Title="{Loc 'ui-link-discord-account'}">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<RichTextLabel Name="Label" Access="Public" Margin="0 0 0 5" />
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center"
|
||||
HorizontalExpand="True">
|
||||
<Button Name="CopyButton" Access="Public" StyleClasses="OpenRight"
|
||||
Text="{Loc 'ui-link-discord-account-copy'}" HorizontalExpand="True" />
|
||||
<Button Name="LinkButton" Access="Public" StyleClasses="OpenLeft"
|
||||
Text="{Loc 'ui-link-discord-account-open-channel'}"
|
||||
HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</linkAccount:LinkAccountWindow>
|
||||
@@ -1,15 +0,0 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._DV.AccountLinking;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class LinkAccountWindow : DefaultWindow
|
||||
{
|
||||
public LinkAccountWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
@@ -63,16 +63,16 @@ public sealed class StellarInteractionParticleSystem : EntitySystem
|
||||
|
||||
private Animation GetAnimation(Vector2 endOffset, Color color)
|
||||
{
|
||||
var startRotation = _random.NextAngle(Angle.FromDegrees(-40), Angle.FromDegrees(40));
|
||||
var startRotation = _random.NextAngle(Angle.FromDegrees(-80), Angle.FromDegrees(80));
|
||||
var endRotation = Angle.Zero;
|
||||
var startScale = new Vector2(0.3f, 0.3f);
|
||||
var endScale = new Vector2(1f, 1f);
|
||||
var rotationLength = TimeSpan.FromMilliseconds(600);
|
||||
|
||||
var startOffset = new Vector2();
|
||||
var offsetLength = TimeSpan.FromMilliseconds(250);
|
||||
var offsetLength = TimeSpan.FromMilliseconds(200);
|
||||
|
||||
var startColor = color.WithAlpha(color.A * 0.7f);
|
||||
var startColor = color.WithAlpha(color.A * 0.9f);
|
||||
var endColor = color.WithAlpha(0f);
|
||||
var colorLength = rotationLength + offsetLength;
|
||||
|
||||
@@ -89,7 +89,7 @@ public sealed class StellarInteractionParticleSystem : EntitySystem
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(startRotation, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(endRotation, (float)rotationLength.TotalSeconds, Easings.OutBack),
|
||||
new AnimationTrackProperty.KeyFrame(endRotation, (float)rotationLength.TotalSeconds, Easings.OutBounce),
|
||||
},
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
@@ -99,7 +99,7 @@ public sealed class StellarInteractionParticleSystem : EntitySystem
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(startScale, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(endScale, (float)rotationLength.TotalSeconds, Easings.OutBack),
|
||||
new AnimationTrackProperty.KeyFrame(endScale, (float)rotationLength.TotalSeconds, Easings.OutBounce),
|
||||
},
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
@@ -109,7 +109,7 @@ public sealed class StellarInteractionParticleSystem : EntitySystem
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(startOffset, 0f),
|
||||
new AnimationTrackProperty.KeyFrame(endOffset, (float)offsetLength.TotalSeconds, Easings.OutBack),
|
||||
new AnimationTrackProperty.KeyFrame(endOffset, (float)offsetLength.TotalSeconds, Easings.OutBounce),
|
||||
},
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Reflection;
|
||||
using Content.DiscordBot.Modules;
|
||||
using Content.Server.Database;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Content.DiscordBot;
|
||||
|
||||
public sealed class CommandHandler(DiscordSocketClient client, InteractionService interaction, ServerDbContext db, Config config)
|
||||
{
|
||||
private ImmutableDictionary<ulong, PatronTier>? _patronTiers;
|
||||
private ImmutableArray<PatronTier> _tierPriority;
|
||||
private Task? _refreshPatronsTask;
|
||||
|
||||
public int Running = 1;
|
||||
|
||||
public async Task InstallCommandsAsync()
|
||||
{
|
||||
var patronTiers = await db.PatronTiers.ToListAsync();
|
||||
_tierPriority = [..patronTiers.OrderBy(t => t.Priority)];
|
||||
_patronTiers = patronTiers.ToImmutableDictionary(t => t.DiscordRole, t => t);
|
||||
|
||||
client.Ready += ReadyAsync;
|
||||
client.SlashCommandExecuted += HandleCommandAsync;
|
||||
client.ButtonExecuted += HandleButtonAsync;
|
||||
client.ModalSubmitted += HandleModalAsync;
|
||||
client.GuildMemberUpdated += HandleGuildMemberUpdated;
|
||||
|
||||
// If you get a log that says '[ERROR]' here, you probably don't have the corrent intents
|
||||
await client.LoginAsync(TokenType.Bot, config.Token);
|
||||
await client.StartAsync();
|
||||
|
||||
interaction.AddModalInfo<LinkAccountModal>();
|
||||
|
||||
_refreshPatronsTask = Task.Run(async () => await RefreshPatrons());
|
||||
}
|
||||
|
||||
private async Task ReadyAsync()
|
||||
{
|
||||
await interaction.AddModulesAsync(Assembly.GetEntryAssembly(), null);
|
||||
await interaction.RegisterCommandsToGuildAsync(config.Guild);
|
||||
}
|
||||
|
||||
private async Task HandleGuildMemberUpdated(Cacheable<SocketGuildUser, ulong> old, SocketGuildUser user)
|
||||
{
|
||||
if (_patronTiers == null)
|
||||
return;
|
||||
|
||||
var rolesChanged = !old.HasValue || old.Value.Roles.Count != user.Roles.Count || !old.Value.Roles.SequenceEqual(user.Roles);
|
||||
if (!rolesChanged)
|
||||
return;
|
||||
|
||||
var wasPatron = old.HasValue || old.Value.Roles.Any(r => _patronTiers.ContainsKey(r.Id));
|
||||
var isPatron = user.Roles.Any(r => _patronTiers.ContainsKey(r.Id));
|
||||
if (wasPatron && !isPatron)
|
||||
{
|
||||
var linked = await db.DiscordLinkedAccounts
|
||||
.Include(l => l.Player)
|
||||
.ThenInclude(p => p.Patron)
|
||||
.ThenInclude(p => p!.Tier)
|
||||
.Where(l => l.Player.Patron != null)
|
||||
.FirstOrDefaultAsync(p => p.DiscordId == user.Id);
|
||||
|
||||
if (linked?.Player.Patron is { } patron)
|
||||
{
|
||||
db.Patrons.Remove(patron);
|
||||
await db.SaveChangesAsync();
|
||||
await Logger.Info($"Removed patron {user.Username}:{linked.DiscordId}:{linked.Player.LastSeenUserName} with tier {patron.Tier.Name}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPatron)
|
||||
{
|
||||
foreach (var tier in _tierPriority)
|
||||
{
|
||||
if (user.Roles.Any(r => r.Id == tier.DiscordRole))
|
||||
{
|
||||
var linked = await db.DiscordLinkedAccounts
|
||||
.Include(l => l.Player)
|
||||
.ThenInclude(p => p.Patron)
|
||||
.FirstOrDefaultAsync(p => p.DiscordId == user.Id);
|
||||
|
||||
if (linked?.Player is not { } player)
|
||||
return;
|
||||
|
||||
player.Patron ??= db.Patrons.Add(new Patron { PlayerId = player.UserId }).Entity;
|
||||
player.Patron.TierId = tier.Id;
|
||||
await db.SaveChangesAsync();
|
||||
await Logger.Info($"Updated patron {user.Username}:{linked.DiscordId}:{linked.Player.LastSeenUserName} with tier {tier.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleCommandAsync(SocketSlashCommand message)
|
||||
{
|
||||
|
||||
if (message.GuildId != config.Guild)
|
||||
return;
|
||||
|
||||
// Create a WebSocket-based command context based on the message
|
||||
var context = new SocketInteractionContext(client, message);
|
||||
|
||||
// Execute the command with the command context we just
|
||||
// created, along with the service provider for precondition checks.
|
||||
await interaction.ExecuteCommandAsync(context, null);
|
||||
}
|
||||
|
||||
private async Task HandleButtonAsync(SocketMessageComponent component)
|
||||
{
|
||||
switch (component.Data.CustomId)
|
||||
{
|
||||
case "link-ss14-account":
|
||||
await component.RespondWithModalAsync<LinkAccountModal>("link-ss14-account");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleModalAsync(SocketModal modal)
|
||||
{
|
||||
switch (modal.Data.CustomId)
|
||||
{
|
||||
case "link-ss14-account":
|
||||
if (modal.GuildId is not { } guildId)
|
||||
break;
|
||||
|
||||
var codeStr = modal.Data.Components.First(c => c.CustomId == "account_code").Value.Trim();
|
||||
if (string.IsNullOrWhiteSpace(codeStr))
|
||||
break;
|
||||
|
||||
await modal.DeferAsync(true);
|
||||
if (!Guid.TryParse(codeStr, out var code))
|
||||
{
|
||||
await modal.FollowupAsync($"{codeStr} isn't a valid code! Get one in-game from the lobby at the top left of the screen.", ephemeral: true);
|
||||
}
|
||||
|
||||
var author = modal.User;
|
||||
var authorId = author.Id;
|
||||
var discord = await db.DiscordAccounts
|
||||
.Include(d => d.LinkedAccount)
|
||||
.ThenInclude(l => l.Player)
|
||||
.ThenInclude(p => p.Patron)
|
||||
.FirstOrDefaultAsync(a => a.Id == authorId);
|
||||
var codes = await db.DiscordLinkingCodes
|
||||
.Include(l => l.Player)
|
||||
.ThenInclude(player => player.Patron)
|
||||
.FirstOrDefaultAsync(p => p.Code == code);
|
||||
|
||||
if (codes == null)
|
||||
{
|
||||
await modal.FollowupAsync($"No player found with code {codeStr}, join the game server and get another code before trying again, or ask for help in another channel.", ephemeral: true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (codes.CreationTime < DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)))
|
||||
{
|
||||
await modal.FollowupAsync($"Code {codeStr} were generated too long ago, join the game server and get another code before trying again.", ephemeral: true);
|
||||
}
|
||||
|
||||
if (discord?.LinkedAccount is { } linked)
|
||||
{
|
||||
if (linked.Player.Patron is { } patron)
|
||||
db.Patrons.Remove(patron);
|
||||
|
||||
linked.Player.Patron = null;
|
||||
db.DiscordLinkedAccounts.Remove(linked);
|
||||
}
|
||||
|
||||
discord ??= db.DiscordAccounts.Add(new DiscordAccount { Id = authorId }).Entity;
|
||||
discord.LinkedAccount = db.DiscordLinkedAccounts.Add(new DiscordLinkedAccount { Discord = discord }).Entity;
|
||||
discord.LinkedAccount.Player = codes.Player;
|
||||
|
||||
var roles = client.GetGuild(guildId).GetUser(authorId).Roles.Select(r => r.Id).ToArray();
|
||||
var tiers = await db.PatronTiers
|
||||
.Where(t => roles.Contains(t.DiscordRole))
|
||||
.ToListAsync();
|
||||
if (tiers.Count == 0)
|
||||
{
|
||||
discord.LinkedAccount.Player.Patron = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
tiers.Sort((a, b) => a.Priority.CompareTo(b.Priority));
|
||||
var tier = tiers[0];
|
||||
discord.LinkedAccount.Player.Patron = db.Patrons.Add(new Patron { Tier = tier }).Entity;
|
||||
discord.LinkedAccount.Player.Patron.Tier = tier;
|
||||
}
|
||||
|
||||
db.DiscordLinkedAccountLogs.Add(new DiscordLinkedAccountLogs
|
||||
{
|
||||
Discord = discord,
|
||||
Player = discord.LinkedAccount.Player,
|
||||
});
|
||||
|
||||
db.ChangeTracker.DetectChanges();
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var msg = $"Linked SS14 account with name {codes.Player.LastSeenUserName}";
|
||||
if (codes.Player.Patron != null)
|
||||
msg += $" and tier {codes.Player.Patron.Tier.Name}";
|
||||
|
||||
await modal.FollowupAsync(msg, ephemeral: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshPatrons()
|
||||
{
|
||||
while (Interlocked.CompareExchange(ref Running, 1, 1) == 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
var patrons = await db.DiscordLinkedAccounts
|
||||
.Include(l => l.Player)
|
||||
.ThenInclude(p => p.Patron)
|
||||
.ThenInclude(p => p!.Tier)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var linked in patrons)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await client.Rest.GetGuildUserAsync(config.Guild, linked.DiscordId);
|
||||
if (user == null)
|
||||
{
|
||||
if (linked.Player.Patron != null)
|
||||
{
|
||||
linked.Player.Patron = null;
|
||||
await Logger.Info($"Removed patron {linked.DiscordId}:{linked.Player.LastSeenUserName}");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var isPatron = false;
|
||||
foreach (var tier in _tierPriority)
|
||||
{
|
||||
if (user.RoleIds.Contains(tier.DiscordRole))
|
||||
{
|
||||
isPatron = true;
|
||||
if (linked.Player.Patron?.Tier.DiscordRole == tier.DiscordRole)
|
||||
break;
|
||||
|
||||
linked.Player.Patron ??= db.Patrons.Add(new Patron { PlayerId = linked.PlayerId })
|
||||
.Entity;
|
||||
linked.Player.Patron.TierId = tier.Id;
|
||||
await Logger.Info($"Updated patron {user.Username}:{linked.DiscordId}:{linked.Player.LastSeenUserName} with tier {tier.Name}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPatron && linked.Player.Patron != null)
|
||||
{
|
||||
linked.Player.Patron = null;
|
||||
await Logger.Info($"Removed patron {user.Username}:{linked.DiscordId}:{linked.Player.LastSeenUserName}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Logger.Error($"Error updating patron with discord id {linked.DiscordId} and player id {linked.PlayerId}", e);
|
||||
}
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await Task.Delay(60000); // 60 seconds
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Logger.Error("Error refreshing patrons", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Content.DiscordBot;
|
||||
|
||||
public sealed class Config
|
||||
{
|
||||
public string Token { get; set; } = string.Empty;
|
||||
|
||||
public string DatabaseString { get; set; } = string.Empty;
|
||||
|
||||
public string DatabaseContext { get; set; } = "postgres";
|
||||
|
||||
/// <summary>
|
||||
/// Discord "guild" ID (which is just the server ID). Default is DeltaV's server ID.
|
||||
/// </summary>
|
||||
public ulong Guild { get; set; } = 968983104247185448UL;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<OutputPath>..\bin\Content.DiscordBot\</OutputPath>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
<RootNamespace>Content.DiscordBot</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Discord.Net" Version="3.15.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Content.Server.Database\Content.Server.Database.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,21 +0,0 @@
|
||||
using Discord;
|
||||
|
||||
namespace Content.DiscordBot;
|
||||
|
||||
public static class Logger
|
||||
{
|
||||
public static Task Log(LogMessage msg)
|
||||
{
|
||||
return Console.Out.WriteLineAsync($"[{msg.Severity.ToString().ToUpper()}] {msg.Message}");
|
||||
}
|
||||
|
||||
public static Task Info(string msg)
|
||||
{
|
||||
return Console.Out.WriteLineAsync($"[INFO] {msg}");
|
||||
}
|
||||
|
||||
public static Task Error(string msg, Exception e)
|
||||
{
|
||||
return Console.Out.WriteLineAsync($"[ERROR] {msg}\n{e}");
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
|
||||
namespace Content.DiscordBot.Modules;
|
||||
|
||||
public sealed class AccountLinkingModule : InteractionModuleBase<SocketInteractionContext>
|
||||
{
|
||||
[SlashCommand("discordlink", "Creates the message with the linking button.")]
|
||||
[RequireTeam]
|
||||
public Task CreateAsync()
|
||||
{
|
||||
var component = new ComponentBuilder()
|
||||
.WithButton("Link your SS14 account here!", "link-ss14-account")
|
||||
.Build();
|
||||
|
||||
return RespondAsync(String.Empty, components: component);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Discord.Interactions;
|
||||
|
||||
namespace Content.DiscordBot.Modules;
|
||||
|
||||
public class LinkAccountModal : IModal
|
||||
{
|
||||
public string Title => "Link SS14 Account";
|
||||
|
||||
[InputLabel("SS14 Linking Code (Top Left in the Lobby)")]
|
||||
[RequiredInput]
|
||||
[ModalTextInput("account_code")]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using Content.DiscordBot;
|
||||
using Content.Server.Database;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
var client = new DiscordSocketClient(new DiscordSocketConfig { GatewayIntents = GatewayIntents.GuildMembers });
|
||||
client.Log += Logger.Log;
|
||||
|
||||
Console.Out.WriteLine($"[INIT] Working Directory: {Directory.GetCurrentDirectory()}");
|
||||
|
||||
var config = new Config();
|
||||
if (File.Exists("link-config.json"))
|
||||
{
|
||||
Console.Out.WriteLine("[INIT] link-config.json found. Deserializing.");
|
||||
config = await JsonSerializer.DeserializeAsync<Config>(File.OpenRead("link-config.json")) ?? new Config();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (Environment.GetEnvironmentVariable("DISCORD_TOKEN") is { } envToken)
|
||||
config.Token = envToken;
|
||||
|
||||
if (Environment.GetEnvironmentVariable("DATABASE_STRING") is { } dbString)
|
||||
config.DatabaseString = dbString;
|
||||
|
||||
if (Environment.GetEnvironmentVariable("DATABASE_CONTEXT") is { } context)
|
||||
config.DatabaseContext = context;
|
||||
|
||||
if (Environment.GetEnvironmentVariable("GUILD") is { } guildId)
|
||||
{
|
||||
try
|
||||
{
|
||||
config.Guild = ulong.Parse("guildId");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Out.WriteLine($"[INIT] Unable to parse guild ID. Defaulting to {config.Guild}. Exception: {ex.GetType()} {ex.Message}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string.IsNullOrWhiteSpace(config.Token))
|
||||
throw new ArgumentException("[INIT] No Discord Bot token found.");
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(config.DatabaseString))
|
||||
throw new ArgumentException("[INIT] No database connection string found.");
|
||||
|
||||
// Override for local sqlite development
|
||||
var usePostgres = true;
|
||||
if (!string.IsNullOrWhiteSpace(config.DatabaseContext) && config.DatabaseContext.Equals("sqlite"))
|
||||
usePostgres = false;
|
||||
|
||||
Console.Out.WriteLine($"[INIT] Guild ID: {config.Guild}");
|
||||
|
||||
ServerDbContext db;
|
||||
if (usePostgres)
|
||||
{
|
||||
Console.Out.WriteLine("[INIT] Connecting to postgres...");
|
||||
var builder = new DbContextOptionsBuilder<PostgresServerDbContext>();
|
||||
builder.UseNpgsql(config.DatabaseString);
|
||||
db = new PostgresServerDbContext(builder.Options);
|
||||
// await db.Database.MigrateAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Out.WriteLine("[INIT] Connecting to sqlite...");
|
||||
var builder = new DbContextOptionsBuilder<SqliteServerDbContext>();
|
||||
builder.UseSqlite(new SqliteConnection(config.DatabaseString));
|
||||
db = new SqliteServerDbContext(builder.Options);
|
||||
}
|
||||
|
||||
Console.Out.WriteLine("[INIT] Database connection successful.");
|
||||
|
||||
var interaction = new InteractionService(client);
|
||||
var handler = new CommandHandler(client, interaction, db, config);
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => Interlocked.Decrement(ref handler.Running);
|
||||
|
||||
Console.Out.WriteLine("[INIT] Starting Discord Bot.");
|
||||
await handler.InstallCommandsAsync();
|
||||
|
||||
// Block this task until the program is closed.
|
||||
await Task.Delay(-1);
|
||||
@@ -1,32 +0,0 @@
|
||||
# Content.DiscordBot
|
||||
|
||||
|
||||
### Configuration (Debug)
|
||||
* `DISCORD_TOKEN`: Discord application token provided @ `https://discord.com/developers/applications/<APP_ID>/bot`
|
||||
* `DATABASE_STRING`: Connection string to the database
|
||||
* For local development, you'll want it to be `Data Source=./bin/Content.Server/data/preferences.db` if you're using sqlite.
|
||||
* `DATABASE_CONTEXT`: Default is `postgres`. If testing locally with sqlite, use `sqlite`.
|
||||
* `GUILD`: The Discord Server ID. DeltaV's discord is `968983104247185448`.
|
||||
* You can find this by turning Developer mode on in Discord, right-clicking on a server, and copying the server ID.
|
||||
|
||||
### Configuration (Production)
|
||||
Requires a `link-config.json` file in the working directory.
|
||||
```json
|
||||
{
|
||||
"Token": "DISCORD_BOT_TOKEN",
|
||||
"DatabaseString": "DB_CONNECTION_STRING"
|
||||
}
|
||||
```
|
||||
|
||||
Here's a quick bash command to create it in your current working directory. Windows users will have to fend for themselves.
|
||||
```bash
|
||||
cat << EOF > link-config.json
|
||||
{
|
||||
"Token": "DISCORD_BOT_TOKEN",
|
||||
"DatabaseString": "DB_CONNECTION_STRING"
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
You can also override `Guild` and `DatabaseContext` if you wanted to by including those JSON properties.
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Content.Server.Database;
|
||||
|
||||
[Table("discord_accounts")]
|
||||
public sealed class DiscordAccount
|
||||
{
|
||||
[Key]
|
||||
public ulong Id { get; set; }
|
||||
|
||||
public DiscordLinkedAccount LinkedAccount { get; set; } = default!;
|
||||
public List<DiscordLinkedAccountLogs> LinkedAccountLogs { get; set; } = default!;
|
||||
}
|
||||
|
||||
[Table("discord_linked_accounts")]
|
||||
public sealed class DiscordLinkedAccount
|
||||
{
|
||||
[Key]
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public Player Player { get; set; } = default!;
|
||||
|
||||
public ulong DiscordId { get; set; }
|
||||
|
||||
public DiscordAccount Discord { get; set; } = default!;
|
||||
}
|
||||
|
||||
[Table("patreon_tiers")]
|
||||
public sealed class PatronTier
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public bool ShowOnCredits { get; set; }
|
||||
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
public ulong DiscordRole { get; set; }
|
||||
|
||||
public int Priority { get; set; }
|
||||
|
||||
public List<Patron> Patrons { get; set; } = default!;
|
||||
}
|
||||
|
||||
[Table("patreon_patrons")]
|
||||
[Index(nameof(TierId))]
|
||||
public sealed class Patron
|
||||
{
|
||||
[Key]
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public Player Player { get; set; } = default!;
|
||||
|
||||
public int TierId { get; set; }
|
||||
|
||||
public PatronTier Tier { get; set; } = default!;
|
||||
}
|
||||
|
||||
[Table("discord_linking_codes")]
|
||||
[Index(nameof(Code))]
|
||||
public sealed class DiscordLinkingCodes
|
||||
{
|
||||
[Key]
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public Player Player { get; set; } = default!;
|
||||
|
||||
public Guid Code { get; set; }
|
||||
|
||||
public DateTime CreationTime { get; set; }
|
||||
}
|
||||
|
||||
[Table("discord_linked_accounts_logs")]
|
||||
[Index(nameof(PlayerId))]
|
||||
[Index(nameof(DiscordId))]
|
||||
[Index(nameof(At))]
|
||||
public sealed class DiscordLinkedAccountLogs
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public Guid PlayerId { get; set; }
|
||||
|
||||
public Player Player { get; set; } = default!;
|
||||
|
||||
public ulong DiscordId { get; set; }
|
||||
|
||||
public DiscordAccount Discord { get; set; } = default!;
|
||||
|
||||
public DateTime At { get; set; }
|
||||
}
|
||||
-2433
File diff suppressed because it is too large
Load Diff
@@ -1,207 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class DiscordLinking : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "cur_time",
|
||||
table: "admin_log");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_accounts",
|
||||
columns: table => new
|
||||
{
|
||||
discord_accounts_id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_accounts", x => x.discord_accounts_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linking_codes",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
code = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
creation_time = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linking_codes", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linking_codes_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patreon_tiers",
|
||||
columns: table => new
|
||||
{
|
||||
patreon_tiers_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
show_on_credits = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
discord_role = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
priority = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_patreon_tiers", x => x.patreon_tiers_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linked_accounts",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
discord_id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linked_accounts", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_discord_accounts_discord_id",
|
||||
column: x => x.discord_id,
|
||||
principalTable: "discord_accounts",
|
||||
principalColumn: "discord_accounts_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linked_accounts_logs",
|
||||
columns: table => new
|
||||
{
|
||||
discord_linked_accounts_logs_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
discord_id = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
at = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linked_accounts_logs", x => x.discord_linked_accounts_logs_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_logs_discord_accounts_discord_id",
|
||||
column: x => x.discord_id,
|
||||
principalTable: "discord_accounts",
|
||||
principalColumn: "discord_accounts_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_logs_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patreon_patrons",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
tier_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_patreon_patrons", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_patreon_patrons_patreon_tiers_tier_id",
|
||||
column: x => x.tier_id,
|
||||
principalTable: "patreon_tiers",
|
||||
principalColumn: "patreon_tiers_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_patreon_patrons_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_discord_id",
|
||||
table: "discord_linked_accounts",
|
||||
column: "discord_id",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_at",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "at");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_discord_id",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "discord_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_player_id",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "player_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linking_codes_code",
|
||||
table: "discord_linking_codes",
|
||||
column: "code");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_patreon_patrons_tier_id",
|
||||
table: "patreon_patrons",
|
||||
column: "tier_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_patreon_tiers_discord_role",
|
||||
table: "patreon_tiers",
|
||||
column: "discord_role",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linked_accounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linked_accounts_logs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linking_codes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "patreon_patrons");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_accounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "patreon_tiers");
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "cur_time",
|
||||
table: "admin_log",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0L);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-248
@@ -1,6 +1,5 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Content.Server.Database;
|
||||
@@ -21,7 +20,7 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.6")
|
||||
.HasAnnotation("ProductVersion", "9.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
@@ -740,151 +739,6 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
b.ToTable("dv_seen_tips", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Patron", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<int>("TierId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("tier_id");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_patreon_patrons");
|
||||
|
||||
b.HasIndex("TierId")
|
||||
.HasDatabaseName("IX_patreon_patrons_tier_id");
|
||||
|
||||
b.ToTable("patreon_patrons", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PatronTier", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("patreon_tiers_id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("DiscordRole")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("discord_role");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("priority");
|
||||
|
||||
b.Property<bool>("ShowOnCredits")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("show_on_credits");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_patreon_tiers");
|
||||
|
||||
b.HasIndex("DiscordRole")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("patreon_tiers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordAccount", b =>
|
||||
{
|
||||
b.Property<decimal>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("discord_accounts_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_discord_accounts");
|
||||
|
||||
b.ToTable("discord_accounts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<decimal>("DiscordId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_discord_linked_accounts");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("discord_linked_accounts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccountLogs", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("discord_linked_accounts_logs_id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("At")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("at");
|
||||
|
||||
b.Property<decimal>("DiscordId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_discord_linked_accounts_logs");
|
||||
|
||||
b.HasIndex("At")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_at");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_discord_id");
|
||||
|
||||
b.HasIndex("PlayerId")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_player_id");
|
||||
|
||||
b.ToTable("discord_linked_accounts_logs", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkingCodes", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<Guid>("Code")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("code");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("creation_time");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_discord_linking_codes");
|
||||
|
||||
b.HasIndex("Code")
|
||||
.HasDatabaseName("IX_discord_linking_codes_code");
|
||||
|
||||
b.ToTable("discord_linking_codes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.IPIntelCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1047,7 +901,7 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("admin_ooc_color");
|
||||
|
||||
b.PrimitiveCollection<List<string>>("ConstructionFavorites")
|
||||
b.PrimitiveCollection<string[]>("ConstructionFavorites")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("construction_favorites");
|
||||
@@ -1986,85 +1840,6 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
.HasConstraintName("FK_dv_seen_tips_player_player_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Patron", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("Patron")
|
||||
.HasForeignKey("Content.Server.Database.Patron", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_patreon_patrons_player_player_id1");
|
||||
|
||||
b.HasOne("Content.Server.Database.PatronTier", "Tier")
|
||||
.WithMany("Patrons")
|
||||
.HasForeignKey("TierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_patreon_patrons_patreon_tiers_tier_id");
|
||||
|
||||
b.Navigation("Player");
|
||||
|
||||
b.Navigation("Tier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccount", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.DiscordAccount", "Discord")
|
||||
.WithOne("LinkedAccount")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkedAccount", "DiscordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_discord_accounts_discord_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("LinkedAccount")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkedAccount", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_player_player_id1");
|
||||
|
||||
b.Navigation("Discord");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccountLogs", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.DiscordAccount", "Discord")
|
||||
.WithMany("LinkedAccountLogs")
|
||||
.HasForeignKey("DiscordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_logs_discord_accounts_discord_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithMany("LinkedAccountLogs")
|
||||
.HasForeignKey("PlayerId")
|
||||
.HasPrincipalKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_logs_player_player_id1");
|
||||
|
||||
b.Navigation("Discord");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkingCodes", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("LinkingCodes")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkingCodes", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linking_codes_player_player_id1");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
@@ -2394,19 +2169,6 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
b.Navigation("BanHits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PatronTier", b =>
|
||||
{
|
||||
b.Navigation("Patrons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordAccount", b =>
|
||||
{
|
||||
b.Navigation("LinkedAccount")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("LinkedAccountLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Player", b =>
|
||||
{
|
||||
b.Navigation("AdminLogs");
|
||||
@@ -2444,14 +2206,6 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
b.Navigation("AdminWatchlistsReceived");
|
||||
|
||||
b.Navigation("JobWhitelists");
|
||||
|
||||
b.Navigation("LinkedAccount");
|
||||
|
||||
b.Navigation("LinkedAccountLogs");
|
||||
|
||||
b.Navigation("LinkingCodes");
|
||||
|
||||
b.Navigation("Patron");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
|
||||
-2428
File diff suppressed because it is too large
Load Diff
@@ -1,207 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class DiscordLinking : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "cur_time",
|
||||
table: "admin_log");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_accounts",
|
||||
columns: table => new
|
||||
{
|
||||
discord_accounts_id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_accounts", x => x.discord_accounts_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linking_codes",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
code = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
creation_time = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linking_codes", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linking_codes_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patreon_tiers",
|
||||
columns: table => new
|
||||
{
|
||||
patreon_tiers_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
show_on_credits = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
discord_role = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
priority = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_patreon_tiers", x => x.patreon_tiers_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linked_accounts",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
discord_id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linked_accounts", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_discord_accounts_discord_id",
|
||||
column: x => x.discord_id,
|
||||
principalTable: "discord_accounts",
|
||||
principalColumn: "discord_accounts_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "discord_linked_accounts_logs",
|
||||
columns: table => new
|
||||
{
|
||||
discord_linked_accounts_logs_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
discord_id = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
at = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_discord_linked_accounts_logs", x => x.discord_linked_accounts_logs_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_logs_discord_accounts_discord_id",
|
||||
column: x => x.discord_id,
|
||||
principalTable: "discord_accounts",
|
||||
principalColumn: "discord_accounts_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_discord_linked_accounts_logs_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "patreon_patrons",
|
||||
columns: table => new
|
||||
{
|
||||
player_id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
tier_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_patreon_patrons", x => x.player_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_patreon_patrons_patreon_tiers_tier_id",
|
||||
column: x => x.tier_id,
|
||||
principalTable: "patreon_tiers",
|
||||
principalColumn: "patreon_tiers_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_patreon_patrons_player_player_id1",
|
||||
column: x => x.player_id,
|
||||
principalTable: "player",
|
||||
principalColumn: "user_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_discord_id",
|
||||
table: "discord_linked_accounts",
|
||||
column: "discord_id",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_at",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "at");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_discord_id",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "discord_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linked_accounts_logs_player_id",
|
||||
table: "discord_linked_accounts_logs",
|
||||
column: "player_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_discord_linking_codes_code",
|
||||
table: "discord_linking_codes",
|
||||
column: "code");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_patreon_patrons_tier_id",
|
||||
table: "patreon_patrons",
|
||||
column: "tier_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_patreon_tiers_discord_role",
|
||||
table: "patreon_tiers",
|
||||
column: "discord_role",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linked_accounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linked_accounts_logs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_linking_codes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "patreon_patrons");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "discord_accounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "patreon_tiers");
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "cur_time",
|
||||
table: "admin_log",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0L);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.6");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
@@ -698,147 +698,6 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
b.ToTable("dv_seen_tips", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Patron", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<int>("TierId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("tier_id");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_patreon_patrons");
|
||||
|
||||
b.HasIndex("TierId")
|
||||
.HasDatabaseName("IX_patreon_patrons_tier_id");
|
||||
|
||||
b.ToTable("patreon_patrons", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PatronTier", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("patreon_tiers_id");
|
||||
|
||||
b.Property<ulong>("DiscordRole")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_role");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("priority");
|
||||
|
||||
b.Property<bool>("ShowOnCredits")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("show_on_credits");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_patreon_tiers");
|
||||
|
||||
b.HasIndex("DiscordRole")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("patreon_tiers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordAccount", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_accounts_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_discord_accounts");
|
||||
|
||||
b.ToTable("discord_accounts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_discord_linked_accounts");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("discord_linked_accounts", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccountLogs", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_linked_accounts_logs_id");
|
||||
|
||||
b.Property<DateTime>("At")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("at");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_discord_linked_accounts_logs");
|
||||
|
||||
b.HasIndex("At")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_at");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_discord_id");
|
||||
|
||||
b.HasIndex("PlayerId")
|
||||
.HasDatabaseName("IX_discord_linked_accounts_logs_player_id");
|
||||
|
||||
b.ToTable("discord_linked_accounts_logs", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkingCodes", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<Guid>("Code")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("code");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("creation_time");
|
||||
|
||||
b.HasKey("PlayerId")
|
||||
.HasName("PK_discord_linking_codes");
|
||||
|
||||
b.HasIndex("Code")
|
||||
.HasDatabaseName("IX_discord_linking_codes_code");
|
||||
|
||||
b.ToTable("discord_linking_codes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.IPIntelCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1900,85 +1759,6 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
.HasConstraintName("FK_dv_seen_tips_player_player_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Patron", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("Patron")
|
||||
.HasForeignKey("Content.Server.Database.Patron", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_patreon_patrons_player_player_id1");
|
||||
|
||||
b.HasOne("Content.Server.Database.PatronTier", "Tier")
|
||||
.WithMany("Patrons")
|
||||
.HasForeignKey("TierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_patreon_patrons_patreon_tiers_tier_id");
|
||||
|
||||
b.Navigation("Player");
|
||||
|
||||
b.Navigation("Tier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccount", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.DiscordAccount", "Discord")
|
||||
.WithOne("LinkedAccount")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkedAccount", "DiscordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_discord_accounts_discord_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("LinkedAccount")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkedAccount", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_player_player_id1");
|
||||
|
||||
b.Navigation("Discord");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkedAccountLogs", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.DiscordAccount", "Discord")
|
||||
.WithMany("LinkedAccountLogs")
|
||||
.HasForeignKey("DiscordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_logs_discord_accounts_discord_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithMany("LinkedAccountLogs")
|
||||
.HasForeignKey("PlayerId")
|
||||
.HasPrincipalKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linked_accounts_logs_player_player_id1");
|
||||
|
||||
b.Navigation("Discord");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordLinkingCodes", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithOne("LinkingCodes")
|
||||
.HasForeignKey("Content.Server.Database.DiscordLinkingCodes", "PlayerId")
|
||||
.HasPrincipalKey("Content.Server.Database.Player", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_discord_linking_codes_player_player_id1");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
@@ -2308,19 +2088,6 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
b.Navigation("BanHits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PatronTier", b =>
|
||||
{
|
||||
b.Navigation("Patrons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.DiscordAccount", b =>
|
||||
{
|
||||
b.Navigation("LinkedAccount")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("LinkedAccountLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Player", b =>
|
||||
{
|
||||
b.Navigation("AdminLogs");
|
||||
@@ -2358,14 +2125,6 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
b.Navigation("AdminWatchlistsReceived");
|
||||
|
||||
b.Navigation("JobWhitelists");
|
||||
|
||||
b.Navigation("LinkedAccount");
|
||||
|
||||
b.Navigation("LinkedAccountLogs");
|
||||
|
||||
b.Navigation("LinkingCodes");
|
||||
|
||||
b.Navigation("Patron");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
|
||||
@@ -48,15 +48,6 @@ namespace Content.Server.Database
|
||||
public DbSet<IPIntelCache> IPIntelCache { get; set; } = null!;
|
||||
public DbSet<DVModel.SeenTip> DVSeenTips { get; set; } = null!; // DeltaV - Tips
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
public DbSet<DiscordAccount> DiscordAccounts { get; set; } = default!;
|
||||
public DbSet<DiscordLinkedAccount> DiscordLinkedAccounts { get; set; } = default!;
|
||||
public DbSet<PatronTier> PatronTiers { get; set; } = default!;
|
||||
public DbSet<Patron> Patrons { get; set; } = default!;
|
||||
public DbSet<DiscordLinkingCodes> DiscordLinkingCodes { get; set; } = default!;
|
||||
public DbSet<DiscordLinkedAccountLogs> DiscordLinkedAccountLogs { get; set; } = default!;
|
||||
// END DeltaV
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Preference>()
|
||||
@@ -404,61 +395,6 @@ namespace Content.Server.Database
|
||||
.OwnsOne(p => p.HWId)
|
||||
.Property(p => p.Type)
|
||||
.HasDefaultValue(HwidType.Legacy);
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
modelBuilder.Entity<DiscordLinkedAccount>()
|
||||
.HasOne(l => l.Player)
|
||||
.WithOne(p => p.LinkedAccount)
|
||||
.HasForeignKey<DiscordLinkedAccount>(l => l.PlayerId)
|
||||
.HasPrincipalKey<Player>(p => p.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<DiscordLinkedAccount>()
|
||||
.HasOne(l => l.Discord)
|
||||
.WithOne(d => d.LinkedAccount)
|
||||
.HasForeignKey<DiscordLinkedAccount>(l => l.DiscordId)
|
||||
.HasPrincipalKey<DiscordAccount>(d => d.Id)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Patron>()
|
||||
.HasOne(p => p.Player)
|
||||
.WithOne(p => p.Patron)
|
||||
.HasForeignKey<Patron>(p => p.PlayerId)
|
||||
.HasPrincipalKey<Player>(p => p.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<Patron>()
|
||||
.HasOne(p => p.Tier)
|
||||
.WithMany(t => t.Patrons)
|
||||
.HasForeignKey(p => p.TierId)
|
||||
.HasPrincipalKey(p => p.Id)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<PatronTier>()
|
||||
.HasIndex(t => t.DiscordRole)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<DiscordLinkingCodes>()
|
||||
.HasOne(l => l.Player)
|
||||
.WithOne(p => p.LinkingCodes)
|
||||
.HasForeignKey<DiscordLinkingCodes>(l => l.PlayerId)
|
||||
.HasPrincipalKey<Player>(p => p.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<DiscordLinkedAccountLogs>()
|
||||
.HasOne(l => l.Player)
|
||||
.WithMany(p => p.LinkedAccountLogs)
|
||||
.HasForeignKey(l => l.PlayerId)
|
||||
.HasPrincipalKey(p => p.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<DiscordLinkedAccountLogs>()
|
||||
.HasOne(l => l.Discord)
|
||||
.WithMany(p => p.LinkedAccountLogs)
|
||||
.HasForeignKey(l => l.DiscordId)
|
||||
.HasPrincipalKey(p => p.Id)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
// END DeltaV
|
||||
}
|
||||
|
||||
public virtual IQueryable<AdminLog> SearchLogs(IQueryable<AdminLog> query, string searchText)
|
||||
@@ -685,13 +621,6 @@ namespace Content.Server.Database
|
||||
public List<ServerRoleBan> AdminServerRoleBansCreated { get; set; } = null!;
|
||||
public List<ServerRoleBan> AdminServerRoleBansLastEdited { get; set; } = null!;
|
||||
public List<RoleWhitelist> JobWhitelists { get; set; } = null!;
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
public DiscordLinkedAccount? LinkedAccount { get; set; }
|
||||
public Patron? Patron { get; set; }
|
||||
public DiscordLinkingCodes? LinkingCodes { get; set; }
|
||||
public List<DiscordLinkedAccountLogs> LinkedAccountLogs { get; set; } = default!;
|
||||
// END DeltaV
|
||||
}
|
||||
|
||||
[Table("whitelist")]
|
||||
|
||||
@@ -89,10 +89,10 @@ internal sealed partial class ChatManager : IChatManager
|
||||
DispatchServerAnnouncement(Loc.GetString(val ? "chat-manager-admin-ooc-chat-enabled-message" : "chat-manager-admin-ooc-chat-disabled-message"));
|
||||
}
|
||||
|
||||
public void DeleteMessagesBy(NetUserId uid)
|
||||
{
|
||||
if (!_players.TryGetValue(uid, out var user))
|
||||
return;
|
||||
public void DeleteMessagesBy(NetUserId uid)
|
||||
{
|
||||
if (!_players.TryGetValue(uid, out var user))
|
||||
return;
|
||||
|
||||
var msg = new MsgDeleteChatMessagesBy { Key = user.Key, Entities = user.Entities };
|
||||
_netManager.ServerSendToAll(msg);
|
||||
|
||||
@@ -93,6 +93,7 @@ public sealed class ChatSanitizationManager : IChatSanitizationManager
|
||||
Entry("('=", "chatsan-tearfully-smiles"),
|
||||
Entry("['=", "chatsan-tearfully-smiles"),
|
||||
Entry("?", "chatsan-confused"), //DeltaV
|
||||
Entry("!", "chatsan-surprised"), //DeltaV
|
||||
Entry("…", "chatsan-sighs"), //DeltaV (note that ... doesn't work as that turns into a radio message)
|
||||
];
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ using Content.Server.GameTicking;
|
||||
using Content.Server.Speech.EntitySystems;
|
||||
using Content.Shared.Speech.Hushing; // DeltaV
|
||||
using Content.Server.Nyanotrasen.Chat;
|
||||
using Content.Server.Speech.Components; // DeltaV
|
||||
using Content.Server.Speech.Prototypes;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
@@ -36,7 +35,6 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Replays;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared._DV.Chat; // DeltaV - chat enhancements
|
||||
|
||||
namespace Content.Server.Chat.Systems;
|
||||
|
||||
@@ -217,7 +215,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
// Was there an emote in the message? If so, send it.
|
||||
if (player != null && emoteStr != message && emoteStr != null)
|
||||
{
|
||||
SendEntityEmote(source, emoteStr, range, nameOverride, null, ignoreActionBlocker); // DeltaV - Had to change up for SendEntityEmote
|
||||
SendEntityEmote(source, emoteStr, range, nameOverride, ignoreActionBlocker);
|
||||
}
|
||||
|
||||
// This can happen if the entire string is sanitized out.
|
||||
@@ -254,18 +252,9 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
case InGameICChatType.Whisper:
|
||||
SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker);
|
||||
break;
|
||||
case InGameICChatType.Emote: // DeltaV - Emote now has different types of emotes.
|
||||
var type = ProcessEmoteMessage(source, message, out var modMessage);
|
||||
if (type == EmoteType.Audible || type == EmoteType.AudiblePossessive)
|
||||
{
|
||||
if (checkRadioPrefix && TryProcessRadioMessage(source, modMessage, out var outputMessage, out var channel, capitalize: false))
|
||||
SendAudibleEntityEmote(source, outputMessage, range, nameOverride, channel, type, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
|
||||
else
|
||||
SendAudibleEntityEmote(source, modMessage, range, nameOverride, null, type, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
|
||||
}
|
||||
else
|
||||
SendEntityEmote(source, modMessage, range, nameOverride, type, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
|
||||
break; // DeltaV - End
|
||||
case InGameICChatType.Emote:
|
||||
SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
|
||||
break;
|
||||
//Nyano - Summary: case adds the telepathic chat sending ability.
|
||||
case InGameICChatType.Telepathic:
|
||||
_nyanoChatSystem.SendTelepathicChat(source, message, range == ChatTransmitRange.HideChat);
|
||||
@@ -640,7 +629,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
string action,
|
||||
ChatTransmitRange range,
|
||||
string? nameOverride,
|
||||
EmoteType? emoteType, // DeltaV
|
||||
bool hideLog = false,
|
||||
bool checkEmote = true,
|
||||
bool ignoreActionBlocker = false,
|
||||
@@ -654,21 +642,11 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
var ent = Identity.Entity(source, EntityManager);
|
||||
string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent));
|
||||
|
||||
// Begin DeltaV
|
||||
string wrappedMessage;
|
||||
|
||||
// Emotes use Identity.Name, since it doesn't actually involve your voice at all.
|
||||
if (emoteType == EmoteType.Possessive) // DeltaV - Emote types now get checked.
|
||||
wrappedMessage = Loc.GetString("chat-manager-entity-me-possessive-wrap-message",
|
||||
("entityName", name),
|
||||
("entity", ent),
|
||||
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
|
||||
else
|
||||
wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
|
||||
("entityName", name),
|
||||
("entity", ent),
|
||||
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
|
||||
// End DeltaV
|
||||
var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message",
|
||||
("entityName", name),
|
||||
("entity", ent),
|
||||
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
|
||||
|
||||
if (checkEmote &&
|
||||
!TryEmoteChatInput(source, action))
|
||||
@@ -682,59 +660,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source}: {action}");
|
||||
}
|
||||
|
||||
// DeltaV - Added this to differentiate between emotes that can be heard over radio and those which can't.
|
||||
protected override void SendAudibleEntityEmote(
|
||||
EntityUid source,
|
||||
string action,
|
||||
ChatTransmitRange range,
|
||||
string? nameOverride,
|
||||
RadioChannelPrototype? channel,
|
||||
EmoteType? emoteType,
|
||||
bool hideLog = false,
|
||||
bool checkEmote = true,
|
||||
bool ignoreActionBlocker = false,
|
||||
NetUserId? author = null
|
||||
)
|
||||
{
|
||||
if (!_actionBlocker.CanSpeak(source) && !ignoreActionBlocker)
|
||||
return;
|
||||
|
||||
EmoteType type = emoteType ?? EmoteType.Audible;
|
||||
|
||||
// get the entity's apparent name (if no override provided).
|
||||
var ent = Identity.Entity(source, EntityManager);
|
||||
string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent));
|
||||
|
||||
string wrappedMessage;
|
||||
|
||||
// Audible emotes use Identity.Name, since that is the status quo. Emotes like scream doesn't currently reveal identities so this won't either. [This may be changed with feedback as you can audibly emote over radios]
|
||||
if (emoteType == EmoteType.AudiblePossessive)
|
||||
wrappedMessage = Loc.GetString("chat-manager-entity-me-audible-possessive-wrap-message",
|
||||
("entityName", name),
|
||||
("entity", ent),
|
||||
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
|
||||
else
|
||||
wrappedMessage = Loc.GetString("chat-manager-entity-me-audible-wrap-message",
|
||||
("entityName", name),
|
||||
("entity", ent),
|
||||
("message", FormattedMessage.RemoveMarkupOrThrow(action)));
|
||||
|
||||
if (checkEmote &&
|
||||
!TryEmoteChatInput(source, action))
|
||||
return;
|
||||
|
||||
SendInVoiceRange(ChatChannel.Emotes, action, wrappedMessage, source, range, author);
|
||||
|
||||
var ev = new EntityAudiblyEmotedEvent(source, action, channel, type);
|
||||
RaiseLocalEvent(source, ref ev, true);
|
||||
if (!hideLog)
|
||||
if (name != Name(source))
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source} as {name}: {action}");
|
||||
else
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {source}: {action}");
|
||||
}
|
||||
// DeltaV - End
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private void SendLOOC(EntityUid source, ICommonSession player, string message, bool hideChat)
|
||||
{
|
||||
@@ -964,7 +889,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
var recipients = new Dictionary<ICommonSession, ICChatRecipientData>();
|
||||
var ghostHearing = GetEntityQuery<GhostHearingComponent>();
|
||||
var xforms = GetEntityQuery<TransformComponent>();
|
||||
var blockListening = GetEntityQuery<BlockListeningComponent>(); // DeltaV - block listening
|
||||
|
||||
var transformSource = xforms.GetComponent(source);
|
||||
var sourceMapId = transformSource.MapID;
|
||||
@@ -980,11 +904,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
if (transformEntity.MapID != sourceMapId)
|
||||
continue;
|
||||
|
||||
// Begin DeltaV - block listening
|
||||
if (blockListening.HasComponent(playerEntity))
|
||||
continue;
|
||||
// End DeltaV - block listening
|
||||
|
||||
var observer = ghostHearing.HasComponent(playerEntity);
|
||||
|
||||
// even if they are a ghost hearer, in some situations we still need the range
|
||||
@@ -1052,4 +971,4 @@ public sealed class CheckTargetedSpeechEvent : EntityEventArgs
|
||||
{
|
||||
public List<EntityUid> Targets = new List<EntityUid>();
|
||||
}
|
||||
// END Mono
|
||||
// END Mono
|
||||
@@ -16,7 +16,7 @@ using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
//using Content.Shared.Traits; // DV - Traits
|
||||
using Content.Shared.Traits;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network;
|
||||
@@ -1924,60 +1924,8 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
|
||||
.Where(s => s.PlayerUserId == player)
|
||||
.ExecuteDeleteAsync();
|
||||
}
|
||||
#endregion
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
#region DeltaV - Account Linking
|
||||
|
||||
public async Task<Guid?> GetLinkingCode(Guid player)
|
||||
{
|
||||
await using var db = await GetDb();
|
||||
var linking = await db.DbContext.DiscordLinkingCodes.FirstOrDefaultAsync(l => l.PlayerId == player);
|
||||
return linking?.Code;
|
||||
}
|
||||
|
||||
public async Task SetLinkingCode(Guid player, Guid code)
|
||||
{
|
||||
await using var db = await GetDb();
|
||||
var linking = await db.DbContext.DiscordLinkingCodes.FirstOrDefaultAsync(l => l.PlayerId == player);
|
||||
if (linking == null)
|
||||
{
|
||||
linking = new DiscordLinkingCodes { PlayerId = player };
|
||||
db.DbContext.DiscordLinkingCodes.Add(linking);
|
||||
}
|
||||
|
||||
linking.Code = code;
|
||||
linking.CreationTime = DateTime.UtcNow;
|
||||
await db.DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> HasLinkedAccount(Guid player, CancellationToken cancel)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
return await db.DbContext.DiscordLinkedAccounts.AnyAsync(l => l.PlayerId == player, cancel);
|
||||
|
||||
}
|
||||
|
||||
public async Task<Patron?> GetPatron(Guid player, CancellationToken cancel)
|
||||
{
|
||||
await using var db = await GetDb(cancel);
|
||||
var patron = await db.DbContext.Patrons
|
||||
.Include(p => p.Tier)
|
||||
.FirstOrDefaultAsync(p => p.PlayerId == player, cancellationToken: cancel);
|
||||
return patron;
|
||||
}
|
||||
|
||||
public async Task<List<Patron>> GetAllPatrons()
|
||||
{
|
||||
await using var db = await GetDb();
|
||||
return await db.DbContext.Patrons
|
||||
.Include(p => p.Player)
|
||||
.Include(p => p.Tier)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
// END DeltaV
|
||||
|
||||
public abstract Task SendNotification(DatabaseNotification notification);
|
||||
|
||||
|
||||
@@ -354,21 +354,6 @@ namespace Content.Server.Database
|
||||
|
||||
#endregion
|
||||
|
||||
// BEGIN DeltaV - Discord / Patreon Account Linking
|
||||
#region DeltaV - Discord Linking
|
||||
|
||||
Task<Guid?> GetLinkingCode(Guid player);
|
||||
|
||||
Task SetLinkingCode(Guid player, Guid code);
|
||||
|
||||
Task<bool> HasLinkedAccount(Guid player, CancellationToken cancel);
|
||||
|
||||
Task<Patron?> GetPatron(Guid player, CancellationToken cancel);
|
||||
|
||||
Task<List<Patron>> GetAllPatrons();
|
||||
#endregion
|
||||
// END DeltaV
|
||||
|
||||
#region DB Notifications
|
||||
|
||||
void SubscribeToNotifications(Action<DatabaseNotification> handler);
|
||||
@@ -1142,41 +1127,6 @@ namespace Content.Server.Database
|
||||
}
|
||||
}
|
||||
|
||||
// BEGIN DeltaV - Discord Linking
|
||||
#region DeltaV - Discord Linking
|
||||
public Task<Guid?> GetLinkingCode(Guid player)
|
||||
{
|
||||
DbReadOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.GetLinkingCode(player));
|
||||
}
|
||||
|
||||
public Task SetLinkingCode(Guid player, Guid code)
|
||||
{
|
||||
DbWriteOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.SetLinkingCode(player, code));
|
||||
}
|
||||
|
||||
public Task<bool> HasLinkedAccount(Guid player, CancellationToken cancel)
|
||||
{
|
||||
DbReadOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.HasLinkedAccount(player, cancel));
|
||||
}
|
||||
|
||||
public Task<Patron?> GetPatron(Guid player, CancellationToken cancel)
|
||||
{
|
||||
DbReadOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.GetPatron(player, cancel));
|
||||
}
|
||||
|
||||
public Task<List<Patron>> GetAllPatrons()
|
||||
{
|
||||
DbReadOpsMetric.Inc();
|
||||
return RunDbCommand(() => _db.GetAllPatrons());
|
||||
}
|
||||
#endregion
|
||||
// END DeltaV
|
||||
|
||||
|
||||
// Wrapper functions to run DB commands from the thread pool.
|
||||
// This will avoid SynchronizationContext capturing and avoid running CPU work on the main thread.
|
||||
// For SQLite, this will also enable read parallelization (within limits).
|
||||
|
||||
@@ -51,8 +51,11 @@ public sealed class SignalTimerSystem : EntitySystem
|
||||
if (_ui.HasUi(uid, SignalTimerUiKey.Key))
|
||||
{
|
||||
_ui.SetUiState(uid, SignalTimerUiKey.Key, new SignalTimerBoundUserInterfaceState(component.Label,
|
||||
TimeSpan.FromSeconds(component.Delay).Minutes.ToString("D2"),
|
||||
TimeSpan.FromSeconds(component.Delay).Seconds.ToString("D2"),
|
||||
// Begin Monolith
|
||||
// TimeSpan.FromSeconds(component.Delay).Minutes.ToString("D2"),
|
||||
// TimeSpan.FromSeconds(component.Delay).Seconds.ToString("D2"),
|
||||
TimeSpan.FromSeconds(component.Delay),
|
||||
// End Monolith
|
||||
component.CanEditLabel,
|
||||
time,
|
||||
active != null,
|
||||
@@ -73,8 +76,11 @@ public sealed class SignalTimerSystem : EntitySystem
|
||||
if (_ui.HasUi(uid, SignalTimerUiKey.Key))
|
||||
{
|
||||
_ui.SetUiState(uid, SignalTimerUiKey.Key, new SignalTimerBoundUserInterfaceState(signalTimer.Label,
|
||||
TimeSpan.FromSeconds(signalTimer.Delay).Minutes.ToString("D2"),
|
||||
TimeSpan.FromSeconds(signalTimer.Delay).Seconds.ToString("D2"),
|
||||
// Begin Monolith
|
||||
// TimeSpan.FromSeconds(signalTimer.Delay).Minutes.ToString("D2"),
|
||||
// TimeSpan.FromSeconds(signalTimer.Delay).Seconds.ToString("D2"),
|
||||
TimeSpan.FromSeconds(signalTimer.Delay),
|
||||
// End Monolith
|
||||
signalTimer.CanEditLabel,
|
||||
TimeSpan.Zero,
|
||||
false,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Server._DV.AccountLinking; // DeltaV
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Managers;
|
||||
@@ -82,6 +81,5 @@ internal static class ServerContentIoC
|
||||
deps.Register<CVarControlManager>();
|
||||
deps.Register<DiscordLink>();
|
||||
deps.Register<DiscordChatLink>();
|
||||
deps.Register<LinkAccountManager>(); // DeltaV - Discord Account Linking
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ using Content.Shared.Radio.Components;
|
||||
using Content.Shared.Radio.EntitySystems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared._DV.Chat;
|
||||
|
||||
namespace Content.Server.Radio.EntitySystems;
|
||||
|
||||
@@ -27,7 +26,6 @@ public sealed class HeadsetSystem : SharedHeadsetSystem
|
||||
SubscribeLocalEvent<HeadsetComponent, EncryptionChannelsChangedEvent>(OnKeysChanged);
|
||||
|
||||
SubscribeLocalEvent<WearingHeadsetComponent, EntitySpokeEvent>(OnSpeak);
|
||||
SubscribeLocalEvent<WearingHeadsetComponent, EntityAudiblyEmotedEvent>(OnAudibleEmote); // DeltaV
|
||||
}
|
||||
|
||||
private void OnKeysChanged(EntityUid uid, HeadsetComponent component, EncryptionChannelsChangedEvent args)
|
||||
@@ -50,43 +48,22 @@ public sealed class HeadsetSystem : SharedHeadsetSystem
|
||||
EnsureComp<ActiveRadioComponent>(uid).Channels = new(keyHolder.Channels);
|
||||
}
|
||||
|
||||
// DeltaV
|
||||
// WARNING - Be very careful when modifying this method.
|
||||
// The implementation right now has null forgiving operatiors in OnSpeak() and OnAudibleEmote() since this only returns true if channel is not null
|
||||
private bool CheckRadioCapable(EntityUid uid, WearingHeadsetComponent headset, RadioChannelPrototype? channel)
|
||||
private void OnSpeak(EntityUid uid, WearingHeadsetComponent component, EntitySpokeEvent args)
|
||||
{
|
||||
if (channel != null
|
||||
&& TryComp(headset.Headset, out EncryptionKeyHolderComponent? keys)
|
||||
&& keys.Channels.Contains(channel.ID))
|
||||
if (args.Channel != null
|
||||
&& TryComp(component.Headset, out EncryptionKeyHolderComponent? keys)
|
||||
&& keys.Channels.Contains(args.Channel.ID))
|
||||
{
|
||||
// Begin DeltaV Additions: No using headsets if you lost your hands or are cuffed
|
||||
if (!TryComp<HandsComponent>(uid, out var hands) || hands.Count < 1 ||
|
||||
TryComp<CuffableComponent>(uid, out var cuffable) && _cuffable.IsCuffed((uid, cuffable)))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("headset-cant-reach"), uid, uid, PopupType.SmallCaution);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
// End DeltaV Additions
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnAudibleEmote(EntityUid uid, WearingHeadsetComponent component, EntityAudiblyEmotedEvent args)
|
||||
{
|
||||
if (CheckRadioCapable(uid, component, args.Channel))
|
||||
{
|
||||
_radio.SendRadioMessage(uid, args.Message, args.Channel!, component.Headset, emType: args.Type);
|
||||
args.Channel = null;
|
||||
}
|
||||
}
|
||||
// DeltaV - End
|
||||
|
||||
private void OnSpeak(EntityUid uid, WearingHeadsetComponent component, EntitySpokeEvent args)
|
||||
{
|
||||
if (CheckRadioCapable(uid, component, args.Channel)) // DeltaV - Put all the radio checks into the CheckRadioCapable() method.
|
||||
{
|
||||
_radio.SendRadioMessage(uid, args.Message, args.Channel!, component.Headset); // DeltaV - Made the args.Channel null ignorant as CheckRadioCapable() guarantees it not null.
|
||||
_radio.SendRadioMessage(uid, args.Message, args.Channel, component.Headset);
|
||||
args.Channel = null; // prevent duplicate messages from other listeners.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared._DV.Chat;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Radio;
|
||||
@@ -39,7 +38,6 @@ public sealed class RadioSystem : EntitySystem
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<IntrinsicRadioReceiverComponent, RadioReceiveEvent>(OnIntrinsicReceive);
|
||||
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntitySpokeEvent>(OnIntrinsicSpeak);
|
||||
SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntityAudiblyEmotedEvent>(OnIntrinsicAudibleEmote); // DeltaV - Robots should be allowed to emote over radio.
|
||||
|
||||
_exemptQuery = GetEntityQuery<TelecomExemptComponent>();
|
||||
}
|
||||
@@ -59,22 +57,12 @@ public sealed class RadioSystem : EntitySystem
|
||||
_netMan.ServerSendMessage(args.ChatMsg, actor.PlayerSession.Channel);
|
||||
}
|
||||
|
||||
// DeltaV
|
||||
private void OnIntrinsicAudibleEmote(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntityAudiblyEmotedEvent args)
|
||||
{
|
||||
if (args.Channel != null && component.Channels.Contains(args.Channel.ID))
|
||||
{
|
||||
SendRadioMessage(uid, args.Message, args.Channel, uid, emType: args.Type);
|
||||
}
|
||||
}
|
||||
// DeltaV - End
|
||||
|
||||
/// <summary>
|
||||
/// Send radio message to all active radio listeners
|
||||
/// </summary>
|
||||
public void SendRadioMessage(EntityUid messageSource, string message, ProtoId<RadioChannelPrototype> channel, EntityUid radioSource, bool escapeMarkup = true, EmoteType? emType = null) // DeltaV - EmoteType? added.
|
||||
public void SendRadioMessage(EntityUid messageSource, string message, ProtoId<RadioChannelPrototype> channel, EntityUid radioSource, bool escapeMarkup = true)
|
||||
{
|
||||
SendRadioMessage(messageSource, message, _prototype.Index(channel), radioSource, escapeMarkup: escapeMarkup, emType: emType);
|
||||
SendRadioMessage(messageSource, message, _prototype.Index(channel), radioSource, escapeMarkup: escapeMarkup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -82,7 +70,7 @@ public sealed class RadioSystem : EntitySystem
|
||||
/// </summary>
|
||||
/// <param name="messageSource">Entity that spoke the message</param>
|
||||
/// <param name="radioSource">Entity that picked up the message and will send it, e.g. headset</param>
|
||||
public void SendRadioMessage(EntityUid messageSource, string message, RadioChannelPrototype channel, EntityUid radioSource, bool escapeMarkup = true, EmoteType? emType = null) // DeltaV - EmoteType? added.
|
||||
public void SendRadioMessage(EntityUid messageSource, string message, RadioChannelPrototype channel, EntityUid radioSource, bool escapeMarkup = true)
|
||||
{
|
||||
// TODO if radios ever garble / modify messages, feedback-prevention needs to be handled better than this.
|
||||
if (!_messages.Add(message))
|
||||
@@ -104,31 +92,14 @@ public sealed class RadioSystem : EntitySystem
|
||||
? FormattedMessage.EscapeText(message)
|
||||
: message;
|
||||
|
||||
// DeltaV - This change is to change up how the messages are wrapped up. Basically changing the formatting depending on the emote type.
|
||||
string wrappedMessage;
|
||||
|
||||
if (emType == EmoteType.Audible)
|
||||
wrappedMessage = Loc.GetString("chat-radio-message-audible-emote-wrap",
|
||||
("color", channel.Color),
|
||||
("channel", $"\\[{channel.LocalizedName}\\]"),
|
||||
("name", name),
|
||||
("message", content));
|
||||
else if (emType == EmoteType.AudiblePossessive)
|
||||
wrappedMessage = Loc.GetString("chat-radio-message-audible-possessive-emote-wrap",
|
||||
("color", channel.Color),
|
||||
("channel", $"\\[{channel.LocalizedName}\\]"),
|
||||
("name", name),
|
||||
("message", content));
|
||||
else
|
||||
wrappedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap",
|
||||
("color", channel.Color),
|
||||
("fontType", speech.FontId),
|
||||
("fontSize", speech.FontSize),
|
||||
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
|
||||
("channel", $"\\[{channel.LocalizedName}\\]"),
|
||||
("name", name),
|
||||
("message", content));
|
||||
// DeltaV - End
|
||||
var wrappedMessage = Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap",
|
||||
("color", channel.Color),
|
||||
("fontType", speech.FontId),
|
||||
("fontSize", speech.FontSize),
|
||||
("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
|
||||
("channel", $"\\[{channel.LocalizedName}\\]"),
|
||||
("name", name),
|
||||
("message", content));
|
||||
|
||||
// most radios are relayed to chat, so lets parse the chat message beforehand
|
||||
var chat = new ChatMessage(
|
||||
|
||||
@@ -27,11 +27,6 @@ public sealed partial class BorgSystem
|
||||
var query = EntityQueryEnumerator<BorgTransponderComponent, BorgChassisComponent, DeviceNetworkComponent, MetaDataComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp, out var chassis, out var device, out var meta))
|
||||
{
|
||||
// DeltaV Begin
|
||||
if (!comp.Active)
|
||||
return;
|
||||
// DeltaV End
|
||||
|
||||
if (comp.NextDisable is { } nextDisable && now >= nextDisable)
|
||||
DoDisable((uid, comp, chassis, meta));
|
||||
|
||||
@@ -88,11 +83,6 @@ public sealed partial class BorgSystem
|
||||
|
||||
private void OnPacketReceived(Entity<BorgTransponderComponent> ent, ref DeviceNetworkPacketEvent args)
|
||||
{
|
||||
// DeltaV Begin
|
||||
if (!ent.Comp.Active)
|
||||
return;
|
||||
// DeltaV End
|
||||
|
||||
var payload = args.Data;
|
||||
if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command))
|
||||
return;
|
||||
@@ -207,17 +197,4 @@ public sealed partial class BorgSystem
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// DeltaV Begin
|
||||
/// <summary>
|
||||
/// DeltaV - sets if the borg transponder is active
|
||||
/// </summary>
|
||||
public void SetTransponderActive(Entity<BorgTransponderComponent?> ent, bool active)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
ent.Comp.Active = active;
|
||||
}
|
||||
// DeltaV End
|
||||
}
|
||||
|
||||
@@ -29,14 +29,12 @@ public sealed partial class SpeechWireAction : ComponentWireAction<SpeechCompone
|
||||
public override bool Cut(EntityUid user, Wire wire, SpeechComponent component)
|
||||
{
|
||||
_speech.SetSpeech(wire.Owner, false, component);
|
||||
EntityManager.GetComponentOrNull<Components.UnblockableSpeechComponent>(user)?.Active = false; // DeltaV - we need this to override unblockable speech
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, SpeechComponent component)
|
||||
{
|
||||
_speech.SetSpeech(wire.Owner, true, component);
|
||||
EntityManager.GetComponentOrNull<Components.UnblockableSpeechComponent>(user)?.Active = true; // DeltaV - we need this to override unblockable speech
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,5 @@ namespace Content.Server.Speech.Components
|
||||
[RegisterComponent]
|
||||
public sealed partial class UnblockableSpeechComponent : Component
|
||||
{
|
||||
// Begin DeltaV
|
||||
[DataField]
|
||||
public bool Active = true;
|
||||
// End DeltaV
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Content.Server.Speech.EntitySystems
|
||||
|
||||
private void OnCheck(EntityUid uid, UnblockableSpeechComponent component, CheckIgnoreSpeechBlockerEvent args)
|
||||
{
|
||||
args.IgnoreBlocker = component.Active; // DeltaV
|
||||
args.IgnoreBlocker = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared._DV.AccountLinking;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountManager : IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly UserDbDataManager _userDb = default!;
|
||||
|
||||
private readonly Dictionary<NetUserId, TimeSpan> _lastRequest = new();
|
||||
private readonly TimeSpan _minimumWait = TimeSpan.FromSeconds(0.5);
|
||||
private readonly Dictionary<NetUserId, SharedPatronFull> _connected = new();
|
||||
private readonly List<SharedPatron> _allPatrons = [];
|
||||
|
||||
private async Task LoadData(ICommonSession player, CancellationToken cancel)
|
||||
{
|
||||
var patron = await _db.GetPatron(player.UserId, cancel);
|
||||
var linked = await _db.HasLinkedAccount(player.UserId, cancel);
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
|
||||
var tier = patron?.Tier;
|
||||
var sharedTier = tier == null
|
||||
? null
|
||||
: new SharedPatronTier(
|
||||
tier.ShowOnCredits,
|
||||
tier.Name
|
||||
);
|
||||
|
||||
_connected[player.UserId] = new SharedPatronFull(sharedTier, linked);
|
||||
}
|
||||
|
||||
private void FinishLoad(ICommonSession player)
|
||||
{
|
||||
SendPatronStatus(player);
|
||||
}
|
||||
|
||||
private void ClientDisconnected(ICommonSession player)
|
||||
{
|
||||
_connected.Remove(player.UserId);
|
||||
}
|
||||
|
||||
private void SendPatronStatus(ICommonSession player)
|
||||
{
|
||||
var connected = _connected.GetValueOrDefault(player.UserId);
|
||||
var msg = new LinkAccountStatusMsg { Patron = connected, };
|
||||
_net.ServerSendMessage(msg, player.Channel);
|
||||
SendPatrons(player);
|
||||
}
|
||||
|
||||
private void OnRequest(LinkAccountRequestMsg message)
|
||||
{
|
||||
var user = message.MsgChannel.UserId;
|
||||
var time = _timing.RealTime;
|
||||
if (_lastRequest.TryGetValue(user, out var last) &&
|
||||
last + _minimumWait > time)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastRequest[user] = time;
|
||||
|
||||
var code = Guid.NewGuid();
|
||||
_db.SetLinkingCode(user, code);
|
||||
|
||||
var response = new LinkAccountCodeMsg { Code = code };
|
||||
_net.ServerSendMessage(response, message.MsgChannel);
|
||||
}
|
||||
|
||||
public async Task RefreshAllPatrons()
|
||||
{
|
||||
var patrons = await _db.GetAllPatrons();
|
||||
|
||||
_allPatrons.Clear();
|
||||
foreach (var patron in patrons)
|
||||
{
|
||||
_allPatrons.Add(new SharedPatron(patron.Player.LastSeenUserName, patron.Tier.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public void SendPatronsToAll()
|
||||
{
|
||||
var msg = new PatronListMsg { Patrons = _allPatrons };
|
||||
_net.ServerSendToAll(msg);
|
||||
}
|
||||
|
||||
public void SendPatrons(ICommonSession player)
|
||||
{
|
||||
var msg = new PatronListMsg { Patrons = _allPatrons };
|
||||
_net.ServerSendMessage(msg, player.Channel);
|
||||
}
|
||||
|
||||
public SharedPatronFull? GetPatron(ICommonSession player)
|
||||
{
|
||||
return GetPatron(player.UserId);
|
||||
}
|
||||
|
||||
public SharedPatronFull? GetPatron(NetUserId userId)
|
||||
{
|
||||
return _connected.GetValueOrDefault(userId);
|
||||
}
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_net.RegisterNetMessage<LinkAccountRequestMsg>(OnRequest);
|
||||
_net.RegisterNetMessage<LinkAccountCodeMsg>();
|
||||
_net.RegisterNetMessage<LinkAccountStatusMsg>();
|
||||
_net.RegisterNetMessage<PatronListMsg>();
|
||||
_userDb.AddOnLoadPlayer(LoadData);
|
||||
_userDb.AddOnFinishLoad(FinishLoad);
|
||||
_userDb.AddOnPlayerDisconnect(ClientDisconnected);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Content.Server.GameTicking;
|
||||
|
||||
namespace Content.Server._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountSystem : EntitySystem
|
||||
{
|
||||
|
||||
[Dependency] private readonly LinkAccountManager _linkAccount = default!;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
||||
|
||||
ReloadPatrons();
|
||||
}
|
||||
|
||||
private void OnGameRunLevelChanged(GameRunLevelChangedEvent ev)
|
||||
{
|
||||
switch (ev.New)
|
||||
{
|
||||
case GameRunLevel.InRound:
|
||||
break;
|
||||
case GameRunLevel.PreRoundLobby:
|
||||
case GameRunLevel.PostRound:
|
||||
ReloadPatrons();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async void ReloadPatrons()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _linkAccount.RefreshAllPatrons();
|
||||
_linkAccount.SendPatronsToAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Error reloading Patrons list:\n{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server._DV.Psionics.Systems;
|
||||
using Content.Shared._DV.Psionics.Components;
|
||||
using Content.Shared._DV.Traits.Assorted;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Roles.Components;
|
||||
@@ -18,12 +17,10 @@ public sealed partial class ParadoxCloneRuleSystem
|
||||
private void FilterTargets(HashSet<Entity<MindComponent>> minds)
|
||||
{
|
||||
// TODO: use generic IMindFilter
|
||||
// no picking other antags or non-crew and entities with no paradox clone trait
|
||||
// no picking other antags or non-crew
|
||||
minds.RemoveWhere(mind => _role.MindIsAntagonist(mind) ||
|
||||
!_role.MindHasRole<JobRoleComponent>((mind, mind), out var role) ||
|
||||
role?.Comp1.JobPrototype == null ||
|
||||
(mind.Comp.OwnedEntity is { } entity && HasComp<NoParadoxCloneComponent>(entity))
|
||||
);
|
||||
role?.Comp1.JobPrototype == null);
|
||||
}
|
||||
|
||||
private void PostClone(EntityUid mob)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared._DV.Silicons.Borgs;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server._DV.Silicons;
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether the cyborg's ID chip slot is active
|
||||
/// </summary>
|
||||
public sealed partial class BorgIdChipWireAction : ComponentWireAction<IdChipSlotComponent>
|
||||
{
|
||||
public override string Name { get; set; } = "wire-name-borg-id-chip";
|
||||
public override Color Color { get; set; } = Color.Thistle;
|
||||
public override object StatusKey => BorgWireActionKey.ChipKey;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, IdChipSlotComponent component)
|
||||
{
|
||||
return component.Active ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, IdChipSlotComponent component)
|
||||
{
|
||||
EntityManager.System<IdChipSlotSystem>()
|
||||
.SetActive((wire.Owner, component), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, IdChipSlotComponent component)
|
||||
{
|
||||
EntityManager.System<IdChipSlotSystem>()
|
||||
.SetActive((wire.Owner, component), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, IdChipSlotComponent component)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using Content.Server.Silicons.Borgs;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server._DV.Silicons;
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether the cyborg's transponder is active
|
||||
/// </summary>
|
||||
public sealed partial class BorgTransponderWireAction : ComponentWireAction<BorgTransponderComponent>
|
||||
{
|
||||
public override string Name { get; set; } = "wire-name-borg-transponder";
|
||||
public override Color Color { get; set; } = Color.YellowGreen;
|
||||
public override object StatusKey => BorgWireActionKey.TransponderKey;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, BorgTransponderComponent component)
|
||||
{
|
||||
return component.Active ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, BorgTransponderComponent component)
|
||||
{
|
||||
EntityManager.System<BorgSystem>()
|
||||
.SetTransponderActive((wire.Owner, component), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, BorgTransponderComponent component)
|
||||
{
|
||||
EntityManager.System<BorgSystem>()
|
||||
.SetTransponderActive((wire.Owner, component), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, BorgTransponderComponent component)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ namespace Content.Server._DV.Silicons.Laws;
|
||||
public sealed class SlavedBorgSystem : SharedSlavedBorgSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly SharedSiliconLawSystem _siliconLaws = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -25,12 +24,12 @@ public sealed class SlavedBorgSystem : SharedSlavedBorgSystem
|
||||
|
||||
private void OnGetSiliconLaws(Entity<SlavedBorgComponent> ent, ref GetSiliconLawsEvent args)
|
||||
{
|
||||
if (ent.Comp.HasBeenAdded || !TryComp<SiliconLawProviderComponent>(ent, out var provider))
|
||||
if (ent.Comp.Added || !TryComp<SiliconLawProviderComponent>(ent, out var provider))
|
||||
return;
|
||||
|
||||
if (provider.Lawset is {} lawset && ent.Comp.ShouldBeAdded)
|
||||
if (provider.Lawset is {} lawset)
|
||||
AddLaw(lawset, ent.Comp.Law);
|
||||
ent.Comp.HasBeenAdded = true; // prevent opening the ui adding more law 0's
|
||||
ent.Comp.Added = true; // prevent opening the ui adding more law 0's
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,30 +39,4 @@ public sealed class SlavedBorgSystem : SharedSlavedBorgSystem
|
||||
{
|
||||
lawset.Laws.Insert(0, _proto.Index(law).ShallowClone());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the slaving is active.
|
||||
/// </summary>
|
||||
public void SetShouldBeAdded(Entity<SlavedBorgComponent?> ent, bool active)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
if (!TryComp<SiliconLawProviderComponent>(ent, out var provider) || provider.Lawset is not { } lawset)
|
||||
return;
|
||||
|
||||
if (!ent.Comp.ShouldBeAdded && active)
|
||||
{
|
||||
AddLaw(lawset, ent.Comp.Law);
|
||||
ent.Comp.HasBeenAdded = true;
|
||||
_siliconLaws.NotifyLawsChanged(ent);
|
||||
}
|
||||
else if (ent.Comp.ShouldBeAdded && !active)
|
||||
{
|
||||
lawset.Laws.Remove(_proto.Index(ent.Comp.Law));
|
||||
ent.Comp.HasBeenAdded = false;
|
||||
_siliconLaws.NotifyLawsChanged(ent);
|
||||
}
|
||||
ent.Comp.ShouldBeAdded = active;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.PowerCell;
|
||||
using Content.Shared.PowerCell.Components;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server._DV.Silicons;
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether the power cell slot is active
|
||||
/// </summary>
|
||||
public sealed partial class PowerCellSlotWireAction : ComponentWireAction<PowerCellSlotComponent>
|
||||
{
|
||||
public override string Name { get; set; } = "wire-name-power-cell";
|
||||
public override Color Color { get; set; } = Color.BurlyWood;
|
||||
public override object StatusKey => BorgWireActionKey.CellKey;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, PowerCellSlotComponent component)
|
||||
{
|
||||
return component.Active ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, PowerCellSlotComponent component)
|
||||
{
|
||||
EntityManager.System<PowerCellSystem>()
|
||||
.SetSlotActive((wire.Owner, component), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, PowerCellSlotComponent component)
|
||||
{
|
||||
EntityManager.System<PowerCellSystem>()
|
||||
.SetSlotActive((wire.Owner, component), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, PowerCellSlotComponent component)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using Content.Server._DV.Silicons.Laws;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared._DV.Silicons.Laws;
|
||||
using Content.Shared._DV.Silicons;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server._DV.Silicons;
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether the cyborg's transponder is active
|
||||
/// </summary>
|
||||
public sealed partial class SlavedBorgWireAction : ComponentWireAction<SlavedBorgComponent>
|
||||
{
|
||||
public override string Name { get; set; } = "wire-name-slaved-borg";
|
||||
public override Color Color { get; set; } = Color.Coral;
|
||||
public override object StatusKey => BorgWireActionKey.SlavedKey;
|
||||
|
||||
public override StatusLightState? GetLightState(Wire wire, SlavedBorgComponent component)
|
||||
{
|
||||
return component.ShouldBeAdded ? StatusLightState.On : StatusLightState.Off;
|
||||
}
|
||||
|
||||
public override bool Cut(EntityUid user, Wire wire, SlavedBorgComponent component)
|
||||
{
|
||||
EntityManager.System<SlavedBorgSystem>()
|
||||
.SetShouldBeAdded((wire.Owner, component), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Mend(EntityUid user, Wire wire, SlavedBorgComponent component)
|
||||
{
|
||||
EntityManager.System<SlavedBorgSystem>()
|
||||
.SetShouldBeAdded((wire.Owner, component), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire, SlavedBorgComponent component)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -33,33 +33,37 @@ public sealed class InteractorSystem : SharedInteractorSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var i = count - 1;
|
||||
var netEnt = ent.Comp.TargetEntities[i].Item1;
|
||||
var target = GetEntity(netEnt);
|
||||
_constructionQuery.TryComp(target, out var construction);
|
||||
var originalCount = construction?.InteractionQueue?.Count ?? 0;
|
||||
if (!InteractWith(ent, target))
|
||||
// Mono
|
||||
for (var i = count - 1; i >= 0; i--)
|
||||
{
|
||||
// have to remove it since user's filter was bad due to unhandled interaction
|
||||
RemoveTarget(ent, target);
|
||||
Machine.Failed(ent.Owner);
|
||||
return;
|
||||
}
|
||||
var netEnt = ent.Comp.TargetEntities[i].Item1;
|
||||
var target = GetEntity(netEnt);
|
||||
_constructionQuery.TryComp(target, out var construction);
|
||||
var originalCount = construction?.InteractionQueue?.Count ?? 0;
|
||||
if (!InteractWith(ent, target))
|
||||
{
|
||||
// have to remove it since user's filter was bad due to unhandled interaction
|
||||
// RemoveTarget(ent, target); // Mono
|
||||
Machine.Failed(ent.Owner);
|
||||
continue; // Mono
|
||||
}
|
||||
|
||||
// construction supercode queues it instead of starting a doafter now, assume that queuing means it has started
|
||||
var newCount = construction?.InteractionQueue?.Count ?? 0;
|
||||
if (newCount > originalCount
|
||||
|| HasDoAfter(ent))
|
||||
{
|
||||
Machine.Started(ent.Owner);
|
||||
UpdateAppearance(ent, InteractorState.Active);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no doafter, complete it immediately
|
||||
TryRemoveTarget(ent, target);
|
||||
Machine.Completed(ent.Owner);
|
||||
UpdateAppearance(ent);
|
||||
// construction supercode queues it instead of starting a doafter now, assume that queuing means it has started
|
||||
var newCount = construction?.InteractionQueue?.Count ?? 0;
|
||||
if (newCount > originalCount
|
||||
|| HasDoAfter(ent))
|
||||
{
|
||||
Machine.Started(ent.Owner);
|
||||
UpdateAppearance(ent, InteractorState.Active);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no doafter, complete it immediately
|
||||
TryRemoveTarget(ent, target);
|
||||
Machine.Completed(ent.Owner);
|
||||
UpdateAppearance(ent);
|
||||
}
|
||||
break; // Mono
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._Goobstation.Lathe;
|
||||
|
||||
/// <summary>
|
||||
/// Lets a lathe produce the last made recipe, controlled by signal port.
|
||||
/// The port must be added by something else e.g. AutomationSlots
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(LatheAutomationSystem))]
|
||||
public sealed partial class LatheAutomationComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public LatheRecipePrototype? LastRecipe;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<SinkPortPrototype> PrintPort = "LathePrint";
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Content.Shared._Goobstation.Factory;
|
||||
using Content.Server.Lathe;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
using Content.Shared.Lathe;
|
||||
|
||||
namespace Content.Server._Goobstation.Lathe;
|
||||
|
||||
public sealed class LatheAutomationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AutomationSystem _automation = default!;
|
||||
[Dependency] private readonly LatheSystem _lathe = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LatheAutomationComponent, LatheStartPrintingEvent>(OnStartPrinting);
|
||||
SubscribeLocalEvent<LatheAutomationComponent, SignalReceivedEvent>(OnSignalReceived);
|
||||
}
|
||||
|
||||
private void OnStartPrinting(Entity<LatheAutomationComponent> ent, ref LatheStartPrintingEvent args)
|
||||
{
|
||||
ent.Comp.LastRecipe = args.Recipe;
|
||||
}
|
||||
|
||||
private void OnSignalReceived(Entity<LatheAutomationComponent> ent, ref SignalReceivedEvent args)
|
||||
{
|
||||
if (!_automation.IsAutomated(ent))
|
||||
return;
|
||||
|
||||
if (args.Port != ent.Comp.PrintPort)
|
||||
return;
|
||||
|
||||
if (ent.Comp.LastRecipe is not {} recipe)
|
||||
return;
|
||||
|
||||
_lathe.TryAddToQueue(ent.Owner, recipe, 1);
|
||||
_lathe.TryStartProducing(ent.Owner); // Won't do anything otherwise
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Immutable;
|
||||
using Content.Shared._DV.Chat; // DeltaV - chat
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Speech;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -99,7 +98,7 @@ public abstract partial class SharedChatSystem
|
||||
{
|
||||
// not all emotes are loc'd, but for the ones that are we pass in entity
|
||||
var action = Loc.GetString(_random.Pick(emote.ChatMessages), ("entity", source));
|
||||
SendEntityEmote(source, action, range, nameOverride, null, hideLog: hideLog, checkEmote: false, ignoreActionBlocker: ignoreActionBlocker); // DeltaV
|
||||
SendEntityEmote(source, action, range, nameOverride, hideLog: hideLog, checkEmote: false, ignoreActionBlocker: ignoreActionBlocker);
|
||||
}
|
||||
|
||||
return didEmote;
|
||||
@@ -209,48 +208,6 @@ public abstract partial class SharedChatSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
// DeltaV
|
||||
/// <summary>
|
||||
/// Checks which type of emote the message contains and returns the type while outputting the string without the prefixes.
|
||||
/// </summary>
|
||||
public static EmoteType? ProcessEmoteMessage(EntityUid source, string input, out string output)
|
||||
{
|
||||
output = input.Trim();
|
||||
EmoteType? type = null;
|
||||
|
||||
if (input.Length == 0)
|
||||
return type;
|
||||
|
||||
if (!(input.StartsWith(AudibleEmotePrefix) || input.StartsWith(PossessiveEmotePrefix)))
|
||||
{
|
||||
type = EmoteType.Normal;
|
||||
return type;
|
||||
}
|
||||
|
||||
var emoteType = input[0];
|
||||
output = input[1..].TrimStart();
|
||||
|
||||
if (emoteType == AudibleEmotePrefix)
|
||||
{
|
||||
emoteType = input[1]; // Check for if we want AudiblePossessiveEmote
|
||||
type = EmoteType.Audible;
|
||||
}
|
||||
|
||||
if (emoteType == PossessiveEmotePrefix)
|
||||
{
|
||||
if (type == EmoteType.Audible)
|
||||
{
|
||||
type = EmoteType.AudiblePossessive;
|
||||
output = input[2..].TrimStart();
|
||||
}
|
||||
else
|
||||
type = EmoteType.Possessive;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
// DeltaV - End
|
||||
|
||||
/// <summary>
|
||||
/// Creates and raises <see cref="BeforeEmoteEvent"/> and then <see cref="EmoteEvent"/> to let other systems do things like play audio.
|
||||
/// In the case that the Before event is cancelled, EmoteEvent will NOT be raised, and will optionally show a message to the player
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Shared._DV.Chat;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Popups;
|
||||
@@ -30,8 +29,6 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
public const char OOCPrefix = '[';
|
||||
public const char EmotesPrefix = '@';
|
||||
public const char EmotesAltPrefix = '*';
|
||||
public const char AudibleEmotePrefix = '!'; // DeltaV - You may now scream audibly!
|
||||
public const char PossessiveEmotePrefix = '\''; // DeltaV - You may now be possessive of things! Whatever that means.
|
||||
public const char AdminPrefix = ']';
|
||||
public const char WhisperPrefix = ',';
|
||||
public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix.
|
||||
@@ -155,7 +152,6 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
string input,
|
||||
out string output,
|
||||
out RadioChannelPrototype? channel,
|
||||
bool capitalize = true, // DeltaV - We might not want to capitalize the first letter if we send in emotes.
|
||||
bool quiet = false)
|
||||
{
|
||||
output = input.Trim();
|
||||
@@ -166,7 +162,7 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
|
||||
if (input.StartsWith(RadioCommonPrefix))
|
||||
{
|
||||
output = capitalize ? SanitizeMessageCapital(input[1..].TrimStart()) : input[1..].TrimStart(); // DeltaV
|
||||
output = SanitizeMessageCapital(input[1..].TrimStart());
|
||||
channel = _prototypeManager.Index<RadioChannelPrototype>(CommonChannel);
|
||||
return true;
|
||||
}
|
||||
@@ -176,7 +172,7 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
|
||||
if (input.Length < 2 || char.IsWhiteSpace(input[1]))
|
||||
{
|
||||
output = capitalize ? SanitizeMessageCapital(input[1..].TrimStart()) : input[1..].TrimStart(); // DeltaV
|
||||
output = SanitizeMessageCapital(input[1..].TrimStart());
|
||||
if (!quiet)
|
||||
_popup.PopupEntity(Loc.GetString("chat-manager-no-radio-key"), source, source);
|
||||
return true;
|
||||
@@ -184,7 +180,7 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
|
||||
var channelKey = input[1];
|
||||
channelKey = char.ToLower(channelKey);
|
||||
output = capitalize ? SanitizeMessageCapital(input[2..].TrimStart()) : input[2..].TrimStart(); // DeltaV
|
||||
output = SanitizeMessageCapital(input[2..].TrimStart());
|
||||
|
||||
if (channelKey == DefaultChannelKey)
|
||||
{
|
||||
@@ -318,29 +314,11 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
return rawmsg.Substring(tagStart, tagEnd - tagStart);
|
||||
}
|
||||
|
||||
// DeltaV
|
||||
protected virtual void SendAudibleEntityEmote(
|
||||
EntityUid source,
|
||||
string action,
|
||||
ChatTransmitRange range,
|
||||
string? nameOverride,
|
||||
RadioChannelPrototype? channel,
|
||||
EmoteType? emoteType,
|
||||
bool hideLog = false,
|
||||
bool checkEmote = true,
|
||||
bool ignoreActionBlocker = false,
|
||||
NetUserId? author = null
|
||||
)
|
||||
{
|
||||
}
|
||||
// DeltaV - End
|
||||
|
||||
protected virtual void SendEntityEmote(
|
||||
EntityUid source,
|
||||
string action,
|
||||
ChatTransmitRange range,
|
||||
string? nameOverride,
|
||||
EmoteType? emoteType,
|
||||
bool hideLog = false,
|
||||
bool checkEmote = true,
|
||||
bool ignoreActionBlocker = false,
|
||||
|
||||
@@ -17,17 +17,6 @@ namespace Content.Shared.Humanoid
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
// DeltaV - i hate this hack but https://github.com/space-wizards/RobustToolbox/issues/6576
|
||||
private ISawmill _locSawmill = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_locSawmill = Logger.GetSawmill("loc");
|
||||
}
|
||||
// End DeltaV - i hate this hack
|
||||
|
||||
public string GetName(string species, Gender? gender = null)
|
||||
{
|
||||
// if they have an old species or whatever just fall back to human I guess?
|
||||
@@ -58,67 +47,31 @@ namespace Content.Shared.Humanoid
|
||||
return Loc.GetString("namepreset-lastfirst",
|
||||
("last", GetLastName(speciesProto)), ("first", GetFirstName(speciesProto, gender)));
|
||||
case SpeciesNaming.FirstLast:
|
||||
// Begin DeltaV - more complex naming
|
||||
default:
|
||||
{
|
||||
var firstId = GetFirstNameId(speciesProto, gender);
|
||||
var lastId = GetLastNameId(speciesProto);
|
||||
var plural = false;
|
||||
|
||||
var oldLevel =_locSawmill.Level;
|
||||
_locSawmill.Level = LogLevel.Fatal; // this is a hack to avoid testfails because TryGetString still logs errors for not-found stuff anyways (wtf)
|
||||
if (Loc.TryGetString($"{lastId}.plural", out var pluralStr))
|
||||
plural = pluralStr == "true";
|
||||
|
||||
var last = Loc.GetString(lastId);
|
||||
|
||||
if (Loc.TryGetString($"{firstId}.intersperse", out var firstIntersperse, ("last", last), ("lastPlural", plural)))
|
||||
{
|
||||
_locSawmill.Level = oldLevel;
|
||||
return firstIntersperse;
|
||||
}
|
||||
|
||||
_locSawmill.Level = oldLevel;
|
||||
return Loc.GetString("namepreset-firstlast",
|
||||
("first", Loc.GetString(firstId)),
|
||||
("last", last),
|
||||
("lastPlural", plural));
|
||||
}
|
||||
// End DeltaV - more complex naming
|
||||
("first", GetFirstName(speciesProto, gender)), ("last", GetLastName(speciesProto)));
|
||||
}
|
||||
}
|
||||
|
||||
// Begin DeltaV - we want IDs
|
||||
public string GetFirstName(SpeciesPrototype speciesProto, Gender? gender = null)
|
||||
{
|
||||
return Loc.GetString(GetFirstNameId(speciesProto, gender));
|
||||
}
|
||||
|
||||
public string GetFirstNameId(SpeciesPrototype speciesProto, Gender? gender = null)
|
||||
{
|
||||
switch (gender)
|
||||
{
|
||||
case Gender.Male:
|
||||
return _random.PickId(_prototypeManager.Index(speciesProto.MaleFirstNames));
|
||||
return _random.Pick(_prototypeManager.Index(speciesProto.MaleFirstNames));
|
||||
case Gender.Female:
|
||||
return _random.PickId(_prototypeManager.Index(speciesProto.FemaleFirstNames));
|
||||
return _random.Pick(_prototypeManager.Index(speciesProto.FemaleFirstNames));
|
||||
default:
|
||||
if (_random.Prob(0.5f))
|
||||
return _random.PickId(_prototypeManager.Index(speciesProto.MaleFirstNames));
|
||||
return _random.Pick(_prototypeManager.Index(speciesProto.MaleFirstNames));
|
||||
else
|
||||
return _random.PickId(_prototypeManager.Index(speciesProto.FemaleFirstNames));
|
||||
return _random.Pick(_prototypeManager.Index(speciesProto.FemaleFirstNames));
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLastNameId(SpeciesPrototype speciesProto)
|
||||
{
|
||||
return _random.PickId(_prototypeManager.Index(speciesProto.LastNames));
|
||||
}
|
||||
|
||||
public string GetLastName(SpeciesPrototype speciesProto)
|
||||
{
|
||||
return Loc.GetString(GetLastNameId(speciesProto));
|
||||
return _random.Pick(_prototypeManager.Index(speciesProto.LastNames));
|
||||
}
|
||||
// End DeltaV - we want IDs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,6 @@ public sealed class ActivateInWorldEvent : HandledEntityEventArgs, ITargetedInte
|
||||
/// </summary>
|
||||
public bool WasLogged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stellar - set to false if this interaction shouldn't have an interaction particle
|
||||
/// </summary>
|
||||
public bool InteractionParticle = true;
|
||||
|
||||
public ActivateInWorldEvent(EntityUid user, EntityUid target, bool complex)
|
||||
{
|
||||
User = user;
|
||||
|
||||
@@ -1189,7 +1189,7 @@ namespace Content.Shared.Interaction
|
||||
RaiseLocalEvent(used, activateMsg, true);
|
||||
if (activateMsg.Handled)
|
||||
{
|
||||
DoContactInteraction(user, used, null, true, interactionParticles: activateMsg.InteractionParticle); // Stellar - Interaction particles
|
||||
DoContactInteraction(user, used, null, true); // Interaction particles
|
||||
if (!activateMsg.WasLogged)
|
||||
_adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user):user} activated {ToPrettyString(used):used}");
|
||||
|
||||
|
||||
@@ -15,24 +15,33 @@ public enum SignalTimerUiKey : byte
|
||||
public sealed class SignalTimerBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public string CurrentText;
|
||||
public string CurrentDelayMinutes;
|
||||
public string CurrentDelaySeconds;
|
||||
// Begin Monolith
|
||||
// public string CurrentDelayMinutes;
|
||||
// public string CurrentDelaySeconds;
|
||||
public TimeSpan CurrentDelay;
|
||||
// End Monolith
|
||||
public bool ShowText;
|
||||
public TimeSpan TriggerTime;
|
||||
public bool TimerStarted;
|
||||
public bool HasAccess;
|
||||
|
||||
public SignalTimerBoundUserInterfaceState(string currentText,
|
||||
string currentDelayMinutes,
|
||||
string currentDelaySeconds,
|
||||
// Begin Monolith
|
||||
// string currentDelayMinutes,
|
||||
// string currentDelaySeconds,
|
||||
TimeSpan currentDelay,
|
||||
// End Monolith
|
||||
bool showText,
|
||||
TimeSpan triggerTime,
|
||||
bool timerStarted,
|
||||
bool hasAccess)
|
||||
{
|
||||
CurrentText = currentText;
|
||||
CurrentDelayMinutes = currentDelayMinutes;
|
||||
CurrentDelaySeconds = currentDelaySeconds;
|
||||
// Begin Monolith
|
||||
// CurrentDelayMinutes = currentDelayMinutes;
|
||||
// CurrentDelaySeconds = currentDelaySeconds;
|
||||
CurrentDelay = currentDelay;
|
||||
// End Monolith
|
||||
ShowText = showText;
|
||||
TriggerTime = triggerTime;
|
||||
TimerStarted = timerStarted;
|
||||
|
||||
@@ -23,12 +23,5 @@ public sealed partial class PowerCellSlotComponent : Component
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool FitsInCharger = true;
|
||||
|
||||
// Begin DeltaV
|
||||
/// <summary>
|
||||
/// DeltaV - power cell slots
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Active = true;
|
||||
// End DeltaV
|
||||
}
|
||||
|
||||
|
||||
@@ -39,14 +39,6 @@ public sealed partial class PowerCellSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin DeltaV
|
||||
if (!ent.Comp.Active)
|
||||
{
|
||||
battery = null;
|
||||
return false;
|
||||
}
|
||||
// End DeltaV
|
||||
|
||||
if (!_itemSlots.TryGetSlot(ent.Owner, ent.Comp.CellSlotId, out var slot))
|
||||
{
|
||||
battery = null;
|
||||
@@ -161,21 +153,6 @@ public sealed partial class PowerCellSystem
|
||||
[PublicAPI]
|
||||
public bool HasCharge(Entity<PowerCellSlotComponent?> ent, float charge, EntityUid? user = null, bool predicted = false)
|
||||
{
|
||||
// Begin DeltaV
|
||||
if (Resolve(ent, ref ent.Comp, false) && !ent.Comp.Active)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
if (predicted)
|
||||
_popup.PopupClient(Loc.GetString("power-cell-disabled"), ent.Owner, user.Value);
|
||||
else
|
||||
_popup.PopupEntity(Loc.GetString("power-cell-disabled"), ent.Owner, user.Value);
|
||||
|
||||
return false;
|
||||
}
|
||||
// End DeltaV
|
||||
|
||||
if (!TryGetBatteryFromSlot(ent, out var battery))
|
||||
{
|
||||
if (user == null)
|
||||
@@ -215,21 +192,6 @@ public sealed partial class PowerCellSystem
|
||||
[PublicAPI]
|
||||
public bool TryUseCharge(Entity<PowerCellSlotComponent?> ent, float charge, EntityUid? user = null, bool predicted = false)
|
||||
{
|
||||
// Begin DeltaV
|
||||
if (Resolve(ent, ref ent.Comp, false) && !ent.Comp.Active)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
if (predicted)
|
||||
_popup.PopupClient(Loc.GetString("power-cell-disabled"), ent.Owner, user.Value);
|
||||
else
|
||||
_popup.PopupEntity(Loc.GetString("power-cell-disabled"), ent.Owner, user.Value);
|
||||
|
||||
return false;
|
||||
}
|
||||
// End DeltaV
|
||||
|
||||
if (!TryGetBatteryFromSlot(ent, out var battery))
|
||||
{
|
||||
if (user == null)
|
||||
@@ -285,29 +247,6 @@ public sealed partial class PowerCellSystem
|
||||
|
||||
return _battery.GetMaxUses(battery.Value.AsNullable(), cost);
|
||||
}
|
||||
|
||||
// Begin DeltaV
|
||||
/// <summary>
|
||||
/// Sets whether a power cell slot is capable of drawing from a battery
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void SetSlotActive(Entity<PowerCellSlotComponent?> ent, bool active)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
ent.Comp.Active = active;
|
||||
Dirty(ent, ent.Comp);
|
||||
|
||||
if (!active)
|
||||
{
|
||||
var emptyEv = new PowerCellSlotEmptyEvent();
|
||||
RaiseLocalEvent(ent, ref emptyEv);
|
||||
}
|
||||
|
||||
_battery.RefreshChargeRate(ent.Owner);
|
||||
}
|
||||
// End DeltaV
|
||||
}
|
||||
|
||||
// Begin DeltaV - event-based search for battery
|
||||
|
||||
@@ -6,7 +6,7 @@ using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Preferences.Loadouts;
|
||||
using Content.Shared.Roles;
|
||||
//using Content.Shared.Traits; // DeltaV - Traits Rework
|
||||
using Content.Shared.Traits;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
@@ -14,21 +14,13 @@ namespace Content.Shared.Random.Helpers
|
||||
return random.Pick(prototype.Values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - Randomly selects an entry from <paramref name="prototype"/> and returns the result.
|
||||
/// </summary>
|
||||
public static string PickId(this IRobustRandom random, LocalizedDatasetPrototype prototype)
|
||||
{
|
||||
var index = random.Next(prototype.Values.Count);
|
||||
return prototype.Values[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Randomly selects an entry from <paramref name="prototype"/>, attempts to localize it, and returns the result.
|
||||
/// </summary>
|
||||
public static string Pick(this IRobustRandom random, LocalizedDatasetPrototype prototype)
|
||||
{
|
||||
return Loc.GetString(random.PickId(prototype)); // DeltaV - we need LocIds too
|
||||
var index = random.Next(prototype.Values.Count);
|
||||
return Loc.GetString(prototype.Values[index]);
|
||||
}
|
||||
|
||||
public static string Pick(this IWeightedRandomPrototype prototype, System.Random random)
|
||||
|
||||
@@ -46,48 +46,4 @@ public sealed partial class SSDIndicatorComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1);
|
||||
|
||||
// DeltaV - SSD Recency Additions START
|
||||
|
||||
/// <summary>
|
||||
/// The time at which the Entity became SSD.
|
||||
/// </summary>
|
||||
[AutoNetworkedField, AutoPausedField]
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan SsdSince = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The icon displayed next to the associated entity when it is recently SSD (stage 2).
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<SsdIconPrototype> RecentIcon = "RecentSSDIcon";
|
||||
|
||||
/// <summary>
|
||||
/// The icon displayed next to the associated entity when it is very recently SSD (stage 1).
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<SsdIconPrototype> VeryRecentIcon = "VeryRecentSSDIcon";
|
||||
|
||||
// DeltaV END
|
||||
}
|
||||
|
||||
// DeltaV - SSD Recency START
|
||||
// If you change this enum, remember to update `Resources/Locale/en-US/_DV/ssdIndicator/examine.ftl`
|
||||
public enum SsdStage : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Stage 1: SSD Indicator is red. They might just be recovering from a crash/timeout.
|
||||
/// </summary>
|
||||
VeryRecent,
|
||||
|
||||
/// <summary>
|
||||
/// Stage 2: SSD Indicator is yellow. They've been gone for a bit, but they shouldn't be moved to cryo yet.
|
||||
/// </summary>
|
||||
Recent,
|
||||
|
||||
/// <summary>
|
||||
/// Stage 3: SSD Indicator is green/default. They've been gone for a long time, they can be moved to cryo.
|
||||
/// </summary>
|
||||
Cryoable,
|
||||
}
|
||||
// DeltaV END
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Content.Shared._DV.CCVars; // DeltaV - SSD Recency
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Examine; // DeltaV - SSD Recency
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Player;
|
||||
@@ -23,9 +21,6 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
private bool _icSsdSleep;
|
||||
private float _icSsdSleepTime;
|
||||
|
||||
private TimeSpan _cryoableSsdSeconds; // DeltaV
|
||||
private TimeSpan _recentSsdSeconds; // DeltaV
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SSDIndicatorComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
@@ -34,44 +29,8 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
|
||||
_cfg.OnValueChanged(CCVars.ICSSDSleep, obj => _icSsdSleep = obj, true);
|
||||
_cfg.OnValueChanged(CCVars.ICSSDSleepTime, obj => _icSsdSleepTime = obj, true);
|
||||
_cfg.OnValueChanged(DCCVars.SsdIndicatorCryoableAfterSeconds, obj => _cryoableSsdSeconds = TimeSpan.FromSeconds(obj), true); // DeltaV - SSD Recency
|
||||
_cfg.OnValueChanged(DCCVars.SsdIndicatorRecentAfterSeconds, obj => _recentSsdSeconds = TimeSpan.FromSeconds(obj), true); // DeltaV - SSD Recency
|
||||
|
||||
SubscribeLocalEvent<SSDIndicatorComponent, ExaminedEvent>(OnExamine); // DeltaV - SSD Recency
|
||||
}
|
||||
|
||||
// DeltaV - SSD Recency START
|
||||
private void OnExamine(Entity<SSDIndicatorComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!ent.Comp.IsSSD)
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(SSDIndicatorComponent)))
|
||||
{
|
||||
var timestamp = (_timing.CurTime - ent.Comp.SsdSince).ToString("%hh':'mm':'ss");
|
||||
args.PushMarkup(Loc.GetString("ssd-examine-duration", ("time", timestamp)));
|
||||
args.PushMarkup(Loc.GetString($"ssd-examine-{GetStage(ent).ToString().ToLower()}"));
|
||||
}
|
||||
}
|
||||
|
||||
public SsdStage GetStage(Entity<SSDIndicatorComponent> ent)
|
||||
{
|
||||
var curTime = _timing.CurTime;
|
||||
|
||||
if (ent.Comp.SsdSince + _cryoableSsdSeconds < curTime)
|
||||
{
|
||||
return SsdStage.Cryoable;
|
||||
}
|
||||
|
||||
if (ent.Comp.SsdSince + _recentSsdSeconds < curTime)
|
||||
{
|
||||
return SsdStage.Recent;
|
||||
}
|
||||
|
||||
return SsdStage.VeryRecent;
|
||||
}
|
||||
// DeltaV END
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, SSDIndicatorComponent component, PlayerAttachedEvent args)
|
||||
{
|
||||
component.IsSSD = false;
|
||||
@@ -96,8 +55,6 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
component.FallAsleepTime = _timing.CurTime + TimeSpan.FromSeconds(_icSsdSleepTime);
|
||||
}
|
||||
|
||||
component.SsdSince = _timing.CurTime; // DeltaV - SSD Recency
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,4 @@ public sealed partial class BorgTransponderComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool FakeDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - whether the transponder is active
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Active = true;
|
||||
}
|
||||
|
||||
@@ -718,13 +718,8 @@ public abstract class SharedStrippableSystem : EntitySystem
|
||||
if (args.Handled || !args.Complex || args.Target == args.User)
|
||||
return;
|
||||
|
||||
// Begin Stellar Changes - don't play an interact particle for examining the strip UI
|
||||
if (TryOpenStrippingUi(args.User, (uid, component)))
|
||||
{
|
||||
args.Handled = true;
|
||||
args.InteractionParticle = false;
|
||||
}
|
||||
// End Stellar Changes - don't play an interact particle for examining the strip UI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountCodeMsg : NetMessage
|
||||
{
|
||||
public Guid Code;
|
||||
|
||||
public override MsgGroups MsgGroup => MsgGroups.Core;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
Code = buffer.ReadGuid();
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.Write(Code);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountRequestMsg : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.Core;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.IO;
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
public sealed class LinkAccountStatusMsg : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.Core;
|
||||
|
||||
public SharedPatronFull? Patron;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
var isPatron = buffer.ReadBoolean();
|
||||
if (!isPatron)
|
||||
return;
|
||||
|
||||
buffer.ReadPadBits();
|
||||
var length = buffer.ReadVariableInt32();
|
||||
using var stream = new MemoryStream(length);
|
||||
buffer.ReadAlignedMemory(stream, length);
|
||||
Patron = serializer.Deserialize<SharedPatronFull>(stream);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
if (Patron == null)
|
||||
{
|
||||
buffer.Write(false);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Write(true);
|
||||
buffer.WritePadBits();
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
serializer.Serialize(stream, Patron);
|
||||
buffer.WriteVariableInt32((int) stream.Length);
|
||||
stream.TryGetBuffer(out var segment);
|
||||
buffer.Write(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
public sealed class PatronListMsg : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.Core;
|
||||
|
||||
public List<SharedPatron> Patrons = default!;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
var count = buffer.ReadVariableInt32();
|
||||
Patrons = new List<SharedPatron>(count);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var name = buffer.ReadString();
|
||||
var tier = buffer.ReadString();
|
||||
Patrons.Add(new SharedPatron(name, tier));
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.WriteVariableInt32(Patrons.Count);
|
||||
foreach (var patron in Patrons)
|
||||
{
|
||||
buffer.Write(patron.Name);
|
||||
buffer.Write(patron.Tier);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SharedPatron(string name, string tier)
|
||||
{
|
||||
public readonly string Name = name;
|
||||
public readonly string Tier = tier;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed record SharedPatronFull(
|
||||
SharedPatronTier? Tier,
|
||||
bool Linked
|
||||
);
|
||||
@@ -1,9 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.AccountLinking;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed record SharedPatronTier(
|
||||
bool ShowOnCredits,
|
||||
string Tier
|
||||
);
|
||||
@@ -1,13 +0,0 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared._DV.CCVars;
|
||||
|
||||
public sealed partial class DCCVars
|
||||
{
|
||||
/// <summary>
|
||||
/// Redirects you to the channel in discord to link your account.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> DiscordAccountLinkingMessageLink =
|
||||
CVarDef.Create("discord.discord_account_linking_message_link", "", CVar.REPLICATED | CVar.SERVER);
|
||||
|
||||
}
|
||||
@@ -316,19 +316,4 @@ public sealed partial class DCCVars
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> EsScreenshakeDisabled =
|
||||
CVarDef.Create("deltav.es_screenshake.disabled", false, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/// <summary>
|
||||
/// The total time a player has to be SSD to be considered cryoable (stage 3).
|
||||
/// Default is 20 minutes. Value should be bigger than <see cref="SsdIndicatorRecentAfterSeconds"/>.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SsdIndicatorCryoableAfterSeconds =
|
||||
CVarDef.Create("deltav.ssd.cryoable_after_seconds", 1200f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// The total time a player has to be SSD to be considered recently SSD (stage 2).
|
||||
/// If the player has been SSD for less than this time, they are considered "very recently" SSD (stage 1).
|
||||
/// Default is 5 minutes. Value should be smaller than <see cref="SsdIndicatorCryoableAfterSeconds"/>.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> SsdIndicatorRecentAfterSeconds =
|
||||
CVarDef.Create("deltav.ssd.recent_after_seconds", 300f, CVar.SERVER | CVar.REPLICATED);
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
using Content.Shared.Radio;
|
||||
|
||||
namespace Content.Shared._DV.Chat;
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct EntityAudiblyEmotedEvent(EntityUid Source, string Message, RadioChannelPrototype? Channel, EmoteType? Type);
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Content.Shared._DV.Chat;
|
||||
|
||||
|
||||
// Note for future: If you want to make this more robust to handle more types of emotes while still being able to check off audible as an option for it then it would
|
||||
// probably be better to make it a struct and have audible be a flag for it and then the type of emote. This would avoid having to make two different types for audible and visual.
|
||||
/// <summary>
|
||||
/// Different ways of emoting. For that little extra in RP!
|
||||
/// </summary>
|
||||
public enum EmoteType : byte
|
||||
{
|
||||
Normal, // Character emotes
|
||||
Audible, // Character screams
|
||||
Possessive, // Character's emote
|
||||
AudiblePossessive // Character's scream
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.Silicons;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BorgWireActionKey : byte
|
||||
{
|
||||
SlavedKey,
|
||||
TransponderKey,
|
||||
ChipKey,
|
||||
CellKey,
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Content.Shared._DV.Silicons.Borgs;
|
||||
/// Adds an id chip slot for a borg which will control its access.
|
||||
/// Enables an id chip's access when inserted to an id chip slot.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(IdChipSlotSystem)), AutoGenerateComponentState]
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(IdChipSlotSystem))]
|
||||
public sealed partial class IdChipSlotComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
@@ -35,12 +35,6 @@ public sealed partial class IdChipSlotComponent : Component
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public EntityWhitelist Whitelist = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether the ID chip slot is active
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Active = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -73,7 +73,7 @@ public sealed class IdChipSlotSystem : EntitySystem
|
||||
|
||||
private void OnGetAdditionalAccess(Entity<IdChipSlotComponent> ent, ref GetAdditionalAccessEvent args)
|
||||
{
|
||||
if (ent.Comp is { Active: true, Chip: {} chip })
|
||||
if (ent.Comp.Chip is {} chip)
|
||||
args.Entities.Add(chip);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public sealed class IdChipSlotSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// enable its access so the borg can use it
|
||||
_access.SetAccessEnabled(args.Entity, ent.Comp.Active);
|
||||
_access.SetAccessEnabled(args.Entity, true);
|
||||
}
|
||||
|
||||
private void OnChipRemoved(Entity<IdChipSlotComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
@@ -105,14 +105,4 @@ public sealed class IdChipSlotSystem : EntitySystem
|
||||
_container.Remove(chip, ent.Comp.Container);
|
||||
_hands.TryPickupAnyHand(args.Actor, chip);
|
||||
}
|
||||
|
||||
public void SetActive(Entity<IdChipSlotComponent?> ent, bool active)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
ent.Comp.Active = active;
|
||||
_access.SetAccessEnabled(ent.Owner, active && ent.Comp.Chip is not null);
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,8 @@ public sealed partial class SlavedBorgComponent : Component
|
||||
public ProtoId<SiliconLawPrototype> Law;
|
||||
|
||||
/// <summary>
|
||||
/// Prevents adding the same law 0 mutliple times during law updates.
|
||||
/// Prevents adding the same law twice.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool HasBeenAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the law 0 should be added to the lawset.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ShouldBeAdded = true;
|
||||
public bool Added;
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Traits.Assorted;
|
||||
|
||||
/// <summary>
|
||||
/// This entity will not be candidate for a paradox clone.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class NoParadoxCloneComponent : Component;
|
||||
@@ -1,9 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Whitelist.Holoprojectors;
|
||||
|
||||
/// <summary>
|
||||
/// Marker component for holoradiationblockers, used for reclaiming charges of the projector.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class HoloRadiationblockerComponent : Component;
|
||||
@@ -126,10 +126,7 @@ public sealed class AutomationSystem : EntitySystem
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsAutomated(EntityUid uid)
|
||||
{
|
||||
return _automatedQuery.HasComp(uid);
|
||||
}
|
||||
public bool IsAutomated(EntityUid uid) => _automatedQuery.HasComp(uid);
|
||||
|
||||
public bool HasSlot(Entity<AutomationSlotsComponent?> ent, string port, bool input)
|
||||
{
|
||||
|
||||
@@ -95,8 +95,3 @@
|
||||
license: "CC-BY-NC-3.0"
|
||||
copyright: "Superposition by Amie Waters, converted to mono"
|
||||
source: "https://amiewaters.bandcamp.com/track/superposition-2"
|
||||
|
||||
- files: ["waitingroomabovethestars.ogg", "waitingroomabovethestars_mono.ogg"]
|
||||
license: "CC-BY-SA-4.0"
|
||||
copyright: "by This_Is_Gray for DeltaV, converted to mono"
|
||||
source: "https://github.com/DeltaV-Station/Delta-v.git"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -13,8 +13,3 @@
|
||||
license: "CC-BY-NC-SA-4.0"
|
||||
copyright: "flying off the album TWENTY by Oliver Buckland."
|
||||
source: "https://oliver-buckland.bandcamp.com/album/twenty"
|
||||
|
||||
- files: ["waitingroomabovethestars.ogg"]
|
||||
license: "CC-BY-SA-4.0"
|
||||
copyright: "by This_Is_Gray for DeltaV"
|
||||
source: "https://github.com/DeltaV-Station/Delta-v.git"
|
||||
|
||||
Binary file not shown.
@@ -307,12 +307,5 @@ Entries:
|
||||
id: 33
|
||||
time: '2026-05-28T16:56:20.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5858
|
||||
- author: DisposableCrewmember42
|
||||
changes:
|
||||
- message: The admin overlay now shows how long people have been SSD
|
||||
type: Add
|
||||
id: 34
|
||||
time: '2026-06-06T19:14:04.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5699
|
||||
Name: DeltaVAdmin
|
||||
Order: 5
|
||||
|
||||
@@ -1,4 +1,120 @@
|
||||
Entries:
|
||||
- author: Colin-Tel, BigMaxPorter
|
||||
changes:
|
||||
- message: The laser carbine now does the intended 20 heat damage.
|
||||
type: Fix
|
||||
id: 1871
|
||||
time: '2025-11-28T08:24:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4790
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Cardboard boxes are now affected by gravity
|
||||
type: Fix
|
||||
id: 1872
|
||||
time: '2025-11-28T08:47:19.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4794
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Skimmer now does its one and only job again, lazy bugger
|
||||
type: Fix
|
||||
id: 1873
|
||||
time: '2025-11-28T09:36:55.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4795
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Flintlock is now craftable as intended
|
||||
type: Fix
|
||||
id: 1874
|
||||
time: '2025-11-28T09:41:03.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4796
|
||||
- author: Toby222
|
||||
changes:
|
||||
- message: Removed the invisible, intangible bear inside all fishing crates that
|
||||
was trying to steal your fish
|
||||
type: Fix
|
||||
id: 1875
|
||||
time: '2025-11-28T09:49:21.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4797
|
||||
- author: SirWarock
|
||||
changes:
|
||||
- message: The faithful rejoice! Your deity has chosen to to protect you as long
|
||||
as you hold your religious tome!
|
||||
type: Tweak
|
||||
id: 1876
|
||||
time: '2025-11-28T19:03:43.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4726
|
||||
- author: Vapetastic-Gaming
|
||||
changes:
|
||||
- message: Submarine Playtest Fixes and Tweaks, it is now in current rotation, with
|
||||
a minimum 80 population !!
|
||||
type: Tweak
|
||||
id: 1877
|
||||
time: '2025-11-29T03:30:17.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4554
|
||||
- author: snowywinters
|
||||
changes:
|
||||
- message: Now normal command turrets alert the AI to an intruder
|
||||
type: Fix
|
||||
id: 1878
|
||||
time: '2025-11-29T19:57:59.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4803
|
||||
- author: kotobdev
|
||||
changes:
|
||||
- message: The FG13 Xiuhcoatl is now substantially more deadly. It also costs less!
|
||||
type: Tweak
|
||||
id: 1879
|
||||
time: '2025-11-29T22:27:08.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4749
|
||||
- author: ShepardToTheStars
|
||||
changes:
|
||||
- message: While trying to stand-up, you can now press your Toggle Crawling keybind
|
||||
to get up faster at the cost of stamina. Of course, you still still need a free
|
||||
hand to do this.
|
||||
type: Tweak
|
||||
id: 1880
|
||||
time: '2025-11-30T16:24:25.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4802
|
||||
- author: TheGrimbeeper
|
||||
changes:
|
||||
- message: Artifacts can now be triggered by ambient radiation, not just uranium
|
||||
spears
|
||||
type: Fix
|
||||
id: 1881
|
||||
time: '2025-11-30T16:30:34.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4817
|
||||
- author: pootslap
|
||||
changes:
|
||||
- message: Characters must now be 40 to be considered middle-aged and 70 to be considered
|
||||
old.
|
||||
type: Tweak
|
||||
id: 1882
|
||||
time: '2025-11-30T16:31:43.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4783
|
||||
- author: Proxysseia
|
||||
changes:
|
||||
- message: Crew of legally docked foreign vessels now has rights
|
||||
type: Add
|
||||
id: 1883
|
||||
time: '2025-11-30T16:37:35.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4763
|
||||
- author: verybigman311
|
||||
changes:
|
||||
- message: Rejoice! Four new cocktails utilizing the long-neglected Angobitters
|
||||
are now available.
|
||||
type: Add
|
||||
- message: You can now ask for Mliko (glorified beer foam) at your local bar.
|
||||
type: Add
|
||||
- message: Famous drinks such as Pilk, Moonshine, and Hooch have been given new
|
||||
sprites.
|
||||
type: Add
|
||||
- message: Alterations have been made to the Grog, Posca, and Gin Fizz recipes.
|
||||
type: Tweak
|
||||
- message: Numerous beverages will now form puddles of the correct color when thrown
|
||||
violently against the ground.
|
||||
type: Fix
|
||||
id: 1884
|
||||
time: '2025-11-30T16:41:31.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/4780
|
||||
- author: verybigman311
|
||||
changes:
|
||||
- message: Lava Fountains are now an available decoration.
|
||||
@@ -4284,115 +4400,4 @@
|
||||
id: 2371
|
||||
time: '2026-06-02T15:16:39.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5944
|
||||
- author: turtlemutt
|
||||
changes:
|
||||
- message: Swapped out Lighthouse security's red with the new blue.
|
||||
type: Tweak
|
||||
id: 2372
|
||||
time: '2026-06-03T18:43:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5898
|
||||
- author: AeraAuling
|
||||
changes:
|
||||
- message: Holy and Shadow have been renamed to be a bit less good and evil
|
||||
type: Tweak
|
||||
id: 2373
|
||||
time: '2026-06-04T10:58:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5952
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: Interaction particles are now less energetic.
|
||||
type: Tweak
|
||||
- message: Interaction particles no longer spawn when opening the strip menu.
|
||||
type: Fix
|
||||
id: 2374
|
||||
time: '2026-06-05T12:46:01.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5933
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: Dionaea now have a new name generation algorithim.
|
||||
type: Tweak
|
||||
id: 2375
|
||||
time: '2026-06-05T13:33:57.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5836
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: 'Reverted and Rework Upstream Medical Borg Changes. Media provided in
|
||||
PR:'
|
||||
type: Tweak
|
||||
- message: Medical Borg can now see Triage Icons.
|
||||
type: Fix
|
||||
id: 2376
|
||||
time: '2026-06-05T15:05:53.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5656
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Added the No Paradox Clone Trait!
|
||||
type: Add
|
||||
id: 2377
|
||||
time: '2026-06-05T15:17:50.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5937
|
||||
- author: rebe83
|
||||
changes:
|
||||
- message: Nuclear operatives, listening post operators, and ninjas now have randomized
|
||||
appearances.
|
||||
type: Tweak
|
||||
id: 2378
|
||||
time: '2026-06-05T15:26:25.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5922
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Added RGB plushies, gay wackpack, LGBT handheld flags, and more pride
|
||||
theme items to the Pride-o-Mat!
|
||||
type: Tweak
|
||||
id: 2379
|
||||
time: '2026-06-05T15:28:44.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5946
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Added Small Nuclear Reactor (7,500) and Small Gas Turbine (5,000) Flatpacks
|
||||
for Purchase!
|
||||
type: Add
|
||||
id: 2380
|
||||
time: '2026-06-05T15:32:57.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5945
|
||||
- author: einknusprigestoast
|
||||
changes:
|
||||
- message: Added a Chameleon armored Vest for Syndicate Agents
|
||||
type: Add
|
||||
id: 2381
|
||||
time: '2026-06-05T17:34:10.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5921
|
||||
- author: sowelipililimute
|
||||
changes:
|
||||
- message: NT Cyborgs now have a wire panel that allow enabling/disabling the transponder,
|
||||
law 0, and AI PDA access.
|
||||
type: Add
|
||||
id: 2382
|
||||
time: '2026-06-05T21:13:49.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5948
|
||||
- author: Stxcking
|
||||
changes:
|
||||
- message: Radiation Barrier Projectors Actually Creates Holo Radiation Barriers
|
||||
Instead of Holo Wet Floor Signs !
|
||||
type: Fix
|
||||
id: 2383
|
||||
time: '2026-06-06T09:53:19.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5787
|
||||
- author: IAmNotGray
|
||||
changes:
|
||||
- message: Added a new jukebox song called "Waiting Room Above The Stars."
|
||||
type: Add
|
||||
id: 2384
|
||||
time: '2026-06-06T12:07:56.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5620
|
||||
- author: DisposableCrewmember42
|
||||
changes:
|
||||
- message: The SSD indicator now changes color depending on duration.
|
||||
type: Add
|
||||
- message: The examine text of SSD players now includes the SSD duration and information
|
||||
on what (not) to do with them.
|
||||
type: Add
|
||||
id: 2385
|
||||
time: '2026-06-06T19:14:04.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5699
|
||||
Order: 1
|
||||
|
||||
@@ -1036,13 +1036,4 @@
|
||||
id: 120
|
||||
time: '2026-05-31T19:28:53.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5847
|
||||
- author: biddygelson
|
||||
changes:
|
||||
- message: 'Academy: added secure windoors to security disposal chutes.'
|
||||
type: Add
|
||||
- message: 'Academy: Escape pods are now the 5x7 DV variant'
|
||||
type: Tweak
|
||||
id: 121
|
||||
time: '2026-06-05T15:07:41.0000000+00:00'
|
||||
url: https://github.com/DeltaV-Station/Delta-v/pull/5880
|
||||
Order: 3
|
||||
|
||||
@@ -59,7 +59,4 @@ storage_limit = 3
|
||||
|
||||
[audio] # DeltaV
|
||||
attenuation = 4 # inversedistanceclamped 1 << 2, see audioparams.cs
|
||||
z_offset = -2
|
||||
|
||||
[discord]
|
||||
discord_account_linking_message_link = "https://discord.com/channels/968983104247185448/1513638637018021978"
|
||||
z_offset = -2
|
||||
@@ -112,6 +112,3 @@ max_announcement_length = 512
|
||||
[audio]
|
||||
attenuation = 4 # inversedistanceclamped 1 << 2, see audioparams.cs
|
||||
z_offset = -2
|
||||
|
||||
[discord]
|
||||
discord_account_linking_message_link = "https://discord.com/channels/968983104247185448/1513638637018021978"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user