mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-15 04:30:57 +01:00
Merge branch 'master' into icarus
This commit is contained in:
5
.github/workflows/build-test-debug.yml
vendored
5
.github/workflows/build-test-debug.yml
vendored
@@ -62,3 +62,8 @@ jobs:
|
||||
- name: Run Content.Tests
|
||||
run: dotnet test --no-build Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0
|
||||
|
||||
- name: Run Content.IntegrationTests
|
||||
shell: pwsh
|
||||
run: |
|
||||
$env:DOTNET_gcServer=1
|
||||
dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -- NUnit.ConsoleOut=0
|
||||
|
||||
3
.github/workflows/conflict-labeler.yml
vendored
3
.github/workflows/conflict-labeler.yml
vendored
@@ -9,10 +9,9 @@ on:
|
||||
jobs:
|
||||
Label:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- name: Check for Merge Conflicts
|
||||
uses: eps1lon/actions-label-merge-conflict@513a24fc7dca40990863be2935e059e650728400
|
||||
uses: ike709/actions-label-merge-conflict@9eefdd17e10566023c46d2dc6dc04fcb8ec76142
|
||||
with:
|
||||
dirtyLabel: "Merge Conflict"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace Content.Client.AI
|
||||
private void DrawCachedRegions(DrawingHandleScreen screenHandle, Box2 viewport)
|
||||
{
|
||||
var transform = _entities.GetComponentOrNull<TransformComponent>(_playerManager.LocalPlayer?.ControlledEntity);
|
||||
if (transform == null || !CachedRegions.TryGetValue(transform.GridEntityId, out var entityRegions))
|
||||
if (transform == null || transform.GridUid == null || !CachedRegions.TryGetValue(transform.GridUid.Value, out var entityRegions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -312,7 +312,7 @@ namespace Content.Client.AI
|
||||
screenTile.X + 15.0f,
|
||||
screenTile.Y + 15.0f);
|
||||
|
||||
screenHandle.DrawRect(box, _cachedRegionColors[transform.GridEntityId][region]);
|
||||
screenHandle.DrawRect(box, _cachedRegionColors[transform.GridUid.Value][region]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,8 @@ namespace Content.Client.AI
|
||||
{
|
||||
var attachedEntity = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
if (!_entities.TryGetComponent(attachedEntity, out TransformComponent? transform) ||
|
||||
!Regions.TryGetValue(transform.GridEntityId, out var entityRegions))
|
||||
transform.GridUid == null ||
|
||||
!Regions.TryGetValue(transform.GridUid.Value, out var entityRegions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -364,7 +365,7 @@ namespace Content.Client.AI
|
||||
screenTile.X + 15.0f,
|
||||
screenTile.Y + 15.0f);
|
||||
|
||||
screenHandle.DrawRect(box, _regionColors[_entities.GetComponent<TransformComponent>(attachedEntity.Value).GridEntityId][chunk][region]);
|
||||
screenHandle.DrawRect(box, _regionColors[transform.GridUid.Value][chunk][region]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
Content.Client/AME/AMEControllerVisualizerSystem.cs
Normal file
61
Content.Client/AME/AMEControllerVisualizerSystem.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Content.Client.AME.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using static Content.Shared.AME.SharedAMEControllerComponent;
|
||||
|
||||
namespace Content.Client.AME;
|
||||
|
||||
public sealed class AMEControllerVisualizerSystem : VisualizerSystem<AMEControllerVisualsComponent>
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AMEControllerVisualsComponent, ComponentInit>(OnComponentInit);
|
||||
}
|
||||
|
||||
private void OnComponentInit(EntityUid uid, AMEControllerVisualsComponent component, ComponentInit args)
|
||||
{
|
||||
if(TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
sprite.LayerMapSet(AMEControllerVisualLayers.Display, sprite.AddLayerState("control_on"));
|
||||
sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAppearanceChange(EntityUid uid, AMEControllerVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
base.OnAppearanceChange(uid, component, ref args);
|
||||
|
||||
if(args.Sprite != null
|
||||
&& args.Component.TryGetData<string>(AMEControllerVisuals.DisplayState, out var state))
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case "on":
|
||||
args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_on");
|
||||
args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true);
|
||||
break;
|
||||
case "critical":
|
||||
args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_critical");
|
||||
args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true);
|
||||
break;
|
||||
case "fuck":
|
||||
args.Sprite.LayerSetState(AMEControllerVisualLayers.Display, "control_fuck");
|
||||
args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, true);
|
||||
break;
|
||||
case "off":
|
||||
args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false);
|
||||
break;
|
||||
default:
|
||||
args.Sprite.LayerSetVisible(AMEControllerVisualLayers.Display, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AMEControllerVisualLayers : byte
|
||||
{
|
||||
Display
|
||||
}
|
||||
|
||||
70
Content.Client/AME/AMEShieldingVisualizerSystem.cs
Normal file
70
Content.Client/AME/AMEShieldingVisualizerSystem.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Content.Client.AME.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using static Content.Shared.AME.SharedAMEShieldComponent;
|
||||
|
||||
namespace Content.Client.AME;
|
||||
|
||||
public sealed class AMEShieldingVisualizerSystem : VisualizerSystem<AMEShieldingVisualsComponent>
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AMEShieldingVisualsComponent, ComponentInit>(OnComponentInit);
|
||||
}
|
||||
|
||||
private void OnComponentInit(EntityUid uid, AMEShieldingVisualsComponent component, ComponentInit args)
|
||||
{
|
||||
if(TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
sprite.LayerMapSet(AMEShieldingVisualsLayer.Core, sprite.AddLayerState("core"));
|
||||
sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, false);
|
||||
sprite.LayerMapSet(AMEShieldingVisualsLayer.CoreState, sprite.AddLayerState("core_weak"));
|
||||
sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAppearanceChange(EntityUid uid, AMEShieldingVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if(args.Sprite == null)
|
||||
return;
|
||||
|
||||
if(args.Component.TryGetData<string>(AMEShieldVisuals.Core, out var core))
|
||||
{
|
||||
if (core == "isCore")
|
||||
{
|
||||
args.Sprite.LayerSetState(AMEShieldingVisualsLayer.Core, "core");
|
||||
args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, true);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.Core, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(args.Component.TryGetData<string>(AMEShieldVisuals.CoreState, out var coreState))
|
||||
{
|
||||
switch(coreState)
|
||||
{
|
||||
case "weak":
|
||||
args.Sprite.LayerSetState(AMEShieldingVisualsLayer.CoreState, "core_weak");
|
||||
args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, true);
|
||||
break;
|
||||
case "strong":
|
||||
args.Sprite.LayerSetState(AMEShieldingVisualsLayer.CoreState, "core_strong");
|
||||
args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, true);
|
||||
break;
|
||||
case "off":
|
||||
args.Sprite.LayerSetVisible(AMEShieldingVisualsLayer.CoreState, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AMEShieldingVisualsLayer : byte
|
||||
{
|
||||
Core,
|
||||
CoreState,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.AME.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class AMEControllerVisualsComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.AME.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class AMEShieldingVisualsComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using static Content.Shared.AME.SharedAMEControllerComponent;
|
||||
|
||||
namespace Content.Client.AME.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class AMEControllerVisualizer : AppearanceVisualizer
|
||||
{
|
||||
public override void InitializeEntity(EntityUid entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<ISpriteComponent>(entity);
|
||||
|
||||
sprite.LayerMapSet(Layers.Display, sprite.AddLayerState("control_on"));
|
||||
sprite.LayerSetVisible(Layers.Display, false);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<ISpriteComponent>(component.Owner);
|
||||
if (component.TryGetData<string>(AMEControllerVisuals.DisplayState, out var state))
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case "on":
|
||||
sprite.LayerSetState(Layers.Display, "control_on");
|
||||
sprite.LayerSetVisible(Layers.Display, true);
|
||||
break;
|
||||
case "critical":
|
||||
sprite.LayerSetState(Layers.Display, "control_critical");
|
||||
sprite.LayerSetVisible(Layers.Display, true);
|
||||
break;
|
||||
case "fuck":
|
||||
sprite.LayerSetState(Layers.Display, "control_fuck");
|
||||
sprite.LayerSetVisible(Layers.Display, true);
|
||||
break;
|
||||
case "off":
|
||||
sprite.LayerSetVisible(Layers.Display, false);
|
||||
break;
|
||||
default:
|
||||
sprite.LayerSetVisible(Layers.Display, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Layers : byte
|
||||
{
|
||||
Display,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using static Content.Shared.AME.SharedAMEShieldComponent;
|
||||
|
||||
namespace Content.Client.AME.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class AMEVisualizer : AppearanceVisualizer
|
||||
{
|
||||
public override void InitializeEntity(EntityUid entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<ISpriteComponent>(entity);
|
||||
sprite.LayerMapSet(Layers.Core, sprite.AddLayerState("core"));
|
||||
sprite.LayerSetVisible(Layers.Core, false);
|
||||
sprite.LayerMapSet(Layers.CoreState, sprite.AddLayerState("core_weak"));
|
||||
sprite.LayerSetVisible(Layers.CoreState, false);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<ISpriteComponent>(component.Owner);
|
||||
if (component.TryGetData<string>(AMEShieldVisuals.Core, out var core))
|
||||
{
|
||||
if (core == "isCore")
|
||||
{
|
||||
sprite.LayerSetState(Layers.Core, "core");
|
||||
sprite.LayerSetVisible(Layers.Core, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetVisible(Layers.Core, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (component.TryGetData<string>(AMEShieldVisuals.CoreState, out var coreState))
|
||||
switch (coreState)
|
||||
{
|
||||
case "weak":
|
||||
sprite.LayerSetState(Layers.CoreState, "core_weak");
|
||||
sprite.LayerSetVisible(Layers.CoreState, true);
|
||||
break;
|
||||
case "strong":
|
||||
sprite.LayerSetState(Layers.CoreState, "core_strong");
|
||||
sprite.LayerSetVisible(Layers.CoreState, true);
|
||||
break;
|
||||
case "off":
|
||||
sprite.LayerSetVisible(Layers.CoreState, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Layers : byte
|
||||
{
|
||||
Core,
|
||||
CoreState,
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
foreach (var grid in _data)
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridEntityId;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.GridEntityId} {(playerGrid == grid.GridEntityId ? " (Current)" : "")}");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
foreach (var grid in _gridData)
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridEntityId;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.GridEntityId} {(playerGrid == grid.GridEntityId ? " (Current)" : "")}");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
foreach (var grid in _gridData)
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridEntityId;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.GridEntityId} {(playerGrid == grid.GridEntityId ? " (Current)" : "")}");
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
foreach (var grid in _data)
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridEntityId;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.GridEntityId} {(playerGrid == grid.GridEntityId ? " (Current)" : "")}");
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace Content.Client.Atmos.UI
|
||||
PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#525252ff") }
|
||||
});
|
||||
CloseButton.OnPressed += _ => Close();
|
||||
SetSize = (300, 200);
|
||||
SetSize = (300, 420);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Content.Client.Audio
|
||||
{
|
||||
if(_playMan.LocalPlayer is null || _playMan.LocalPlayer.ControlledEntity != message.Entity) return;
|
||||
if (!TryComp<TransformComponent>(message.Entity, out var xform) ||
|
||||
!_mapManager.TryGetGrid(xform.GridEntityId, out var grid)) return;
|
||||
!_mapManager.TryGetGrid(xform.GridUid, out var grid)) return;
|
||||
|
||||
var tileDef = (ContentTileDefinition) _tileDefMan[grid.GetTileRef(xform.Coordinates).Tile.TypeId];
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Content.Client.Buckle
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_entMan.TryGetComponent(Owner, out RiderComponent? rider))
|
||||
if (LastEntityBuckledTo != null && _entMan.HasComponent<VehicleComponent>(LastEntityBuckledTo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,46 @@
|
||||
using Content.Client.Cargo.Components;
|
||||
using Content.Client.Cargo.UI;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.BUI;
|
||||
using Content.Shared.Cargo.Components;
|
||||
using Content.Shared.Cargo.Events;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.Cargo.Components.SharedCargoConsoleComponent;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
namespace Content.Client.Cargo
|
||||
namespace Content.Client.Cargo.BUI
|
||||
{
|
||||
public sealed class CargoConsoleBoundUserInterface : BoundUserInterface
|
||||
public sealed class CargoOrderConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private CargoConsoleMenu? _menu;
|
||||
|
||||
/// <summary>
|
||||
/// This is the separate popup window for individual orders.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private CargoConsoleOrderMenu? _orderMenu;
|
||||
|
||||
[ViewVariables]
|
||||
public CargoOrderDatabaseComponent? Orders { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public bool RequestOnly { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int BankId { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public string? BankName { get; private set; }
|
||||
public string? AccountName { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int BankBalance { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public (int CurrentCapacity, int MaxCapacity) ShuttleCapacity { get; private set; }
|
||||
public int OrderCapacity { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int OrderCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected product
|
||||
/// </summary>
|
||||
private CargoProductPrototype? _product;
|
||||
|
||||
public CargoConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
public CargoOrderConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -47,30 +48,29 @@ namespace Content.Client.Cargo
|
||||
{
|
||||
base.Open();
|
||||
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
if (!entMan.TryGetComponent(Owner.Owner, out CargoOrderDatabaseComponent? orders)) return;
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var sysManager = entityManager.EntitySysManager;
|
||||
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
||||
_menu = new CargoConsoleMenu(IoCManager.Resolve<IPrototypeManager>(), spriteSystem);
|
||||
var localPlayer = IoCManager.Resolve<IPlayerManager>()?.LocalPlayer?.ControlledEntity;
|
||||
|
||||
Orders = orders;
|
||||
string orderRequester;
|
||||
|
||||
if (entityManager.TryGetComponent<MetaDataComponent>(localPlayer, out var metadata))
|
||||
orderRequester = metadata.EntityName;
|
||||
else
|
||||
orderRequester = string.Empty;
|
||||
|
||||
_menu = new CargoConsoleMenu(this);
|
||||
_orderMenu = new CargoConsoleOrderMenu();
|
||||
|
||||
_menu.OnClose += Close;
|
||||
|
||||
_menu.Populate();
|
||||
|
||||
Orders.OnDatabaseUpdated += _menu.PopulateOrders;
|
||||
|
||||
_menu.CallShuttleButton.OnPressed += (_) =>
|
||||
{
|
||||
SendMessage(new CargoConsoleShuttleMessage());
|
||||
};
|
||||
_menu.OnItemSelected += (args) =>
|
||||
{
|
||||
if (args.Button.Parent is not CargoProductRow row)
|
||||
return;
|
||||
_product = row.Product;
|
||||
_orderMenu.Requester.Text = "";
|
||||
_orderMenu.Requester.Text = orderRequester;
|
||||
_orderMenu.Reason.Text = "";
|
||||
_orderMenu.Amount.Value = 1;
|
||||
_orderMenu.OpenCentered();
|
||||
@@ -86,7 +86,15 @@ namespace Content.Client.Cargo
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
private void Populate(List<CargoOrderData> orders)
|
||||
{
|
||||
if (_menu == null) return;
|
||||
|
||||
_menu.PopulateProducts();
|
||||
_menu.PopulateCategories();
|
||||
_menu.PopulateOrders(orders);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
@@ -95,17 +103,16 @@ namespace Content.Client.Cargo
|
||||
|
||||
if (state is not CargoConsoleInterfaceState cState)
|
||||
return;
|
||||
if (RequestOnly != cState.RequestOnly)
|
||||
{
|
||||
RequestOnly = cState.RequestOnly;
|
||||
_menu?.UpdateRequestOnly();
|
||||
}
|
||||
BankId = cState.BankId;
|
||||
BankName = cState.BankName;
|
||||
BankBalance = cState.BankBalance;
|
||||
ShuttleCapacity = cState.ShuttleCapacity;
|
||||
_menu?.UpdateCargoCapacity();
|
||||
_menu?.UpdateBankData();
|
||||
|
||||
OrderCapacity = cState.Capacity;
|
||||
OrderCount = cState.Count;
|
||||
BankBalance = cState.Balance;
|
||||
|
||||
AccountName = cState.Name;
|
||||
|
||||
Populate(cState.Orders);
|
||||
_menu?.UpdateCargoCapacity(OrderCount, OrderCapacity);
|
||||
_menu?.UpdateBankData(AccountName, BankBalance);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -114,11 +121,6 @@ namespace Content.Client.Cargo
|
||||
|
||||
if (!disposing) return;
|
||||
|
||||
if (Orders != null && _menu != null)
|
||||
{
|
||||
Orders.OnDatabaseUpdated -= _menu.PopulateOrders;
|
||||
}
|
||||
|
||||
_menu?.Dispose();
|
||||
_orderMenu?.Dispose();
|
||||
}
|
||||
@@ -126,7 +128,7 @@ namespace Content.Client.Cargo
|
||||
private bool AddOrder()
|
||||
{
|
||||
int orderAmt = _orderMenu?.Amount.Value ?? 0;
|
||||
if (orderAmt < 1 || orderAmt > ShuttleCapacity.MaxCapacity)
|
||||
if (orderAmt < 1 || orderAmt > OrderCapacity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -153,11 +155,12 @@ namespace Content.Client.Cargo
|
||||
if (args.Button.Parent?.Parent is not CargoOrderRow row || row.Order == null)
|
||||
return;
|
||||
|
||||
if (ShuttleCapacity.CurrentCapacity == ShuttleCapacity.MaxCapacity)
|
||||
if (OrderCount >= OrderCapacity)
|
||||
return;
|
||||
|
||||
SendMessage(new CargoConsoleApproveOrderMessage(row.Order.OrderNumber));
|
||||
_menu?.UpdateCargoCapacity();
|
||||
// Most of the UI isn't predicted anyway so.
|
||||
// _menu?.UpdateCargoCapacity(OrderCount + row.Order.Amount, OrderCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Content.Client.Cargo.UI;
|
||||
using Content.Shared.Cargo.BUI;
|
||||
using Content.Shared.Cargo.Events;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Cargo.BUI;
|
||||
|
||||
public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private CargoShuttleMenu? _menu;
|
||||
|
||||
public CargoShuttleConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) {}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_menu = new CargoShuttleMenu(IoCManager.Resolve<IGameTiming>(), IoCManager.Resolve<IPrototypeManager>(), EntitySystem.Get<SpriteSystem>());
|
||||
|
||||
_menu.ShuttleCallRequested += OnShuttleCall;
|
||||
_menu.ShuttleRecallRequested += OnShuttleRecall;
|
||||
_menu.OnClose += Close;
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
_menu?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShuttleRecall()
|
||||
{
|
||||
SendMessage(new CargoRecallShuttleMessage());
|
||||
}
|
||||
|
||||
private void OnShuttleCall()
|
||||
{
|
||||
SendMessage(new CargoCallShuttleMessage());
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return;
|
||||
_menu?.SetAccountName(cargoState.AccountName);
|
||||
_menu?.SetShuttleName(cargoState.ShuttleName);
|
||||
_menu?.SetShuttleETA(cargoState.ShuttleETA);
|
||||
_menu?.SetOrders(cargoState.Orders);
|
||||
_menu?.SetCanRecall(cargoState.CanRecall);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.Cargo.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class CargoOrderDatabaseComponent : SharedCargoOrderDatabaseComponent
|
||||
{
|
||||
private readonly List<CargoOrderData> _orders = new();
|
||||
|
||||
public IReadOnlyList<CargoOrderData> Orders => _orders;
|
||||
/// <summary>
|
||||
/// Event called when the database is updated.
|
||||
/// </summary>
|
||||
public event Action? OnDatabaseUpdated;
|
||||
|
||||
// TODO add account selector menu
|
||||
|
||||
/// <summary>
|
||||
/// Removes all orders from the database.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_orders.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an order to the database.
|
||||
/// </summary>
|
||||
/// <param name="order">The order to be added.</param>
|
||||
public void AddOrder(CargoOrderData order)
|
||||
{
|
||||
if (!_orders.Contains(order))
|
||||
_orders.Add(order);
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (curState is not CargoOrderDatabaseState state)
|
||||
return;
|
||||
Clear();
|
||||
if (state.Orders == null)
|
||||
return;
|
||||
foreach (var order in state.Orders)
|
||||
{
|
||||
AddOrder(order);
|
||||
}
|
||||
|
||||
OnDatabaseUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
namespace Content.Client.Cargo;
|
||||
namespace Content.Client.Cargo.Systems;
|
||||
|
||||
public sealed partial class CargoSystem
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Cargo;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Cargo;
|
||||
namespace Content.Client.Cargo.Systems;
|
||||
|
||||
public sealed partial class CargoSystem : SharedCargoSystem
|
||||
{
|
||||
@@ -1,7 +1,8 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
SetSize="400 600"
|
||||
MinSize="400 600">
|
||||
<userInterface:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:userInterface="clr-namespace:Content.Client.UserInterface"
|
||||
SetSize="600 600"
|
||||
MinSize="600 600">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-account-name-label'}"
|
||||
@@ -15,28 +16,12 @@
|
||||
<Label Name="PointsLabel"
|
||||
Text="0" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-shuttle-status-label'}"
|
||||
StyleClasses="LabelKeyText" />
|
||||
<Label Name="ShuttleStatusLabel"
|
||||
Text="{Loc 'cargo-console-menu-shuttle-status-away-text'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-order-capacity-label'}"
|
||||
StyleClasses="LabelKeyText" />
|
||||
<Label Name="ShuttleCapacityLabel"
|
||||
Text="0/20" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="CallShuttleButton"
|
||||
Access="Public"
|
||||
Text="{Loc 'cargo-console-menu-call-shuttle-button'}"
|
||||
TextAlign="Center"
|
||||
HorizontalExpand="True"/>
|
||||
<Button Name="PermissionsButton"
|
||||
Text="{Loc 'cargo-console-menu-permissions-button'}"
|
||||
TextAlign="Center" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<OptionButton Name="Categories"
|
||||
Prefix="{Loc 'cargo-console-menu-categories-label'}"
|
||||
@@ -80,4 +65,4 @@
|
||||
</PanelContainer>
|
||||
<TextureButton VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
</userInterface:FancyWindow>
|
||||
|
||||
@@ -1,31 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Stylesheets;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Content.Client.Cargo.UI
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CargoConsoleMenu : DefaultWindow
|
||||
public sealed partial class CargoConsoleMenu : FancyWindow
|
||||
{
|
||||
[Dependency]
|
||||
private IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public CargoConsoleBoundUserInterface Owner { get; private set; }
|
||||
private IPrototypeManager _protoManager;
|
||||
private SpriteSystem _spriteSystem;
|
||||
|
||||
public event Action<ButtonEventArgs>? OnItemSelected;
|
||||
public event Action<ButtonEventArgs>? OnOrderApproved;
|
||||
@@ -34,25 +27,18 @@ namespace Content.Client.Cargo.UI
|
||||
private readonly List<string> _categoryStrings = new();
|
||||
private string? _category;
|
||||
|
||||
public CargoConsoleMenu(CargoConsoleBoundUserInterface owner)
|
||||
public CargoConsoleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
Owner = owner;
|
||||
_protoManager = protoManager;
|
||||
_spriteSystem = spriteSystem;
|
||||
|
||||
Title = Loc.GetString(Owner.RequestOnly
|
||||
? "cargo-console-menu-request-only-title"
|
||||
: "cargo-console-menu-title");
|
||||
Title = Loc.GetString("cargo-console-menu-title");
|
||||
|
||||
CallShuttleButton.OnPressed += OnCallShuttleButtonPressed;
|
||||
SearchBar.OnTextChanged += OnSearchBarTextChanged;
|
||||
Categories.OnItemSelected += OnCategoryItemSelected;
|
||||
}
|
||||
|
||||
private void OnCallShuttleButtonPressed(ButtonEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs args)
|
||||
{
|
||||
SetCategoryText(args.Id);
|
||||
@@ -70,7 +56,7 @@ namespace Content.Client.Cargo.UI
|
||||
Categories.SelectId(id);
|
||||
}
|
||||
|
||||
public IEnumerable<CargoProductPrototype> ProductPrototypes => _prototypeManager.EnumeratePrototypes<CargoProductPrototype>();
|
||||
public IEnumerable<CargoProductPrototype> ProductPrototypes => _protoManager.EnumeratePrototypes<CargoProductPrototype>();
|
||||
|
||||
/// <summary>
|
||||
/// Populates the list of products that will actually be shown, using the current filters.
|
||||
@@ -78,9 +64,12 @@ namespace Content.Client.Cargo.UI
|
||||
public void PopulateProducts()
|
||||
{
|
||||
Products.RemoveAllChildren();
|
||||
var products = ProductPrototypes.ToList();
|
||||
products.Sort((x, y) =>
|
||||
string.Compare(x.Name, y.Name, StringComparison.Ordinal));
|
||||
|
||||
var search = SearchBar.Text.Trim().ToLowerInvariant();
|
||||
foreach (var prototype in ProductPrototypes)
|
||||
foreach (var prototype in products)
|
||||
{
|
||||
// if no search or category
|
||||
// else if search
|
||||
@@ -94,7 +83,7 @@ namespace Content.Client.Cargo.UI
|
||||
Product = prototype,
|
||||
ProductName = { Text = prototype.Name },
|
||||
PointCost = { Text = prototype.PointCost.ToString() },
|
||||
Icon = { Texture = prototype.Icon.Frame0() },
|
||||
Icon = { Texture = _spriteSystem.Frame0(prototype.Icon) },
|
||||
};
|
||||
button.MainButton.OnPressed += args =>
|
||||
{
|
||||
@@ -132,31 +121,20 @@ namespace Content.Client.Cargo.UI
|
||||
/// <summary>
|
||||
/// Populates the list of orders and requests.
|
||||
/// </summary>
|
||||
public void PopulateOrders()
|
||||
public void PopulateOrders(IEnumerable<CargoOrderData> orders)
|
||||
{
|
||||
Orders.RemoveAllChildren();
|
||||
Requests.RemoveAllChildren();
|
||||
Orders.DisposeAllChildren();
|
||||
Requests.DisposeAllChildren();
|
||||
|
||||
if (Owner.Orders == null)
|
||||
foreach (var order in orders)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var order in Owner.Orders.Orders)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<CargoProductPrototype>(order.ProductId, out CargoProductPrototype? product))
|
||||
{
|
||||
DebugTools.Assert(false);
|
||||
Logger.ErrorS("cargo", $"Unable to find product name for {order.ProductId}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var product = _protoManager.Index<CargoProductPrototype>(order.ProductId);
|
||||
var productName = product.Name;
|
||||
|
||||
var row = new CargoOrderRow
|
||||
{
|
||||
Order = order,
|
||||
Icon = { Texture = product.Icon.Frame0() },
|
||||
Icon = { Texture = _spriteSystem.Frame0(product.Icon) },
|
||||
ProductName =
|
||||
{
|
||||
Text = Loc.GetString(
|
||||
@@ -177,43 +155,23 @@ namespace Content.Client.Cargo.UI
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Owner.RequestOnly)
|
||||
row.Approve.Visible = false;
|
||||
else
|
||||
row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(args); };
|
||||
// TODO: Disable based on access.
|
||||
row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(args); };
|
||||
Requests.AddChild(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Populate()
|
||||
public void UpdateCargoCapacity(int count, int capacity)
|
||||
{
|
||||
PopulateProducts();
|
||||
PopulateCategories();
|
||||
PopulateOrders();
|
||||
// TODO: Rename + Loc.
|
||||
ShuttleCapacityLabel.Text = $"{count}/{capacity}";
|
||||
}
|
||||
|
||||
public void UpdateCargoCapacity()
|
||||
public void UpdateBankData(string name, int points)
|
||||
{
|
||||
ShuttleCapacityLabel.Text = $"{Owner.ShuttleCapacity.CurrentCapacity}/{Owner.ShuttleCapacity.MaxCapacity}";
|
||||
}
|
||||
|
||||
public void UpdateBankData()
|
||||
{
|
||||
AccountNameLabel.Text = Owner.BankName;
|
||||
PointsLabel.Text = Owner.BankBalance.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show/Hide Call Shuttle button and Approve buttons
|
||||
/// </summary>
|
||||
public void UpdateRequestOnly()
|
||||
{
|
||||
CallShuttleButton.Visible = !Owner.RequestOnly;
|
||||
foreach (CargoOrderRow row in Requests.Children)
|
||||
{
|
||||
row.Approve.Visible = !Owner.RequestOnly;
|
||||
}
|
||||
AccountNameLabel.Text = name;
|
||||
PointsLabel.Text = points.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
47
Content.Client/Cargo/UI/CargoShuttleMenu.xaml
Normal file
47
Content.Client/Cargo/UI/CargoShuttleMenu.xaml
Normal file
@@ -0,0 +1,47 @@
|
||||
<userInterface:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:userInterface="clr-namespace:Content.Client.UserInterface"
|
||||
SetSize="600 600"
|
||||
MinSize="600 600">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-account-name-label'}"
|
||||
StyleClasses="LabelKeyText" />
|
||||
<Label Name="AccountNameLabel"
|
||||
Text="{Loc 'cargo-console-menu-account-name-none-text'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-shuttle-name-label'}"
|
||||
StyleClasses="LabelKeyText" />
|
||||
<Label Name="ShuttleNameLabel"
|
||||
Text="{Loc 'cargo-console-menu-shuttle-name-none-text'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'cargo-console-menu-shuttle-status-label'}"
|
||||
StyleClasses="LabelKeyText" />
|
||||
<Label Name="ShuttleStatusLabel"
|
||||
Text="{Loc 'cargo-console-menu-shuttle-status-away-text'}" />
|
||||
</BoxContainer>
|
||||
<Button Name="ShuttleCallButton"
|
||||
Text="Call Shuttle"/>
|
||||
<Button Name="ShuttleRecallButton"
|
||||
Text="Recall Shuttle"
|
||||
ToolTip="Needs to be out of range to recall."
|
||||
Visible="False"/>
|
||||
<Label Text="{Loc 'cargo-console-menu-orders-label'}" />
|
||||
<PanelContainer VerticalExpand="True"
|
||||
SizeFlagsStretchRatio="6">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#000000" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="Orders"
|
||||
Orientation="Vertical"
|
||||
StyleClasses="transparentItemList"
|
||||
VerticalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
<TextureButton VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</userInterface:FancyWindow>
|
||||
128
Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs
Normal file
128
Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Cargo;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Cargo.UI
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CargoShuttleMenu : FancyWindow
|
||||
{
|
||||
private readonly IGameTiming _timing;
|
||||
private readonly IPrototypeManager _protoManager;
|
||||
private readonly SpriteSystem _spriteSystem;
|
||||
|
||||
public Action? ShuttleCallRequested;
|
||||
public Action? ShuttleRecallRequested;
|
||||
|
||||
private TimeSpan? _shuttleEta;
|
||||
|
||||
public CargoShuttleMenu(IGameTiming timing, IPrototypeManager protoManager, SpriteSystem spriteSystem)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_timing = timing;
|
||||
_protoManager = protoManager;
|
||||
_spriteSystem = spriteSystem;
|
||||
ShuttleCallButton.OnPressed += OnCallPressed;
|
||||
ShuttleRecallButton.OnPressed += OnRecallPressed;
|
||||
Title = Loc.GetString("cargo-shuttle-console-menu-title");
|
||||
}
|
||||
|
||||
public void SetAccountName(string name)
|
||||
{
|
||||
AccountNameLabel.Text = name;
|
||||
}
|
||||
|
||||
public void SetShuttleName(string name)
|
||||
{
|
||||
ShuttleNameLabel.Text = name;
|
||||
}
|
||||
|
||||
public void SetShuttleETA(TimeSpan? eta)
|
||||
{
|
||||
_shuttleEta = eta;
|
||||
|
||||
if (eta == null)
|
||||
{
|
||||
ShuttleCallButton.Visible = false;
|
||||
ShuttleRecallButton.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShuttleRecallButton.Visible = false;
|
||||
ShuttleCallButton.Visible = true;
|
||||
ShuttleCallButton.Disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRecallPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
ShuttleRecallRequested?.Invoke();
|
||||
}
|
||||
|
||||
private void OnCallPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
ShuttleCallRequested?.Invoke();
|
||||
}
|
||||
|
||||
public void SetOrders(List<CargoOrderData> orders)
|
||||
{
|
||||
Orders.DisposeAllChildren();
|
||||
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var product = _protoManager.Index<CargoProductPrototype>(order.ProductId);
|
||||
var productName = product.Name;
|
||||
|
||||
var row = new CargoOrderRow
|
||||
{
|
||||
Order = order,
|
||||
Icon = { Texture = _spriteSystem.Frame0(product.Icon) },
|
||||
ProductName =
|
||||
{
|
||||
Text = Loc.GetString(
|
||||
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
|
||||
("productName", productName),
|
||||
("orderAmount", order.Amount),
|
||||
("orderRequester", order.Requester))
|
||||
},
|
||||
Description = {Text = Loc.GetString("cargo-console-menu-order-reason-description",
|
||||
("reason", order.Reason))}
|
||||
};
|
||||
|
||||
row.Approve.Visible = false;
|
||||
row.Cancel.Visible = false;
|
||||
|
||||
Orders.AddChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCanRecall(bool canRecall)
|
||||
{
|
||||
ShuttleRecallButton.Disabled = !canRecall;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
var remaining = _shuttleEta - _timing.CurTime;
|
||||
|
||||
if (remaining == null || remaining <= TimeSpan.Zero)
|
||||
{
|
||||
ShuttleStatusLabel.Text = $"Available";
|
||||
ShuttleCallButton.Disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShuttleStatusLabel.Text = $"Available in: {remaining.Value.TotalSeconds:0.0}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.Cargo.UI
|
||||
{
|
||||
public sealed class GalacticBankSelectionMenu : DefaultWindow
|
||||
{
|
||||
private readonly ItemList _accounts;
|
||||
private int _accountCount;
|
||||
private string[] _accountNames = System.Array.Empty<string>();
|
||||
private int[] _accountIds = System.Array.Empty<int>();
|
||||
private int _selectedAccountId = -1;
|
||||
|
||||
public GalacticBankSelectionMenu(CargoConsoleBoundUserInterface owner)
|
||||
{
|
||||
MinSize = SetSize = (300, 300);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Title = Loc.GetString("galactic-bank-selection-menu-title");
|
||||
|
||||
_accounts = new ItemList { SelectMode = ItemList.ItemListSelectMode.Single };
|
||||
|
||||
Contents.AddChild(_accounts);
|
||||
}
|
||||
|
||||
public void Populate(int accountCount, string[] accountNames, int[] accountIds, int selectedAccountId)
|
||||
{
|
||||
_accountCount = accountCount;
|
||||
_accountNames = accountNames;
|
||||
_accountIds = accountIds;
|
||||
_selectedAccountId = selectedAccountId;
|
||||
|
||||
_accounts.Clear();
|
||||
for (var i = 0; i < _accountCount; i++)
|
||||
{
|
||||
var id = _accountIds[i];
|
||||
_accounts.AddItem($"ID: {id} || {_accountNames[i]}");
|
||||
if (id == _selectedAccountId)
|
||||
_accounts[id].Selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,11 +128,10 @@ namespace Content.Client.Chat.UI
|
||||
Modulate = Color.White;
|
||||
}
|
||||
|
||||
var worldPos = xform.WorldPosition;
|
||||
var scale = _eyeManager.MainViewport.GetRenderScale();
|
||||
var offset = new Vector2(0, EntityVerticalOffset * EyeManager.PixelsPerMeter * scale);
|
||||
var lowerCenter = (_eyeManager.WorldToScreen(worldPos) - offset) / UIScale;
|
||||
var offset = (-_eyeManager.CurrentEye.Rotation).ToWorldVec() * -EntityVerticalOffset;
|
||||
var worldPos = xform.WorldPosition + offset;
|
||||
|
||||
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
|
||||
var screenPos = lowerCenter - (ContentSize.X / 2, ContentSize.Y + _verticalOffsetAchieved);
|
||||
// Round to nearest 0.5
|
||||
screenPos = (screenPos * 2).Rounded() / 2;
|
||||
|
||||
@@ -251,14 +251,14 @@ public sealed class ClothingSystem : EntitySystem
|
||||
|
||||
if (ev.Layers.Count == 0)
|
||||
{
|
||||
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers));
|
||||
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true);
|
||||
return;
|
||||
}
|
||||
|
||||
// temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a
|
||||
// bookmark to determine where in the list of layers we should insert the clothing layers.
|
||||
bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index);
|
||||
|
||||
|
||||
// add the new layers
|
||||
foreach (var (key, layerData) in ev.Layers)
|
||||
{
|
||||
@@ -294,6 +294,6 @@ public sealed class ClothingSystem : EntitySystem
|
||||
layer.Offset += slotDef.Offset;
|
||||
}
|
||||
|
||||
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers));
|
||||
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ namespace Content.Client.DragDrop
|
||||
// CanInteract() doesn't support checking a second "target" entity.
|
||||
// Doing so manually:
|
||||
var ev = new GettingInteractedWithAttemptEvent(eventArgs.User, eventArgs.Dragged);
|
||||
RaiseLocalEvent(eventArgs.Dragged, ev);
|
||||
RaiseLocalEvent(eventArgs.Dragged, ev, true);
|
||||
if (ev.Cancelled)
|
||||
return false;
|
||||
|
||||
|
||||
58
Content.Client/Drugs/DrugOverlaySystem.cs
Normal file
58
Content.Client/Drugs/DrugOverlaySystem.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Drugs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
|
||||
namespace Content.Client.Drugs;
|
||||
|
||||
/// <summary>
|
||||
/// System to handle drug related overlays.
|
||||
/// </summary>
|
||||
public sealed class DrugOverlaySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||
|
||||
private RainbowOverlay _overlay = default!;
|
||||
|
||||
public static string RainbowKey = "SeeingRainbows";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentShutdown>(OnShutdown);
|
||||
|
||||
SubscribeLocalEvent<SeeingRainbowsComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<SeeingRainbowsComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
|
||||
_overlay = new();
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, PlayerAttachedEvent args)
|
||||
{
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, PlayerDetachedEvent args)
|
||||
{
|
||||
_overlay.Intoxication = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
|
||||
{
|
||||
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||
{
|
||||
_overlay.Intoxication = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Content.Client/Drugs/RainbowOverlay.cs
Normal file
70
Content.Client/Drugs/RainbowOverlay.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Content.Shared.Drugs;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Drugs;
|
||||
|
||||
public sealed class RainbowOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
public override bool RequestScreenTexture => true;
|
||||
private readonly ShaderInstance _rainbowShader;
|
||||
|
||||
public float Intoxication = 0.0f;
|
||||
|
||||
private const float VisualThreshold = 10.0f;
|
||||
private const float PowerDivisor = 250.0f;
|
||||
|
||||
private float EffectScale => Math.Clamp((Intoxication - VisualThreshold) / PowerDivisor, 0.0f, 1.0f);
|
||||
|
||||
public RainbowOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
var playerEntity = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
|
||||
if (playerEntity == null)
|
||||
return;
|
||||
|
||||
if (!_entityManager.HasComponent<SeeingRainbowsComponent>(playerEntity)
|
||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
||||
return;
|
||||
|
||||
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
||||
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
|
||||
return;
|
||||
|
||||
var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
|
||||
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
return EffectScale > 0;
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (ScreenTexture == null)
|
||||
return;
|
||||
|
||||
var handle = args.WorldHandle;
|
||||
_rainbowShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||
_rainbowShader.SetParameter("effectScale", EffectScale);
|
||||
handle.UseShader(_rainbowShader);
|
||||
handle.DrawRect(args.WorldBounds, Color.White);
|
||||
}
|
||||
}
|
||||
81
Content.Client/Drunk/DrunkOverlay.cs
Normal file
81
Content.Client/Drunk/DrunkOverlay.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Content.Shared.Drunk;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Drunk;
|
||||
|
||||
public sealed class DrunkOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
public override bool RequestScreenTexture => true;
|
||||
private readonly ShaderInstance _drunkShader;
|
||||
|
||||
public float CurrentBoozePower = 0.0f;
|
||||
|
||||
private const float VisualThreshold = 10.0f;
|
||||
private const float PowerDivisor = 250.0f;
|
||||
|
||||
private float _visualScale = 0;
|
||||
|
||||
public DrunkOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_drunkShader = _prototypeManager.Index<ShaderPrototype>("Drunk").InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
var playerEntity = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
|
||||
if (playerEntity == null)
|
||||
return;
|
||||
|
||||
if (!_entityManager.HasComponent<DrunkComponent>(playerEntity)
|
||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
||||
return;
|
||||
|
||||
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
||||
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrunkSystem.DrunkKey, out var time, status))
|
||||
return;
|
||||
|
||||
var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
|
||||
CurrentBoozePower += (timeLeft - CurrentBoozePower) * args.DeltaSeconds / 16f;
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
_visualScale = BoozePowerToVisual(CurrentBoozePower);
|
||||
return _visualScale > 0;
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (ScreenTexture == null)
|
||||
return;
|
||||
|
||||
var handle = args.WorldHandle;
|
||||
_drunkShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||
_drunkShader.SetParameter("boozePower", _visualScale);
|
||||
handle.UseShader(_drunkShader);
|
||||
handle.DrawRect(args.WorldBounds, Color.White);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the # of seconds the drunk effect lasts for (booze power) to a percentage
|
||||
/// used by the actual shader.
|
||||
/// </summary>
|
||||
/// <param name="boozePower"></param>
|
||||
private float BoozePowerToVisual(float boozePower)
|
||||
{
|
||||
return Math.Clamp((boozePower - VisualThreshold) / PowerDivisor, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
53
Content.Client/Drunk/DrunkSystem.cs
Normal file
53
Content.Client/Drunk/DrunkSystem.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Content.Shared.Drunk;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
|
||||
namespace Content.Client.Drunk;
|
||||
|
||||
public sealed class DrunkSystem : SharedDrunkSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||
|
||||
private DrunkOverlay _overlay = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DrunkComponent, ComponentInit>(OnDrunkInit);
|
||||
SubscribeLocalEvent<DrunkComponent, ComponentShutdown>(OnDrunkShutdown);
|
||||
|
||||
SubscribeLocalEvent<DrunkComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<DrunkComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
|
||||
_overlay = new();
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, DrunkComponent component, PlayerAttachedEvent args)
|
||||
{
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(EntityUid uid, DrunkComponent component, PlayerDetachedEvent args)
|
||||
{
|
||||
_overlay.CurrentBoozePower = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnDrunkInit(EntityUid uid, DrunkComponent component, ComponentInit args)
|
||||
{
|
||||
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnDrunkShutdown(EntityUid uid, DrunkComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||
{
|
||||
_overlay.CurrentBoozePower = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,6 @@ namespace Content.Client.Entry
|
||||
factory.RegisterClass<SharedLatheComponent>();
|
||||
factory.RegisterClass<SharedSpawnPointComponent>();
|
||||
factory.RegisterClass<SharedVendingMachineComponent>();
|
||||
factory.RegisterClass<SharedCargoConsoleComponent>();
|
||||
factory.RegisterClass<SharedReagentDispenserComponent>();
|
||||
factory.RegisterClass<SharedChemMasterComponent>();
|
||||
factory.RegisterClass<SharedGravityGeneratorComponent>();
|
||||
|
||||
@@ -105,7 +105,7 @@ public sealed class EyeLerpingSystem : EntitySystem
|
||||
if (!TryComp(uid, out TransformComponent? transform)
|
||||
|| !TryComp(uid, out EyeComponent? eye)
|
||||
|| eye.Eye == null
|
||||
|| !_mapManager.TryGetGrid(transform.GridEntityId, out var grid))
|
||||
|| !_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
||||
{
|
||||
_toRemove.Add(uid);
|
||||
return;
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace Content.Client.GameTicking.Managers
|
||||
public sealed class ClientGameTicker : SharedGameTicker
|
||||
{
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
[ViewVariables] private bool _initialized;
|
||||
private Dictionary<EntityUid, Dictionary<string, uint?>> _jobsAvailable = new();
|
||||
private Dictionary<EntityUid, string> _stationNames = new();
|
||||
@@ -135,7 +137,7 @@ namespace Content.Client.GameTicking.Managers
|
||||
RestartSound = message.RestartSound;
|
||||
|
||||
//This is not ideal at all, but I don't see an immediately better fit anywhere else.
|
||||
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.RoundId, message.AllPlayersEndInfo);
|
||||
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.RoundId, message.AllPlayersEndInfo, _entityManager);
|
||||
}
|
||||
|
||||
private void RoundRestartCleanup(RoundRestartCleanupEvent ev)
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Content.Client.Hands
|
||||
if (hand.HeldEntity == null)
|
||||
{
|
||||
// the held item was removed.
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers));
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ namespace Content.Client.Hands
|
||||
|
||||
if (ev.Layers.Count == 0)
|
||||
{
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers));
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace Content.Client.Hands
|
||||
sprite.LayerSetData(index, layerData);
|
||||
}
|
||||
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers));
|
||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
||||
}
|
||||
|
||||
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Content.Client.IconSmoothing
|
||||
[RegisterComponent]
|
||||
public sealed class IconSmoothComponent : Component
|
||||
{
|
||||
public (EntityUid, Vector2i)? LastPosition;
|
||||
public (EntityUid?, Vector2i)? LastPosition;
|
||||
|
||||
/// <summary>
|
||||
/// We will smooth with other objects with the same key.
|
||||
|
||||
@@ -33,9 +33,9 @@ namespace Content.Client.IconSmoothing
|
||||
var xform = Transform(uid);
|
||||
if (xform.Anchored)
|
||||
{
|
||||
component.LastPosition = _mapManager.TryGetGrid(xform.GridEntityId, out var grid)
|
||||
? (xform.GridEntityId, grid.TileIndicesFor(xform.Coordinates))
|
||||
: (EntityUid.Invalid, new Vector2i(0, 0));
|
||||
component.LastPosition = _mapManager.TryGetGrid(xform.GridUid, out var grid)
|
||||
? (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates))
|
||||
: (null, new Vector2i(0, 0));
|
||||
|
||||
DirtyNeighbours(uid, component);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ namespace Content.Client.IconSmoothing
|
||||
|
||||
Vector2i pos;
|
||||
|
||||
if (transform.Anchored && _mapManager.TryGetGrid(transform.GridEntityId, out var grid))
|
||||
if (transform.Anchored && _mapManager.TryGetGrid(transform.GridUid, out var grid))
|
||||
{
|
||||
pos = grid.CoordinatesToTile(transform.Coordinates);
|
||||
}
|
||||
@@ -191,9 +191,9 @@ namespace Content.Client.IconSmoothing
|
||||
|
||||
if (xform.Anchored)
|
||||
{
|
||||
if (!_mapManager.TryGetGrid(xform.GridEntityId, out grid))
|
||||
if (!_mapManager.TryGetGrid(xform.GridUid, out grid))
|
||||
{
|
||||
Logger.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridEntityId} was missing.");
|
||||
Logger.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridUid} was missing.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public sealed class ItemSystem : SharedItemSystem
|
||||
|
||||
// if the item is in a container, it might be equipped to hands or inventory slots --> update visuals.
|
||||
if (_containerSystem.TryGetContainingContainer(uid, out var container))
|
||||
RaiseLocalEvent(container.Owner, new VisualsChangedEvent(uid, container.ID));
|
||||
RaiseLocalEvent(container.Owner, new VisualsChangedEvent(uid, container.ID), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace Content.Client.Items.UI
|
||||
}
|
||||
|
||||
var collectMsg = new ItemStatusCollectMessage();
|
||||
_entityManager.EventBus.RaiseLocalEvent(_entity!.Value, collectMsg);
|
||||
_entityManager.EventBus.RaiseLocalEvent(_entity!.Value, collectMsg, true);
|
||||
|
||||
foreach (var control in collectMsg.Controls)
|
||||
{
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Shared.Kudzu;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Client.Kudzu;
|
||||
|
||||
public sealed class KudzuVisualizer : AppearanceVisualizer
|
||||
{
|
||||
[DataField("layer")]
|
||||
private int Layer { get; } = 0;
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
var entities = IoCManager.Resolve<IEntityManager>();
|
||||
if (!entities.TryGetComponent(component.Owner, out SpriteComponent? sprite))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.TryGetData(KudzuVisuals.Variant, out int var) && component.TryGetData(KudzuVisuals.GrowthLevel, out int level))
|
||||
{
|
||||
sprite.LayerMapReserveBlank(Layer);
|
||||
sprite.LayerSetState(0, $"kudzu_{level}{var}");
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Content.Client/Kudzu/KudzuVisualizerComponent.cs
Normal file
10
Content.Client/Kudzu/KudzuVisualizerComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Content.Client.Kudzu
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class KudzuVisualsComponent : Component
|
||||
{
|
||||
[DataField("layer")]
|
||||
public int Layer { get; } = 0;
|
||||
}
|
||||
|
||||
}
|
||||
22
Content.Client/Kudzu/KudzuVisualizerSystem.cs
Normal file
22
Content.Client/Kudzu/KudzuVisualizerSystem.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Content.Shared.Kudzu;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Kudzu
|
||||
{
|
||||
|
||||
public sealed class KudzuVisualsSystem : VisualizerSystem<KudzuVisualsComponent>
|
||||
{
|
||||
protected override void OnAppearanceChange(EntityUid uid, KudzuVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
if (args.Component.TryGetData(KudzuVisuals.Variant, out int var)
|
||||
&& args.Component.TryGetData(KudzuVisuals.GrowthLevel, out int level))
|
||||
{
|
||||
var index = args.Sprite.LayerMapReserveBlank(component.Layer);
|
||||
args.Sprite.LayerSetState(index, $"kudzu_{level}{var}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,9 +76,10 @@ namespace Content.Client.NodeContainer
|
||||
var node = _system.NodeLookup[(groupId, nodeId)];
|
||||
|
||||
|
||||
var gridId = _entityManager.GetComponent<TransformComponent>(node.Entity).GridEntityId;
|
||||
var grid = _mapManager.GetGrid(gridId);
|
||||
var gridTile = grid.TileIndicesFor(_entityManager.GetComponent<TransformComponent>(node.Entity).Coordinates);
|
||||
var xform = _entityManager.GetComponent<TransformComponent>(node.Entity);
|
||||
if (!_mapManager.TryGetGrid(xform.GridUid, out var grid))
|
||||
return;
|
||||
var gridTile = grid.TileIndicesFor(xform.Coordinates);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"entity: {node.Entity}\n");
|
||||
|
||||
@@ -30,6 +30,12 @@ public sealed class OrbitVisualsSystem : EntitySystem
|
||||
|
||||
component.OrbitLength = _robustRandom.NextFloat(0.5f * component.OrbitLength, 1.5f * component.OrbitLength);
|
||||
|
||||
if (TryComp<SpriteComponent>(uid, out var sprite))
|
||||
{
|
||||
sprite.EnableDirectionOverride = true;
|
||||
sprite.DirectionOverride = Direction.South;
|
||||
}
|
||||
|
||||
var animationPlayer = EntityManager.EnsureComponent<AnimationPlayerComponent>(uid);
|
||||
if (animationPlayer.HasRunningAnimation(_orbitAnimationKey))
|
||||
return;
|
||||
@@ -44,9 +50,11 @@ public sealed class OrbitVisualsSystem : EntitySystem
|
||||
|
||||
private void OnComponentRemove(EntityUid uid, OrbitVisualsComponent component, ComponentRemove args)
|
||||
{
|
||||
if (!TryComp<ISpriteComponent>(uid, out var sprite))
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
return;
|
||||
|
||||
sprite.EnableDirectionOverride = false;
|
||||
|
||||
var animationPlayer = EntityManager.EnsureComponent<AnimationPlayerComponent>(uid);
|
||||
if (animationPlayer.HasRunningAnimation(_orbitAnimationKey))
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.Client.Physics.Controllers
|
||||
return;
|
||||
}
|
||||
|
||||
if (xform.GridEntityId != EntityUid.Invalid)
|
||||
if (xform.GridUid != null)
|
||||
mover.LastGridAngle = GetParentGridAngle(xform, mover);
|
||||
|
||||
// Essentially we only want to set our mob to predicted so every other entity we just interpolate
|
||||
@@ -66,7 +66,7 @@ namespace Content.Client.Physics.Controllers
|
||||
// Server-side should just be handled on its own so we'll just do this shizznit
|
||||
if (TryComp(player, out IMobMoverComponent? mobMover))
|
||||
{
|
||||
HandleMobMovement(mover, body, mobMover, xform);
|
||||
HandleMobMovement(mover, body, mobMover, xform, frameTime);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Message;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -10,10 +11,13 @@ namespace Content.Client.RoundEnd
|
||||
{
|
||||
public sealed class RoundEndSummaryWindow : DefaultWindow
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
|
||||
public RoundEndSummaryWindow(string gm, string roundEnd, TimeSpan roundTimeSpan, int roundId,
|
||||
RoundEndMessageEvent.RoundEndPlayerInfo[] info)
|
||||
RoundEndMessageEvent.RoundEndPlayerInfo[] info, IEntityManager entityManager)
|
||||
{
|
||||
_entityManager = entityManager;
|
||||
|
||||
MinSize = SetSize = (520, 580);
|
||||
|
||||
Title = Loc.GetString("round-end-summary-window-title");
|
||||
@@ -105,7 +109,27 @@ namespace Content.Client.RoundEnd
|
||||
//Create labels for each player info.
|
||||
foreach (var playerInfo in sortedPlayersInfo)
|
||||
{
|
||||
var playerInfoText = new RichTextLabel();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
};
|
||||
|
||||
var playerInfoText = new RichTextLabel
|
||||
{
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
VerticalExpand = true,
|
||||
};
|
||||
|
||||
if (_entityManager.TryGetComponent(playerInfo.PlayerEntityUid, out ISpriteComponent? sprite))
|
||||
{
|
||||
hBox.AddChild(new SpriteView
|
||||
{
|
||||
Sprite = sprite,
|
||||
OverrideDirection = Direction.South,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
VerticalExpand = true,
|
||||
});
|
||||
}
|
||||
|
||||
if (playerInfo.PlayerICName != null)
|
||||
{
|
||||
@@ -129,7 +153,8 @@ namespace Content.Client.RoundEnd
|
||||
("playerRole", Loc.GetString(playerInfo.Role))));
|
||||
}
|
||||
}
|
||||
playerInfoContainer.AddChild(playerInfoText);
|
||||
hBox.AddChild(playerInfoText);
|
||||
playerInfoContainer.AddChild(hBox);
|
||||
}
|
||||
|
||||
playerInfoContainerScrollbox.AddChild(playerInfoContainer);
|
||||
|
||||
@@ -24,6 +24,7 @@ public sealed class RadarConsoleBoundUserInterface : BoundUserInterface
|
||||
base.UpdateState(state);
|
||||
if (state is not RadarConsoleBoundInterfaceState cState) return;
|
||||
|
||||
_window?.SetMatrix(cState.Coordinates, cState.Angle);
|
||||
_window?.UpdateState(cState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ public sealed class ShuttleConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (state is not ShuttleConsoleBoundInterfaceState cState) return;
|
||||
|
||||
_window?.SetMatrix(cState.Coordinates, cState.Angle);
|
||||
_window?.UpdateState(cState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,4 @@ using Content.Shared.Shuttles.Events;
|
||||
|
||||
namespace Content.Client.Shuttles.Systems;
|
||||
|
||||
public sealed class DockingSystem : EntitySystem
|
||||
{
|
||||
public void StartAutodock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new AutodockRequestMessage {Entity = uid});
|
||||
}
|
||||
|
||||
public void StopAutodock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new StopAutodockRequestMessage() {Entity = uid});
|
||||
}
|
||||
|
||||
public void Undock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new UndockRequestMessage() {Entity = uid});
|
||||
}
|
||||
}
|
||||
public sealed class DockingSystem : EntitySystem {}
|
||||
|
||||
@@ -31,6 +31,9 @@ public class DockingControl : Control
|
||||
public EntityUid? ViewedDock;
|
||||
public EntityUid? GridEntity;
|
||||
|
||||
public EntityCoordinates? Coordinates;
|
||||
public Angle? Angle;
|
||||
|
||||
/// <summary>
|
||||
/// Stored by GridID then by docks
|
||||
/// </summary>
|
||||
@@ -69,11 +72,12 @@ public class DockingControl : Control
|
||||
handle.DrawLine((MidPoint, MidPoint) - aExtent, (MidPoint, MidPoint) + aExtent, gridLines);
|
||||
}
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(ViewedDock, out var xform) ||
|
||||
if (Coordinates == null ||
|
||||
Angle == null ||
|
||||
!_entManager.TryGetComponent<TransformComponent>(GridEntity, out var gridXform)) return;
|
||||
|
||||
var rotation = Matrix3.CreateRotation(xform.LocalRotation);
|
||||
var matrix = Matrix3.CreateTranslation(-xform.LocalPosition);
|
||||
var rotation = Matrix3.CreateRotation(Angle.Value);
|
||||
var matrix = Matrix3.CreateTranslation(-Coordinates.Value.Position);
|
||||
|
||||
// Draw the fixtures around the dock before drawing it
|
||||
if (_entManager.TryGetComponent<FixturesComponent>(GridEntity, out var fixtures))
|
||||
@@ -128,7 +132,7 @@ public class DockingControl : Control
|
||||
ScalePosition(rotation.Transform(new Vector2(0.5f, -0.5f)))), Color.Green);
|
||||
|
||||
// Draw nearby grids
|
||||
var worldPos = gridXform.WorldMatrix.Transform(xform.LocalPosition);
|
||||
var worldPos = gridXform.WorldMatrix.Transform(Coordinates.Value.Position);
|
||||
var gridInvMatrix = gridXform.InvWorldMatrix;
|
||||
Matrix3.Multiply(in gridInvMatrix, in matrix, out var invMatrix);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Client.UserInterface;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
|
||||
@@ -19,4 +20,9 @@ public sealed partial class RadarConsoleWindow : FancyWindow,
|
||||
{
|
||||
RadarScreen.UpdateState(scc);
|
||||
}
|
||||
|
||||
public void SetMatrix(EntityCoordinates? coordinates, Angle? angle)
|
||||
{
|
||||
RadarScreen.SetMatrix(coordinates, angle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,11 @@ public sealed class RadarControl : Control
|
||||
private const float GridLinesDistance = 32f;
|
||||
|
||||
/// <summary>
|
||||
/// Entity used to transform all of the radar objects.
|
||||
/// Used to transform all of the radar objects. Typically is a shuttle console parented to a grid.
|
||||
/// </summary>
|
||||
private EntityUid? _entity;
|
||||
private EntityCoordinates? _coordinates;
|
||||
|
||||
private Angle? _rotation;
|
||||
|
||||
private float _radarMinRange = 64f;
|
||||
private float _radarMaxRange = 256f;
|
||||
@@ -61,6 +63,12 @@ public sealed class RadarControl : Control
|
||||
MinSize = (SizeFull, SizeFull);
|
||||
}
|
||||
|
||||
public void SetMatrix(EntityCoordinates? coordinates, Angle? angle)
|
||||
{
|
||||
_coordinates = coordinates;
|
||||
_rotation = angle;
|
||||
}
|
||||
|
||||
public void UpdateState(RadarConsoleBoundInterfaceState ls)
|
||||
{
|
||||
_radarMaxRange = ls.MaxRange;
|
||||
@@ -74,7 +82,6 @@ public sealed class RadarControl : Control
|
||||
if (_radarMaxRange < _radarMinRange)
|
||||
_radarMinRange = _radarMaxRange;
|
||||
|
||||
_entity = ls.Entity;
|
||||
_docks.Clear();
|
||||
|
||||
foreach (var state in ls.Docks)
|
||||
@@ -109,7 +116,7 @@ public sealed class RadarControl : Control
|
||||
handle.DrawCircle((MidPoint, MidPoint), ScaledMinimapRadius, Color.Black);
|
||||
|
||||
// No data
|
||||
if (_entity == null)
|
||||
if (_coordinates == null || _rotation == null)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
@@ -135,8 +142,8 @@ public sealed class RadarControl : Control
|
||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||
var fixturesQuery = _entManager.GetEntityQuery<FixturesComponent>();
|
||||
var bodyQuery = _entManager.GetEntityQuery<PhysicsComponent>();
|
||||
var xform = xformQuery.GetComponent(_entity.Value);
|
||||
var mapPosition = xform.MapPosition;
|
||||
|
||||
var mapPosition = _coordinates.Value.ToMap(_entManager);
|
||||
|
||||
if (mapPosition.MapId == MapId.Nullspace)
|
||||
{
|
||||
@@ -144,28 +151,30 @@ public sealed class RadarControl : Control
|
||||
return;
|
||||
}
|
||||
|
||||
// Can also use ourGridBody.LocalCenter
|
||||
var offset = xform.Coordinates.Position;
|
||||
var offsetMatrix = Matrix3.CreateTranslation(-offset);
|
||||
var offset = _coordinates.Value.Position;
|
||||
Matrix3 matrix;
|
||||
|
||||
// Draw our grid in detail
|
||||
var ourGridId = xform.GridID;
|
||||
if (ourGridId != GridId.Invalid)
|
||||
var ourGridId = _coordinates.Value.GetGridUid(_entManager);
|
||||
if (ourGridId != null)
|
||||
{
|
||||
matrix = xform.InvWorldMatrix;
|
||||
var ourGridFixtures = fixturesQuery.GetComponent(ourGridId);
|
||||
var offsetMatrix = Matrix3.CreateInverseTransform(offset.X, offset.Y, (float) _rotation.Value.Theta);
|
||||
var ourGridFixtures = fixturesQuery.GetComponent(ourGridId.Value);
|
||||
// Draw our grid; use non-filled boxes so it doesn't look awful.
|
||||
DrawGrid(handle, offsetMatrix, ourGridFixtures, Color.Yellow);
|
||||
|
||||
DrawDocks(handle, xform.GridEntityId, offsetMatrix);
|
||||
DrawDocks(handle, ourGridId.Value, offsetMatrix);
|
||||
|
||||
var ourGridMatrix = xformQuery.GetComponent(ourGridId.Value).InvWorldMatrix;
|
||||
|
||||
Matrix3.Multiply(in ourGridMatrix, in offsetMatrix, out matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix = Matrix3.CreateTranslation(-offset);
|
||||
}
|
||||
|
||||
var invertedPosition = xform.Coordinates.Position - offset;
|
||||
var invertedPosition = _coordinates.Value.Position - offset;
|
||||
invertedPosition.Y = -invertedPosition.Y;
|
||||
// Don't need to transform the InvWorldMatrix again as it's already offset to its position.
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
@@ -17,10 +18,7 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
{
|
||||
private readonly IEntityManager _entManager;
|
||||
|
||||
/// <summary>
|
||||
/// EntityUid of the open console.
|
||||
/// </summary>
|
||||
private EntityUid? _entity;
|
||||
private EntityUid? _shuttleUid;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dock button for camera.
|
||||
@@ -84,9 +82,14 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
UndockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
||||
}
|
||||
|
||||
public void SetMatrix(EntityCoordinates? coordinates, Angle? angle)
|
||||
{
|
||||
_shuttleUid = coordinates?.EntityId;
|
||||
RadarScreen.SetMatrix(coordinates, angle);
|
||||
}
|
||||
|
||||
public void UpdateState(ShuttleConsoleBoundInterfaceState scc)
|
||||
{
|
||||
_entity = scc.Entity;
|
||||
UpdateDocks(scc.Docks);
|
||||
RadarScreen.UpdateState(scc);
|
||||
MaxRadarRange.Text = $"{scc.MaxRange:0}";
|
||||
@@ -110,20 +113,16 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
DockPorts.DisposeAllChildren();
|
||||
DockingScreen.Docks = _docks;
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(_entity, out var xform))
|
||||
{
|
||||
// TODO: Show Placeholder
|
||||
return;
|
||||
}
|
||||
|
||||
if (_docks.TryGetValue(xform.GridEntityId, out var gridDocks))
|
||||
// TODO: Show Placeholder
|
||||
if (_shuttleUid != null && _docks.TryGetValue(_shuttleUid.Value, out var gridDocks))
|
||||
{
|
||||
var index = 1;
|
||||
|
||||
foreach (var state in gridDocks)
|
||||
{
|
||||
var ent = state.Entity;
|
||||
var pressed = ent == DockingScreen.ViewedDock;
|
||||
var pressed = state.Entity == DockingScreen.ViewedDock;
|
||||
|
||||
string suffix;
|
||||
|
||||
if (state.Connected)
|
||||
@@ -142,21 +141,26 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
Pressed = pressed,
|
||||
};
|
||||
|
||||
button.OnMouseEntered += args => OnDockMouseEntered(args, ent);
|
||||
button.OnMouseExited += args => OnDockMouseExited(args, ent);
|
||||
button.OnToggled += args => OnDockToggled(args, ent);
|
||||
if (pressed)
|
||||
{
|
||||
_selectedDock = button;
|
||||
}
|
||||
|
||||
button.OnMouseEntered += args => OnDockMouseEntered(args, state);
|
||||
button.OnMouseExited += args => OnDockMouseExited(args, state);
|
||||
button.OnToggled += args => OnDockToggled(args, state);
|
||||
DockPorts.AddChild(button);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDockMouseEntered(GUIMouseHoverEventArgs obj, EntityUid uid)
|
||||
private void OnDockMouseEntered(GUIMouseHoverEventArgs obj, DockingInterfaceState state)
|
||||
{
|
||||
RadarScreen.HighlightedDock = uid;
|
||||
RadarScreen.HighlightedDock = state.Entity;
|
||||
}
|
||||
|
||||
private void OnDockMouseExited(GUIMouseHoverEventArgs obj, EntityUid uid)
|
||||
private void OnDockMouseExited(GUIMouseHoverEventArgs obj, DockingInterfaceState state)
|
||||
{
|
||||
RadarScreen.HighlightedDock = null;
|
||||
}
|
||||
@@ -164,10 +168,18 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
/// <summary>
|
||||
/// Shows a docking camera instead of radar screen.
|
||||
/// </summary>
|
||||
private void OnDockToggled(BaseButton.ButtonEventArgs obj, EntityUid ent)
|
||||
private void OnDockToggled(BaseButton.ButtonEventArgs obj, DockingInterfaceState state)
|
||||
{
|
||||
var ent = state.Entity;
|
||||
|
||||
if (_selectedDock != null)
|
||||
{
|
||||
// If it got untoggled via other means then we'll stop viewing the old dock.
|
||||
if (DockingScreen.ViewedDock != null && DockingScreen.ViewedDock != state.Entity)
|
||||
{
|
||||
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
||||
}
|
||||
|
||||
_selectedDock.Pressed = false;
|
||||
_selectedDock = null;
|
||||
}
|
||||
@@ -186,15 +198,23 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
}
|
||||
else
|
||||
{
|
||||
// DebugTools.Assert(DockingScreen.ViewedDock == null);
|
||||
_entManager.TryGetComponent<TransformComponent>(_entity, out var xform);
|
||||
if (_shuttleUid != null)
|
||||
{
|
||||
DockingScreen.Coordinates = state.Coordinates;
|
||||
DockingScreen.Angle = state.Angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
DockingScreen.Coordinates = null;
|
||||
DockingScreen.Angle = null;
|
||||
}
|
||||
|
||||
UndockButton.Disabled = false;
|
||||
RadarScreen.Visible = false;
|
||||
DockingScreen.Visible = true;
|
||||
DockingScreen.ViewedDock = ent;
|
||||
StartAutodockPressed?.Invoke(ent);
|
||||
DockingScreen.GridEntity = xform?.GridEntityId;
|
||||
DockingScreen.GridEntity = _shuttleUid;
|
||||
_selectedDock = obj.Button;
|
||||
}
|
||||
}
|
||||
@@ -214,9 +234,8 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(_entity, out var entXform) ||
|
||||
!_entManager.TryGetComponent<PhysicsComponent>(entXform.GridEntityId, out var gridBody) ||
|
||||
!_entManager.TryGetComponent<TransformComponent>(entXform.GridEntityId, out var gridXform))
|
||||
if (!_entManager.TryGetComponent<PhysicsComponent>(_shuttleUid, out var gridBody) ||
|
||||
!_entManager.TryGetComponent<TransformComponent>(_shuttleUid, out var gridXform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,46 @@ namespace Content.Client.Singularity
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _prototypeManager.Index<ShaderPrototype>("Singularity").Instance().Duplicate();
|
||||
_shader.SetParameter("maxDistance", MaxDistance * EyeManager.PixelsPerMeter);
|
||||
}
|
||||
|
||||
private Vector2[] _positions = new Vector2[MaxCount];
|
||||
private float[] _intensities = new float[MaxCount];
|
||||
private float[] _falloffPowers = new float[MaxCount];
|
||||
private int _count = 0;
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (args.Viewport.Eye == null)
|
||||
return false;
|
||||
|
||||
_count = 0;
|
||||
foreach (var (distortion, xform) in _entMan.EntityQuery<SingularityDistortionComponent, TransformComponent>())
|
||||
{
|
||||
if (xform.MapID != args.MapId)
|
||||
continue;
|
||||
|
||||
var mapPos = xform.WorldPosition;
|
||||
|
||||
// is the distortion in range?
|
||||
if ((mapPos - args.WorldAABB.ClosestPoint(mapPos)).LengthSquared > MaxDistance * MaxDistance)
|
||||
continue;
|
||||
|
||||
// To be clear, this needs to use "inside-viewport" pixels.
|
||||
// In other words, specifically NOT IViewportControl.WorldToScreen (which uses outer coordinates).
|
||||
var tempCoords = args.Viewport.WorldToLocal(mapPos);
|
||||
tempCoords.Y = args.Viewport.Size.Y - tempCoords.Y;
|
||||
|
||||
_positions[_count] = tempCoords;
|
||||
_intensities[_count] = distortion.Intensity;
|
||||
_falloffPowers[_count] = distortion.FalloffPower;
|
||||
_count++;
|
||||
|
||||
if (_count == MaxCount)
|
||||
break;
|
||||
}
|
||||
|
||||
return (_count > 0);
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -34,48 +74,11 @@ namespace Content.Client.Singularity
|
||||
if (ScreenTexture == null || args.Viewport.Eye == null)
|
||||
return;
|
||||
|
||||
// Has to be correctly handled because of the way intensity/falloff transform works so just do it.
|
||||
_shader?.SetParameter("renderScale", args.Viewport.RenderScale);
|
||||
|
||||
var position = new Vector2[MaxCount];
|
||||
var intensity = new float[MaxCount];
|
||||
var falloffPower = new float[MaxCount];
|
||||
int count = 0;
|
||||
|
||||
var mapId = args.Viewport.Eye.Position.MapId;
|
||||
|
||||
foreach (var distortion in _entMan.EntityQuery<SingularityDistortionComponent>())
|
||||
{
|
||||
var mapPos = _entMan.GetComponent<TransformComponent>(distortion.Owner).MapPosition;
|
||||
if (mapPos.MapId != mapId)
|
||||
continue;
|
||||
|
||||
// is the distortion in range?
|
||||
if ((mapPos.Position - args.WorldAABB.ClosestPoint(mapPos.Position)).LengthSquared > MaxDistance * MaxDistance)
|
||||
continue;
|
||||
|
||||
// To be clear, this needs to use "inside-viewport" pixels.
|
||||
// In other words, specifically NOT IViewportControl.WorldToScreen (which uses outer coordinates).
|
||||
var tempCoords = args.Viewport.WorldToLocal(mapPos.Position);
|
||||
tempCoords.Y = args.Viewport.Size.Y - tempCoords.Y;
|
||||
|
||||
position[count] = tempCoords;
|
||||
intensity[count] = distortion.Intensity;
|
||||
falloffPower[count] = distortion.FalloffPower;
|
||||
count++;
|
||||
|
||||
if (count == MaxCount)
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
_shader?.SetParameter("count", count);
|
||||
_shader?.SetParameter("position", position);
|
||||
_shader?.SetParameter("intensity", intensity);
|
||||
_shader?.SetParameter("falloffPower", falloffPower);
|
||||
_shader?.SetParameter("maxDistance", MaxDistance * EyeManager.PixelsPerMeter);
|
||||
_shader?.SetParameter("count", _count);
|
||||
_shader?.SetParameter("position", _positions);
|
||||
_shader?.SetParameter("intensity", _intensities);
|
||||
_shader?.SetParameter("falloffPower", _falloffPowers);
|
||||
_shader?.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||
|
||||
var worldHandle = args.WorldHandle;
|
||||
|
||||
7
Content.Client/Speech/EntitySystems/SlurredSystem.cs
Normal file
7
Content.Client/Speech/EntitySystems/SlurredSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Speech.EntitySystems;
|
||||
|
||||
namespace Content.Client.Speech.EntitySystems;
|
||||
|
||||
public sealed class SlurredSystem : SharedSlurredSystem
|
||||
{
|
||||
}
|
||||
@@ -34,13 +34,14 @@ namespace Content.Client.StationEvents
|
||||
_baseShader = _prototypeManager.Index<ShaderPrototype>("Radiation").Instance().Duplicate();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
RadiationQuery(args.Viewport.Eye);
|
||||
return _pulses.Count > 0;
|
||||
}
|
||||
|
||||
if (_pulses.Count == 0)
|
||||
return;
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (ScreenTexture == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ namespace Content.Client.Verbs
|
||||
if (verb.ExecutionEventArgs != null)
|
||||
{
|
||||
if (verb.EventTarget.IsValid())
|
||||
RaiseLocalEvent(verb.EventTarget, verb.ExecutionEventArgs);
|
||||
RaiseLocalEvent(verb.EventTarget, verb.ExecutionEventArgs, true);
|
||||
else
|
||||
RaiseLocalEvent(verb.ExecutionEventArgs);
|
||||
}
|
||||
|
||||
@@ -1,440 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Client.Entry;
|
||||
using Content.Client.IoC;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.IoC;
|
||||
using Content.Shared.CCVar;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client;
|
||||
using Robust.Server;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.UnitTesting;
|
||||
|
||||
namespace Content.IntegrationTests
|
||||
{
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public abstract class ContentIntegrationTest : RobustIntegrationTest
|
||||
{
|
||||
private static readonly (string cvar, string value, bool)[] ServerTestCvars = {
|
||||
// Avoid funny race conditions with the database.
|
||||
(CCVars.DatabaseSynchronous.Name, "true", false),
|
||||
|
||||
// No artificial database delay, as it can make tests fail.
|
||||
(CCVars.DatabaseSqliteDelay.Name, "0", false),
|
||||
|
||||
// Disable holidays as some of them might mess with the map at round start.
|
||||
(CCVars.HolidaysEnabled.Name, "false", false),
|
||||
|
||||
// Avoid loading a large map by default for integration tests if none has been specified.
|
||||
(CCVars.GameMap.Name, "empty", true),
|
||||
|
||||
// Makes sure IGameMapManager actually listens.
|
||||
(CCVars.GameMapForced.Name, "true", true),
|
||||
};
|
||||
|
||||
private static void SetServerTestCvars(IntegrationOptions options)
|
||||
{
|
||||
foreach (var (cvar, value, tryAdd) in ServerTestCvars)
|
||||
{
|
||||
if (tryAdd)
|
||||
{
|
||||
options.CVarOverrides.TryAdd(cvar, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
options.CVarOverrides[cvar] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected sealed override ClientIntegrationInstance StartClient(ClientIntegrationOptions options = null)
|
||||
{
|
||||
options ??= new ClientContentIntegrationOption()
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning
|
||||
};
|
||||
|
||||
options.Pool = ShouldPool(options, false);
|
||||
|
||||
// Load content resources, but not config and user data.
|
||||
options.Options = new GameControllerOptions()
|
||||
{
|
||||
LoadContentResources = true,
|
||||
LoadConfigAndUserData = false,
|
||||
};
|
||||
|
||||
options.ContentStart = true;
|
||||
|
||||
options.ContentAssemblies = new[]
|
||||
{
|
||||
typeof(Shared.Entry.EntryPoint).Assembly,
|
||||
typeof(EntryPoint).Assembly,
|
||||
typeof(ContentIntegrationTest).Assembly
|
||||
};
|
||||
|
||||
options.BeforeStart += () =>
|
||||
{
|
||||
IoCManager.Resolve<IModLoader>().SetModuleBaseCallbacks(new ClientModuleTestingCallbacks
|
||||
{
|
||||
ClientBeforeIoC = () =>
|
||||
{
|
||||
if (options is ClientContentIntegrationOption contentOptions)
|
||||
{
|
||||
contentOptions.ContentBeforeIoC?.Invoke();
|
||||
}
|
||||
|
||||
IoCManager.Register<IParallaxManager, DummyParallaxManager>(true);
|
||||
IoCManager.Resolve<ILogManager>().GetSawmill("loc").Level = LogLevel.Error;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return base.StartClient(options);
|
||||
}
|
||||
|
||||
protected override ServerIntegrationInstance StartServer(ServerIntegrationOptions options = null)
|
||||
{
|
||||
options ??= new ServerContentIntegrationOption
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning,
|
||||
};
|
||||
|
||||
SetServerTestCvars(options);
|
||||
options.Pool = ShouldPool(options, true);
|
||||
|
||||
// Load content resources, but not config and user data.
|
||||
options.Options = new ServerOptions()
|
||||
{
|
||||
LoadConfigAndUserData = false,
|
||||
LoadContentResources = true,
|
||||
};
|
||||
|
||||
options.ContentStart = true;
|
||||
|
||||
options.ContentAssemblies = new[]
|
||||
{
|
||||
typeof(Shared.Entry.EntryPoint).Assembly,
|
||||
typeof(Server.Entry.EntryPoint).Assembly,
|
||||
typeof(ContentIntegrationTest).Assembly
|
||||
};
|
||||
|
||||
options.BeforeStart += () =>
|
||||
{
|
||||
IoCManager.Resolve<IModLoader>().SetModuleBaseCallbacks(new ServerModuleTestingCallbacks
|
||||
{
|
||||
ServerBeforeIoC = () =>
|
||||
{
|
||||
if (options is ServerContentIntegrationOption contentOptions)
|
||||
{
|
||||
contentOptions.ContentBeforeIoC?.Invoke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
IoCManager.Resolve<ILogManager>().GetSawmill("loc").Level = LogLevel.Error;
|
||||
};
|
||||
|
||||
return base.StartServer(options);
|
||||
}
|
||||
|
||||
protected ServerIntegrationInstance StartServerDummyTicker(ServerIntegrationOptions options = null)
|
||||
{
|
||||
options ??= new ServerContentIntegrationOption();
|
||||
|
||||
// Load content resources, but not config and user data.
|
||||
options.Options = new ServerOptions()
|
||||
{
|
||||
LoadConfigAndUserData = false,
|
||||
LoadContentResources = true,
|
||||
};
|
||||
|
||||
// Dummy game ticker.
|
||||
options.CVarOverrides[CCVars.GameDummyTicker.Name] = "true";
|
||||
|
||||
return StartServer(options);
|
||||
}
|
||||
|
||||
protected async Task<(ClientIntegrationInstance client, ServerIntegrationInstance server)>
|
||||
StartConnectedServerClientPair(ClientIntegrationOptions clientOptions = null,
|
||||
ServerIntegrationOptions serverOptions = null)
|
||||
{
|
||||
var client = StartClient(clientOptions);
|
||||
var server = StartServer(serverOptions);
|
||||
|
||||
await StartConnectedPairShared(client, server);
|
||||
|
||||
return (client, server);
|
||||
}
|
||||
|
||||
protected async Task<(ClientIntegrationInstance client, ServerIntegrationInstance server)>
|
||||
StartConnectedServerDummyTickerClientPair(ClientIntegrationOptions clientOptions = null,
|
||||
ServerIntegrationOptions serverOptions = null)
|
||||
{
|
||||
var client = StartClient(clientOptions);
|
||||
var server = StartServerDummyTicker(serverOptions);
|
||||
|
||||
await StartConnectedPairShared(client, server);
|
||||
|
||||
return (client, server);
|
||||
}
|
||||
|
||||
private bool ShouldPool(IntegrationOptions options, bool server)
|
||||
{
|
||||
// TODO TEST POOLING client pooling
|
||||
if (!server)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.Pool.HasValue)
|
||||
{
|
||||
return options.Pool.Value;
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
if (options.CVarOverrides.Count != 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var (cvar, value, _) in ServerTestCvars)
|
||||
{
|
||||
if (!options.CVarOverrides.TryGetValue(cvar, out var actualValue) ||
|
||||
actualValue != value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.CVarOverrides.TryGetValue(CCVars.GameDummyTicker.Name, out var dummy) &&
|
||||
dummy == "true")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.CVarOverrides.TryGetValue(CCVars.GameLobbyEnabled.Name, out var lobby) &&
|
||||
lobby == "true")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options is ClientContentIntegrationOption {ContentBeforeIoC: { }}
|
||||
or ServerContentIntegrationOption {ContentBeforeIoC: { }})
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return options.InitIoC == null &&
|
||||
options.BeforeStart == null &&
|
||||
options.ContentAssemblies == null;
|
||||
}
|
||||
|
||||
protected override async Task OnClientReturn(ClientIntegrationInstance client)
|
||||
{
|
||||
await base.OnClientReturn(client);
|
||||
|
||||
await client.WaitIdleAsync();
|
||||
|
||||
var net = client.ResolveDependency<IClientNetManager>();
|
||||
var prototypes = client.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
await client.WaitPost(() =>
|
||||
{
|
||||
net.ClientDisconnect("Test pooling disconnect");
|
||||
|
||||
if (client.PreviousOptions?.ExtraPrototypes is { } oldExtra)
|
||||
{
|
||||
prototypes.RemoveString(oldExtra);
|
||||
}
|
||||
|
||||
if (client.Options?.ExtraPrototypes is { } extra)
|
||||
{
|
||||
prototypes.LoadString(extra, true);
|
||||
prototypes.ResolveResults();
|
||||
}
|
||||
});
|
||||
|
||||
await WaitUntil(client, () => !net.IsConnected);
|
||||
}
|
||||
|
||||
protected override async Task OnServerReturn(ServerIntegrationInstance server)
|
||||
{
|
||||
await base.OnServerReturn(server);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
if (server.Options != null)
|
||||
{
|
||||
SetServerTestCvars(server.Options);
|
||||
}
|
||||
|
||||
var systems = server.ResolveDependency<IEntitySystemManager>();
|
||||
var prototypes = server.ResolveDependency<IPrototypeManager>();
|
||||
var net = server.ResolveDependency<IServerNetManager>();
|
||||
var players = server.ResolveDependency<IPlayerManager>();
|
||||
|
||||
var gameTicker = systems.GetEntitySystem<GameTicker>();
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
foreach (var channel in net.Channels)
|
||||
{
|
||||
net.DisconnectChannel(channel, "Test pooling disconnect");
|
||||
}
|
||||
});
|
||||
|
||||
await WaitUntil(server, () => players.PlayerCount == 0);
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
gameTicker.RestartRound();
|
||||
|
||||
if (server.PreviousOptions?.ExtraPrototypes is { } oldExtra)
|
||||
{
|
||||
prototypes.RemoveString(oldExtra);
|
||||
}
|
||||
|
||||
if (server.Options?.ExtraPrototypes is { } extra)
|
||||
{
|
||||
prototypes.LoadString(extra, true);
|
||||
prototypes.ResolveResults();
|
||||
}
|
||||
});
|
||||
|
||||
if (!gameTicker.DummyTicker)
|
||||
{
|
||||
await WaitUntil(server, () => gameTicker.RunLevel == GameRunLevel.InRound);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task WaitUntil(IntegrationInstance instance, Func<bool> func, int maxTicks = 600,
|
||||
int tickStep = 1)
|
||||
{
|
||||
await WaitUntil(instance, async () => await Task.FromResult(func()), maxTicks, tickStep);
|
||||
}
|
||||
|
||||
protected async Task WaitUntil(IntegrationInstance instance, Func<Task<bool>> func, int maxTicks = 600,
|
||||
int tickStep = 1)
|
||||
{
|
||||
var ticksAwaited = 0;
|
||||
bool passed;
|
||||
|
||||
await instance.WaitIdleAsync();
|
||||
|
||||
while (!(passed = await func()) && ticksAwaited < maxTicks)
|
||||
{
|
||||
var ticksToRun = tickStep;
|
||||
|
||||
if (ticksAwaited + tickStep > maxTicks)
|
||||
{
|
||||
ticksToRun = maxTicks - ticksAwaited;
|
||||
}
|
||||
|
||||
await instance.WaitRunTicks(ticksToRun);
|
||||
|
||||
ticksAwaited += ticksToRun;
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
{
|
||||
Assert.Fail($"Condition did not pass after {maxTicks} ticks.\n" +
|
||||
$"Tests ran ({instance.TestsRan.Count}):\n" +
|
||||
$"{string.Join('\n', instance.TestsRan)}");
|
||||
}
|
||||
Assert.That(passed);
|
||||
}
|
||||
|
||||
private static async Task StartConnectedPairShared(ClientIntegrationInstance client,
|
||||
ServerIntegrationInstance server)
|
||||
{
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
|
||||
client.SetConnectTarget(server);
|
||||
|
||||
client.Post(() => IoCManager.Resolve<IClientNetManager>().ClientConnect(null!, 0, null!));
|
||||
|
||||
await RunTicksSync(client, server, 10);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs <paramref name="ticks"/> ticks on both server and client while keeping their main loop in sync.
|
||||
/// </summary>
|
||||
protected static async Task RunTicksSync(ClientIntegrationInstance client, ServerIntegrationInstance server,
|
||||
int ticks)
|
||||
{
|
||||
for (var i = 0; i < ticks; i++)
|
||||
{
|
||||
await server.WaitRunTicks(1);
|
||||
await client.WaitRunTicks(1);
|
||||
}
|
||||
}
|
||||
|
||||
protected MapId GetMainMapId(IMapManager manager)
|
||||
{
|
||||
// TODO a heuristic that is not this bad
|
||||
return manager.GetAllMapIds().Last();
|
||||
}
|
||||
|
||||
protected IMapGrid GetMainGrid(IMapManager manager)
|
||||
{
|
||||
// TODO a heuristic that is not this bad
|
||||
return manager.GetAllGrids().First();
|
||||
}
|
||||
|
||||
protected TileRef GetMainTile(IMapGrid grid)
|
||||
{
|
||||
// TODO a heuristic that is not this bad
|
||||
return grid.GetAllTiles().First();
|
||||
}
|
||||
|
||||
protected EntityCoordinates GetMainEntityCoordinates(IMapManager manager)
|
||||
{
|
||||
var gridId = GetMainGrid(manager).GridEntityId;
|
||||
return new EntityCoordinates(gridId, -0.5f, -0.5f);
|
||||
}
|
||||
|
||||
protected sealed class ClientContentIntegrationOption : ClientIntegrationOptions
|
||||
{
|
||||
public ClientContentIntegrationOption()
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning;
|
||||
}
|
||||
|
||||
public override GameControllerOptions Options { get; set; } = new()
|
||||
{
|
||||
LoadContentResources = true,
|
||||
LoadConfigAndUserData = false,
|
||||
};
|
||||
|
||||
public Action ContentBeforeIoC { get; set; }
|
||||
}
|
||||
|
||||
protected sealed class ServerContentIntegrationOption : ServerIntegrationOptions
|
||||
{
|
||||
public ServerContentIntegrationOption()
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning;
|
||||
}
|
||||
|
||||
public override ServerOptions Options { get; set; } = new()
|
||||
{
|
||||
LoadContentResources = true,
|
||||
LoadConfigAndUserData = false,
|
||||
};
|
||||
|
||||
public Action ContentBeforeIoC { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
[SetUpFixture]
|
||||
// ReSharper disable once CheckNamespace
|
||||
public sealed class ContentIntegrationTestSetup
|
||||
{
|
||||
[OneTimeTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
var robustSetup = new RobustIntegrationTestSetup();
|
||||
|
||||
robustSetup.Shutdown();
|
||||
robustSetup.PrintTestPoolingInfo();
|
||||
}
|
||||
}
|
||||
708
Content.IntegrationTests/PoolManager.cs
Normal file
708
Content.IntegrationTests/PoolManager.cs
Normal file
@@ -0,0 +1,708 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Client.IoC;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Content.IntegrationTests.Tests;
|
||||
using Content.IntegrationTests.Tests.DeviceNetwork;
|
||||
using Content.IntegrationTests.Tests.Interaction.Click;
|
||||
using Content.IntegrationTests.Tests.Networking;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Maps;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client;
|
||||
using Robust.Server;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.UnitTesting;
|
||||
|
||||
|
||||
[assembly: LevelOfParallelism(3)]
|
||||
|
||||
namespace Content.IntegrationTests;
|
||||
|
||||
public static class PoolManager
|
||||
{
|
||||
private static readonly (string cvar, string value, bool tryAdd)[] ServerTestCvars =
|
||||
{
|
||||
(CCVars.DatabaseSynchronous.Name, "true", false),
|
||||
(CCVars.DatabaseSqliteDelay.Name, "0", false),
|
||||
(CCVars.HolidaysEnabled.Name, "false", false),
|
||||
(CCVars.GameMap.Name, "empty", true),
|
||||
(CCVars.GameMapForced.Name, "true", true),
|
||||
(CCVars.AdminLogsQueueSendDelay.Name, "0", true),
|
||||
(CCVars.NetPVS.Name, "false", true),
|
||||
(CCVars.NetInterp.Name, "false", true),
|
||||
(CCVars.NPCMaxUpdates.Name, "999999", true),
|
||||
(CCVars.GameMapForced.Name, "true", true),
|
||||
(CCVars.SysWinTickPeriod.Name, "0", true),
|
||||
(CCVars.ContactMinimumThreads.Name, "1", true),
|
||||
(CCVars.ContactMultithreadThreshold.Name, "999", true),
|
||||
(CCVars.PositionConstraintsMinimumThread.Name, "1", true),
|
||||
(CCVars.PositionConstraintsPerThread.Name, "999", true),
|
||||
(CCVars.VelocityConstraintMinimumThreads.Name, "1", true),
|
||||
(CCVars.VelocityConstraintsPerThread.Name, "999", true),
|
||||
(CCVars.ThreadParallelCount.Name, "1", true),
|
||||
};
|
||||
|
||||
private static int PairId = 0;
|
||||
private static object PairLock = new object();
|
||||
private static List<Pair> Pairs = new();
|
||||
|
||||
private static async Task ConfigurePrototypes(RobustIntegrationTest.IntegrationInstance instance,
|
||||
PoolSettings settings)
|
||||
{
|
||||
await instance.WaitPost(() =>
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
var changes = new Dictionary<Type, HashSet<string>>();
|
||||
prototypeManager.LoadString(settings.ExtraPrototypes.Trim(), true, changes);
|
||||
prototypeManager.ReloadPrototypes(changes);
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task<RobustIntegrationTest.ServerIntegrationInstance> GenerateServer(PoolSettings poolSettings)
|
||||
{
|
||||
var options = new RobustIntegrationTest.ServerIntegrationOptions
|
||||
{
|
||||
ExtraPrototypes = poolSettings.ExtraPrototypes,
|
||||
ContentStart = true,
|
||||
Options = new ServerOptions()
|
||||
{
|
||||
LoadConfigAndUserData = false,
|
||||
LoadContentResources = !poolSettings.NoLoadContent,
|
||||
},
|
||||
ContentAssemblies = new[]
|
||||
{
|
||||
typeof(Shared.Entry.EntryPoint).Assembly,
|
||||
typeof(Server.Entry.EntryPoint).Assembly,
|
||||
typeof(PoolManager).Assembly
|
||||
}
|
||||
};
|
||||
|
||||
options.BeforeStart += () =>
|
||||
{
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.LoadExtraSystemType<SimplePredictReconcileTest.PredictionTestEntitySystem>();
|
||||
IoCManager.Resolve<IComponentFactory>().RegisterClass<SimplePredictReconcileTest.PredictionTestComponent>();
|
||||
IoCManager.Register<ResettingEntitySystemTests.TestRoundRestartCleanupEvent>();
|
||||
IoCManager.Register<InteractionSystemTests.TestInteractionSystem>();
|
||||
IoCManager.Register<DeviceNetworkTestSystem>();
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.LoadExtraSystemType<ResettingEntitySystemTests.TestRoundRestartCleanupEvent>();
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.LoadExtraSystemType<InteractionSystemTests.TestInteractionSystem>();
|
||||
IoCManager.Resolve<IEntitySystemManager>().LoadExtraSystemType<DeviceNetworkTestSystem>();
|
||||
IoCManager.Resolve<ILogManager>().GetSawmill("loc").Level = LogLevel.Error;
|
||||
};
|
||||
|
||||
SetupCVars(poolSettings, options);
|
||||
|
||||
var server = new RobustIntegrationTest.ServerIntegrationInstance(options);
|
||||
await server.WaitIdleAsync();
|
||||
return server;
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
lock (PairLock)
|
||||
{
|
||||
var pairs = Pairs;
|
||||
// We are trying to make things blow up if they are still happening after this method.
|
||||
Pairs = null;
|
||||
foreach (var pair in pairs)
|
||||
{
|
||||
pair.Client.Dispose();
|
||||
pair.Server.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<RobustIntegrationTest.ClientIntegrationInstance> GenerateClient(PoolSettings poolSettings)
|
||||
{
|
||||
var options = new RobustIntegrationTest.ClientIntegrationOptions
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning,
|
||||
ContentStart = true,
|
||||
ExtraPrototypes = poolSettings.ExtraPrototypes,
|
||||
ContentAssemblies = new[]
|
||||
{
|
||||
typeof(Shared.Entry.EntryPoint).Assembly,
|
||||
typeof(Client.Entry.EntryPoint).Assembly,
|
||||
typeof(PoolManager).Assembly
|
||||
}
|
||||
};
|
||||
|
||||
if (poolSettings.NoLoadContent)
|
||||
{
|
||||
Assert.Warn("NoLoadContent does not work on the client, ignoring");
|
||||
}
|
||||
|
||||
options.Options = new GameControllerOptions()
|
||||
{
|
||||
LoadConfigAndUserData = false,
|
||||
// LoadContentResources = !poolSettings.NoLoadContent
|
||||
};
|
||||
|
||||
options.BeforeStart += () =>
|
||||
{
|
||||
IoCManager.Resolve<IModLoader>().SetModuleBaseCallbacks(new ClientModuleTestingCallbacks
|
||||
{
|
||||
ClientBeforeIoC = () =>
|
||||
{
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.LoadExtraSystemType<SimplePredictReconcileTest.PredictionTestEntitySystem>();
|
||||
IoCManager.Resolve<IComponentFactory>()
|
||||
.RegisterClass<SimplePredictReconcileTest.PredictionTestComponent>();
|
||||
IoCManager.Register<IParallaxManager, DummyParallaxManager>(true);
|
||||
IoCManager.Resolve<ILogManager>().GetSawmill("loc").Level = LogLevel.Error;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SetupCVars(poolSettings, options);
|
||||
|
||||
var client = new RobustIntegrationTest.ClientIntegrationInstance(options);
|
||||
await client.WaitIdleAsync();
|
||||
return client;
|
||||
}
|
||||
|
||||
private static void SetupCVars(PoolSettings poolSettings, RobustIntegrationTest.IntegrationOptions options)
|
||||
{
|
||||
foreach (var serverTestCvar in ServerTestCvars)
|
||||
{
|
||||
options.CVarOverrides[serverTestCvar.cvar] = serverTestCvar.value;
|
||||
}
|
||||
|
||||
if (poolSettings.DummyTicker)
|
||||
{
|
||||
options.CVarOverrides[CCVars.GameDummyTicker.Name] = "true";
|
||||
}
|
||||
|
||||
if (poolSettings.InLobby)
|
||||
{
|
||||
options.CVarOverrides[CCVars.GameLobbyEnabled.Name] = "true";
|
||||
}
|
||||
|
||||
if (poolSettings.DisableInterpolate)
|
||||
{
|
||||
options.CVarOverrides[CCVars.NetInterp.Name] = "false";
|
||||
}
|
||||
|
||||
if (poolSettings.Map != null)
|
||||
{
|
||||
options.CVarOverrides[CCVars.GameMap.Name] = poolSettings.Map;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<PairTracker> GetServerClient(PoolSettings poolSettings = null,
|
||||
[System.Runtime.CompilerServices.CallerFilePath] string testMethodFilePath = "",
|
||||
[System.Runtime.CompilerServices.CallerMemberName] string testMethodName = "") =>
|
||||
await GetServerClientPair(poolSettings ?? new PoolSettings(), $"{testMethodFilePath}, {testMethodName}");
|
||||
|
||||
private static async Task<PairTracker> GetServerClientPair(PoolSettings poolSettings, string testMethodName)
|
||||
{
|
||||
var poolRetrieveTimeWatch = new Stopwatch();
|
||||
poolRetrieveTimeWatch.Start();
|
||||
await TestContext.Out.WriteLineAsync("Getting server/client");
|
||||
Pair pair;
|
||||
if (poolSettings.MustBeNew)
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Creating, because must be new pair");
|
||||
pair = await CreateServerClientPair(poolSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = GrabOptimalPair(poolSettings);
|
||||
if (pair != null)
|
||||
{
|
||||
var canSkip = pair.Settings.CanFastRecycle(poolSettings);
|
||||
|
||||
if (!canSkip)
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Cleaning existing pair");
|
||||
await CleanPooledPair(poolSettings, pair);
|
||||
}
|
||||
else
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Skip cleanup pair");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Creating, because pool empty");
|
||||
pair = await CreateServerClientPair(poolSettings);
|
||||
}
|
||||
}
|
||||
|
||||
var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Got server/client (id:{pair.PairId},uses:{pair.TestHistory.Count}) in {poolRetrieveTime.TotalMilliseconds} ms");
|
||||
pair.Settings = poolSettings;
|
||||
|
||||
TestContext.Out.WriteLine($"Test History|\n{string.Join('\n', pair.TestHistory)}\n|Test History End");
|
||||
pair.TestHistory.Add(testMethodName);
|
||||
var usageWatch = new Stopwatch();
|
||||
usageWatch.Start();
|
||||
return new PairTracker()
|
||||
{
|
||||
Pair = pair,
|
||||
UsageWatch = usageWatch
|
||||
};
|
||||
}
|
||||
|
||||
private static Pair GrabOptimalPair(PoolSettings poolSettings)
|
||||
{
|
||||
lock (PairLock)
|
||||
{
|
||||
if (Pairs.Count == 0) return null;
|
||||
for (var i = 0; i < Pairs.Count; i++)
|
||||
{
|
||||
var pair = Pairs[i];
|
||||
if (!pair.Settings.CanFastRecycle(poolSettings)) continue;
|
||||
Pairs.RemoveAt(i);
|
||||
return pair;
|
||||
}
|
||||
var defaultPair = Pairs[^1];
|
||||
Pairs.RemoveAt(Pairs.Count - 1);
|
||||
return defaultPair;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used after checking pairs, Don't use this directly
|
||||
/// </summary>
|
||||
/// <param name="pair"></param>
|
||||
public static void NoCheckReturn(Pair pair)
|
||||
{
|
||||
lock (PairLock)
|
||||
{
|
||||
Pairs.Add(pair);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CleanPooledPair(PoolSettings poolSettings, Pair pair)
|
||||
{
|
||||
var methodWatch = new Stopwatch();
|
||||
methodWatch.Start();
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Setting CVar ");
|
||||
var configManager = pair.Server.ResolveDependency<IConfigurationManager>();
|
||||
await pair.Server.WaitPost(() =>
|
||||
{
|
||||
configManager.SetCVar(CCVars.GameLobbyEnabled, poolSettings.InLobby);
|
||||
});
|
||||
var cNetMgr = pair.Client.ResolveDependency<IClientNetManager>();
|
||||
if (!cNetMgr.IsConnected)
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Connecting client, and restarting server");
|
||||
pair.Client.SetConnectTarget(pair.Server);
|
||||
await pair.Server.WaitPost(() =>
|
||||
{
|
||||
EntitySystem.Get<GameTicker>().RestartRound();
|
||||
});
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
cNetMgr.ClientConnect(null!, 0, null!);
|
||||
});
|
||||
await ReallyBeIdle(pair,11);
|
||||
}
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Disconnecting client, and restarting server");
|
||||
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
cNetMgr.ClientDisconnect("Test pooling cleanup disconnect");
|
||||
});
|
||||
await ReallyBeIdle(pair, 5);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(pair.Settings.ExtraPrototypes))
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Removing prototypes");
|
||||
if (!pair.Settings.NoServer)
|
||||
{
|
||||
var serverProtoManager = pair.Server.ResolveDependency<IPrototypeManager>();
|
||||
await pair.Server.WaitPost(() =>
|
||||
{
|
||||
serverProtoManager.RemoveString(pair.Settings.ExtraPrototypes.Trim());
|
||||
});
|
||||
}
|
||||
if(!pair.Settings.NoClient)
|
||||
{
|
||||
var clientProtoManager = pair.Client.ResolveDependency<IPrototypeManager>();
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
clientProtoManager.RemoveString(pair.Settings.ExtraPrototypes.Trim());
|
||||
});
|
||||
}
|
||||
|
||||
await ReallyBeIdle(pair, 1);
|
||||
}
|
||||
|
||||
if (poolSettings.ExtraPrototypes != null)
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Adding prototypes");
|
||||
if (!poolSettings.NoServer)
|
||||
{
|
||||
await ConfigurePrototypes(pair.Server, poolSettings);
|
||||
}
|
||||
if (!poolSettings.NoClient)
|
||||
{
|
||||
await ConfigurePrototypes(pair.Client, poolSettings);
|
||||
}
|
||||
}
|
||||
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Restarting server again");
|
||||
await pair.Server.WaitPost(() =>
|
||||
{
|
||||
EntitySystem.Get<GameTicker>().RestartRound();
|
||||
});
|
||||
|
||||
|
||||
if (!poolSettings.NotConnected)
|
||||
{
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Connecting client");
|
||||
await ReallyBeIdle(pair);
|
||||
pair.Client.SetConnectTarget(pair.Server);
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
var netMgr = IoCManager.Resolve<IClientNetManager>();
|
||||
if (!netMgr.IsConnected)
|
||||
{
|
||||
netMgr.ClientConnect(null!, 0, null!);
|
||||
}
|
||||
});
|
||||
}
|
||||
await ReallyBeIdle(pair);
|
||||
await TestContext.Out.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Done recycling");
|
||||
}
|
||||
|
||||
private static async Task<Pair> CreateServerClientPair(PoolSettings poolSettings)
|
||||
{
|
||||
var client = await GenerateClient(poolSettings);
|
||||
var server = await GenerateServer(poolSettings);
|
||||
|
||||
var pair = new Pair { Server = server, Client = client, PairId = Interlocked.Increment(ref PairId)};
|
||||
if (!poolSettings.NotConnected)
|
||||
{
|
||||
pair.Client.SetConnectTarget(pair.Server);
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
var netMgr = IoCManager.Resolve<IClientNetManager>();
|
||||
if (!netMgr.IsConnected)
|
||||
{
|
||||
netMgr.ClientConnect(null!, 0, null!);
|
||||
}
|
||||
});
|
||||
await ReallyBeIdle(pair, 10);
|
||||
await client.WaitRunTicks(1);
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
public static async Task<TestMapData> CreateTestMap(PairTracker pairTracker)
|
||||
{
|
||||
var server = pairTracker.Pair.Server;
|
||||
var settings = pairTracker.Pair.Settings;
|
||||
if (settings.NoServer) throw new Exception("Cannot setup test map without server");
|
||||
var mapData = new TestMapData
|
||||
{
|
||||
|
||||
};
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
mapData.MapId = mapManager.CreateMap();
|
||||
mapData.MapGrid = mapManager.CreateGrid(mapData.MapId);
|
||||
mapData.GridCoords = new EntityCoordinates(mapData.MapGrid.GridEntityId, 0, 0);
|
||||
var tileDefinitionManager = IoCManager.Resolve<ITileDefinitionManager>();
|
||||
var plating = tileDefinitionManager["plating"];
|
||||
var platingTile = new Tile(plating.TileId);
|
||||
mapData.MapGrid.SetTile(mapData.GridCoords, platingTile);
|
||||
mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId);
|
||||
mapData.Tile = mapData.MapGrid.GetAllTiles().First();
|
||||
});
|
||||
if (!settings.Disconnected)
|
||||
{
|
||||
await RunTicksSync(pairTracker.Pair, 10);
|
||||
}
|
||||
|
||||
return mapData;
|
||||
}
|
||||
|
||||
public static async Task RunTicksSync(Pair pair, int ticks)
|
||||
{
|
||||
for (var i = 0; i < ticks; i++)
|
||||
{
|
||||
await pair.Server.WaitRunTicks(1);
|
||||
await pair.Client.WaitRunTicks(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task WaitUntil(RobustIntegrationTest.IntegrationInstance instance, Func<bool> func,
|
||||
int maxTicks = 600,
|
||||
int tickStep = 1)
|
||||
{
|
||||
await WaitUntil(instance, async () => await Task.FromResult(func()), maxTicks, tickStep);
|
||||
}
|
||||
|
||||
public static async Task ReallyBeIdle(Pair pair, int runTicks = 25)
|
||||
{
|
||||
for (int i = 0; i < runTicks; i++)
|
||||
{
|
||||
await pair.Client.WaitRunTicks(1);
|
||||
await pair.Server.WaitRunTicks(1);
|
||||
for (int idleCycles = 0; idleCycles < 4; idleCycles++)
|
||||
{
|
||||
await pair.Client.WaitIdleAsync();
|
||||
await pair.Server.WaitIdleAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task WaitUntil(RobustIntegrationTest.IntegrationInstance instance, Func<Task<bool>> func,
|
||||
int maxTicks = 600,
|
||||
int tickStep = 1)
|
||||
{
|
||||
var ticksAwaited = 0;
|
||||
bool passed;
|
||||
|
||||
await instance.WaitIdleAsync();
|
||||
|
||||
while (!(passed = await func()) && ticksAwaited < maxTicks)
|
||||
{
|
||||
var ticksToRun = tickStep;
|
||||
|
||||
if (ticksAwaited + tickStep > maxTicks)
|
||||
{
|
||||
ticksToRun = maxTicks - ticksAwaited;
|
||||
}
|
||||
|
||||
await instance.WaitRunTicks(ticksToRun);
|
||||
|
||||
ticksAwaited += ticksToRun;
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
{
|
||||
Assert.Fail($"Condition did not pass after {maxTicks} ticks.\n" +
|
||||
$"Tests ran ({instance.TestsRan.Count}):\n" +
|
||||
$"{string.Join('\n', instance.TestsRan)}");
|
||||
}
|
||||
|
||||
Assert.That(passed);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PoolSettings
|
||||
{
|
||||
// Todo: We can make more of these pool-able, if we need enough of them for it to matter
|
||||
public bool MustNotBeReused => Destructive || NoLoadContent || DisableInterpolate || DummyTicker;
|
||||
public bool MustBeNew => Fresh || NoLoadContent || DisableInterpolate || DummyTicker;
|
||||
|
||||
public bool NotConnected => NoClient || NoServer || Disconnected;
|
||||
/// <summary>
|
||||
/// We are going to ruin this pair
|
||||
/// </summary>
|
||||
public bool Destructive { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We need a brand new pair
|
||||
/// </summary>
|
||||
public bool Fresh { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We need a pair that uses a dummy ticker
|
||||
/// </summary>
|
||||
public bool DummyTicker { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We need the client, and server to be disconnected
|
||||
/// </summary>
|
||||
public bool Disconnected { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We need the server to be in the lobby
|
||||
/// </summary>
|
||||
public bool InLobby { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We don't want content loaded
|
||||
/// </summary>
|
||||
public bool NoLoadContent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// We want to add some prototypes
|
||||
/// </summary>
|
||||
public string ExtraPrototypes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Disables NetInterp
|
||||
/// </summary>
|
||||
public bool DisableInterpolate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Tells the pool it has to clean up before the server/client can be used.
|
||||
/// </summary>
|
||||
public bool Dirty { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the map Cvar, and loads the map
|
||||
/// </summary>
|
||||
public string Map { get; init; } // TODO for map painter
|
||||
|
||||
/// <summary>
|
||||
/// The test won't use the client (so we can skip cleaning it)
|
||||
/// </summary>
|
||||
public bool NoClient { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The test won't use the client (so we can skip cleaning it)
|
||||
/// </summary>
|
||||
public bool NoServer { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Guess if skipping recycling is ok
|
||||
/// </summary>
|
||||
/// <param name="nextSettings">The next set of settings the old pair will be set to</param>
|
||||
/// <returns></returns>
|
||||
public bool CanFastRecycle(PoolSettings nextSettings)
|
||||
{
|
||||
if (Dirty) return false;
|
||||
if (Destructive || nextSettings.Destructive) return false;
|
||||
if (NotConnected != nextSettings.NotConnected) return false;
|
||||
if (InLobby != nextSettings.InLobby) return false;
|
||||
if (DisableInterpolate != nextSettings.DisableInterpolate) return false;
|
||||
if (nextSettings.DummyTicker) return false;
|
||||
if (Map != nextSettings.Map) return false;
|
||||
if (NoLoadContent != nextSettings.NoLoadContent) return false;
|
||||
if (nextSettings.Fresh) return false;
|
||||
if (ExtraPrototypes != nextSettings.ExtraPrototypes) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TestMapData
|
||||
{
|
||||
public MapId MapId { get; set; }
|
||||
public IMapGrid MapGrid { get; set; }
|
||||
public EntityCoordinates GridCoords { get; set; }
|
||||
public MapCoordinates MapCoords { get; set; }
|
||||
public TileRef Tile { get; set; }
|
||||
}
|
||||
|
||||
public sealed class Pair
|
||||
{
|
||||
public int PairId { get; init; }
|
||||
public List<string> TestHistory { get; set; } = new();
|
||||
public PoolSettings Settings { get; set; }
|
||||
public RobustIntegrationTest.ServerIntegrationInstance Server { get; init; }
|
||||
public RobustIntegrationTest.ClientIntegrationInstance Client { get; init; }
|
||||
}
|
||||
|
||||
public sealed class PairTracker : IAsyncDisposable
|
||||
{
|
||||
private int _disposed;
|
||||
|
||||
public async Task OnDirtyDispose()
|
||||
{
|
||||
var usageTime = UsageWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Dirty: Test returned in {usageTime.TotalMilliseconds} ms");
|
||||
var dirtyWatch = new Stopwatch();
|
||||
dirtyWatch.Start();
|
||||
Pair.Client.Dispose();
|
||||
Pair.Server.Dispose();
|
||||
var disposeTime = dirtyWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Dirty: Disposed in {disposeTime.TotalMilliseconds} ms");
|
||||
}
|
||||
|
||||
public async Task OnCleanDispose()
|
||||
{
|
||||
var usageTime = UsageWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Clean: Test returned in {usageTime.TotalMilliseconds} ms");
|
||||
var cleanWatch = new Stopwatch();
|
||||
cleanWatch.Start();
|
||||
// Let any last minute failures the test cause happen.
|
||||
await PoolManager.ReallyBeIdle(Pair);
|
||||
if (!Pair.Settings.Destructive)
|
||||
{
|
||||
if (Pair.Client.IsAlive == false)
|
||||
{
|
||||
throw new Exception("Test killed the client", Pair.Client.UnhandledException);
|
||||
}
|
||||
|
||||
if (Pair.Server.IsAlive == false)
|
||||
{
|
||||
throw new Exception("Test killed the server", Pair.Server.UnhandledException);
|
||||
}
|
||||
}
|
||||
|
||||
if (Pair.Settings.MustNotBeReused)
|
||||
{
|
||||
Pair.Client.Dispose();
|
||||
Pair.Server.Dispose();
|
||||
var returnTime2 = cleanWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Clean: Clean disposed in {returnTime2.TotalMilliseconds} ms");
|
||||
return;
|
||||
}
|
||||
|
||||
var sRuntimeLog = Pair.Server.ResolveDependency<IRuntimeLog>();
|
||||
if (sRuntimeLog.ExceptionCount > 0) throw new Exception("Server logged exceptions");
|
||||
var cRuntimeLog = Pair.Client.ResolveDependency<IRuntimeLog>();
|
||||
if (cRuntimeLog.ExceptionCount > 0) throw new Exception("Client logged exceptions");
|
||||
PoolManager.NoCheckReturn(Pair);
|
||||
var returnTime = cleanWatch.Elapsed;
|
||||
await TestContext.Out.WriteLineAsync($"Clean: Clean returned to pool in {returnTime.TotalMilliseconds} ms");
|
||||
}
|
||||
public Stopwatch UsageWatch { get; set; }
|
||||
public Pair Pair { get; init; }
|
||||
|
||||
public async ValueTask CleanReturnAsync()
|
||||
{
|
||||
var disposed = Interlocked.Exchange(ref _disposed, 1);
|
||||
switch (disposed)
|
||||
{
|
||||
case 0:
|
||||
await TestContext.Out.WriteLineAsync("Clean Return Start");
|
||||
break;
|
||||
case 1:
|
||||
throw new Exception("Already called clean return before");
|
||||
case 2:
|
||||
throw new Exception("Already dirty disposed");
|
||||
default:
|
||||
throw new Exception("Unexpected disposed value");
|
||||
}
|
||||
|
||||
await OnCleanDispose();
|
||||
await TestContext.Out.WriteLineAsync($"Clean Return Exiting");
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
var disposed = Interlocked.Exchange(ref _disposed, 2);
|
||||
switch (disposed)
|
||||
{
|
||||
case 0:
|
||||
await TestContext.Out.WriteLineAsync("Dirty Return Start");
|
||||
break;
|
||||
case 1:
|
||||
await TestContext.Out.WriteLineAsync("Dirty Return - Already Clean Disposed");
|
||||
return;
|
||||
case 2:
|
||||
throw new Exception("Already called dirty return before");
|
||||
default:
|
||||
throw new Exception("Unexpected disposed value");
|
||||
}
|
||||
|
||||
await OnDirtyDispose();
|
||||
await TestContext.Out.WriteLineAsync($"Dirty Return Exiting");
|
||||
}
|
||||
}
|
||||
15
Content.IntegrationTests/PoolManagerTestEventHandler.cs
Normal file
15
Content.IntegrationTests/PoolManagerTestEventHandler.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
[assembly: Parallelizable(ParallelScope.Children)]
|
||||
|
||||
namespace Content.IntegrationTests;
|
||||
|
||||
[SetUpFixture]
|
||||
public sealed class PoolManagerTestEventHandler
|
||||
{
|
||||
[OneTimeTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
PoolManager.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,13 @@ namespace Content.IntegrationTests.Tests.AI
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(BehaviorSetPrototype))]
|
||||
public sealed class BehaviorSetsTest : ContentIntegrationTest
|
||||
public sealed class BehaviorSetsTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestBehaviorSets()
|
||||
{
|
||||
var server = StartServer();
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var reflectionManager = server.ResolveDependency<IReflectionManager>();
|
||||
@@ -56,6 +56,7 @@ namespace Content.IntegrationTests.Tests.AI
|
||||
}
|
||||
}
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AccessReaderComponent))]
|
||||
public sealed class AccessReaderTest : ContentIntegrationTest
|
||||
public sealed class AccessReaderTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestTags()
|
||||
{
|
||||
var server = StartServer();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var system = EntitySystem.Get<AccessReaderSystem>();
|
||||
@@ -69,6 +71,7 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
Assert.That(system.IsAllowed(new[] { "A", "B" }, reader), Is.False);
|
||||
Assert.That(system.IsAllowed(new string[] { }, reader), Is.False);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ using System.Threading.Tasks;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Commands;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Database;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
@@ -17,38 +19,31 @@ namespace Content.IntegrationTests.Tests.Administration.Logs;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AdminLogSystem))]
|
||||
public sealed class AddTests : ContentIntegrationTest
|
||||
public sealed class AddTests
|
||||
{
|
||||
[Test]
|
||||
public async Task AddAndGetSingleLog()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
Pool = true
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var sMaps = server.ResolveDependency<IMapManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var coordinates = GetMainEntityCoordinates(sMaps);
|
||||
var entity = sEntities.SpawnEntity(null, coordinates);
|
||||
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{entity:Entity} test log: {guid}");
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = sAdminLogSystem.CurrentRoundJson(new LogFilter
|
||||
{
|
||||
@@ -69,20 +64,15 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AddAndGetUnformattedLog()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
Pool = true
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sDatabase = server.ResolveDependency<IServerDbManager>();
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
@@ -94,9 +84,10 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var coordinates = GetMainEntityCoordinates(sMaps);
|
||||
var entity = sEntities.SpawnEntity(null, coordinates);
|
||||
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{entity} test log: {guid}");
|
||||
@@ -104,7 +95,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
SharedAdminLog log = default;
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter
|
||||
{
|
||||
@@ -136,31 +127,26 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
json.Dispose();
|
||||
}
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(500)]
|
||||
public async Task BulkAddLogs(int amount)
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
Pool = true
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var sMaps = server.ResolveDependency<IMapManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var coordinates = GetMainEntityCoordinates(sMaps);
|
||||
var entity = sEntities.SpawnEntity(null, coordinates);
|
||||
|
||||
for (var i = 0; i < amount; i++)
|
||||
@@ -169,26 +155,20 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
}
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var messages = await sAdminLogSystem.CurrentRoundLogs();
|
||||
return messages.Count >= amount;
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AddPlayerSessionLog()
|
||||
{
|
||||
var (client, server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
Pool = true
|
||||
});
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sPlayers = server.ResolveDependency<IPlayerManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
@@ -207,7 +187,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
});
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = await sAdminLogSystem.CurrentRoundLogs();
|
||||
if (logs.Count == 0)
|
||||
@@ -218,20 +198,22 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
Assert.That(logs.First().Players, Does.Contain(playerGuid));
|
||||
return true;
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PreRoundAddAndGetSingle()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{Dirty = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var configManager = server.ResolveDependency<IConfigurationManager>();
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0",
|
||||
[CCVars.GameLobbyEnabled.Name] = "true"
|
||||
},
|
||||
configManager.SetCVar(CCVars.GameLobbyEnabled, true);
|
||||
var command = new RestartRoundNowCommand();
|
||||
command.Execute(null, string.Empty, Array.Empty<string>());
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
var sDatabase = server.ResolveDependency<IServerDbManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
@@ -253,7 +235,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
SharedAdminLog log = default;
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter
|
||||
{
|
||||
@@ -284,20 +266,14 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
|
||||
json.Dispose();
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DuplicatePlayerDoesNotThrowTest()
|
||||
{
|
||||
var (client, server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
});
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sPlayers = server.ResolveDependency<IPlayerManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
@@ -313,7 +289,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{player} {player} test log: {guid}");
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter
|
||||
{
|
||||
@@ -328,24 +304,17 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
return true;
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DuplicatePlayerIdDoesNotThrowTest()
|
||||
{
|
||||
var (client, server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
});
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sPlayers = server.ResolveDependency<IPlayerManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
|
||||
|
||||
@@ -358,7 +327,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{player:first} {player:second} test log: {guid}");
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter
|
||||
{
|
||||
@@ -373,6 +342,7 @@ public sealed class AddTests : ContentIntegrationTest
|
||||
return true;
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,36 +12,28 @@ namespace Content.IntegrationTests.Tests.Administration.Logs;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AdminLogSystem))]
|
||||
public sealed class FilterTests : ContentIntegrationTest
|
||||
public sealed class FilterTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase(DateOrder.Ascending)]
|
||||
[TestCase(DateOrder.Descending)]
|
||||
public async Task Date(DateOrder order)
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
},
|
||||
Pool = true
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var sMaps = server.ResolveDependency<IMapManager>();
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
|
||||
|
||||
var commonGuid = Guid.NewGuid();
|
||||
var firstGuid = Guid.NewGuid();
|
||||
var secondGuid = Guid.NewGuid();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var coordinates = GetMainEntityCoordinates(sMaps);
|
||||
var entity = sEntities.SpawnEntity(null, coordinates);
|
||||
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{entity:Entity} test log: {commonGuid} {firstGuid}");
|
||||
@@ -51,13 +43,12 @@ public sealed class FilterTests : ContentIntegrationTest
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var coordinates = GetMainEntityCoordinates(sMaps);
|
||||
var entity = sEntities.SpawnEntity(null, coordinates);
|
||||
|
||||
sAdminLogSystem.Add(LogType.Unknown, $"{entity:Entity} test log: {commonGuid} {secondGuid}");
|
||||
});
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
var commonGuidStr = commonGuid.ToString();
|
||||
|
||||
@@ -110,5 +101,6 @@ public sealed class FilterTests : ContentIntegrationTest
|
||||
|
||||
return firstFound && secondFound;
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,21 +14,13 @@ namespace Content.IntegrationTests.Tests.Administration.Logs;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AdminLogSystem))]
|
||||
public sealed class QueryTests : ContentIntegrationTest
|
||||
public sealed class QueryTests
|
||||
{
|
||||
[Test]
|
||||
public async Task QuerySingleLog()
|
||||
{
|
||||
var serverOptions = new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.AdminLogsQueueSendDelay.Name] = "0"
|
||||
}
|
||||
};
|
||||
var (client, server) = await StartConnectedServerClientPair(serverOptions: serverOptions);
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sSystems = server.ResolveDependency<IEntitySystemManager>();
|
||||
var sPlayers = server.ResolveDependency<IPlayerManager>();
|
||||
@@ -57,7 +49,7 @@ public sealed class QueryTests : ContentIntegrationTest
|
||||
AnyPlayers = new[] {player.UserId.UserId}
|
||||
};
|
||||
|
||||
await WaitUntil(server, async () =>
|
||||
await PoolManager.WaitUntil(server, async () =>
|
||||
{
|
||||
foreach (var _ in await sAdminLogSystem.All(filter))
|
||||
{
|
||||
@@ -66,5 +58,7 @@ public sealed class QueryTests : ContentIntegrationTest
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AtmosAlarmThreshold))]
|
||||
public sealed class AlarmThresholdTest : ContentIntegrationTest
|
||||
public sealed class AlarmThresholdTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: alarmThreshold
|
||||
@@ -21,12 +21,8 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
[Test]
|
||||
public async Task TestAlarmThreshold()
|
||||
{
|
||||
var server = StartServerDummyTicker(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
AtmosAlarmThreshold threshold = default!;
|
||||
@@ -91,6 +87,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
Assert.That(threshold.UpperBound, Is.EqualTo(null));
|
||||
Assert.That(threshold.LowerBound, Is.EqualTo(null));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,13 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(Atmospherics))]
|
||||
public sealed class ConstantsTest : ContentIntegrationTest
|
||||
public sealed class ConstantsTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TotalGasesTest()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
@@ -27,6 +26,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
|
||||
Assert.That(Enum.GetValues(typeof(Gas)).Length, Is.EqualTo(Atmospherics.TotalNumberOfGases));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,17 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(GasMixture))]
|
||||
public sealed class GasMixtureTest : ContentIntegrationTest
|
||||
public sealed class GasMixtureTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestMerge()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var atmosphereSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AtmosphereSystem>();
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var a = new GasMixture(10f);
|
||||
var b = new GasMixture(10f);
|
||||
@@ -48,7 +47,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
Assert.That(a.GetMoles(Gas.Oxygen), Is.EqualTo(50));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -60,9 +59,10 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
[TestCase(Atmospherics.BreathPercentage)]
|
||||
public async Task RemoveRatio(float ratio)
|
||||
{
|
||||
var server = StartServer();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var a = new GasMixture(10f);
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
Assert.That(a.GetMoles(Gas.Nitrogen), Is.EqualTo(100 - b.GetMoles(Gas.Nitrogen)));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
[TestFixture]
|
||||
[TestOf(typeof(SharedBodyComponent))]
|
||||
[TestOf(typeof(BodyComponent))]
|
||||
public sealed class LegTest : ContentIntegrationTest
|
||||
public sealed class LegTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -32,8 +32,8 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
[Test]
|
||||
public async Task RemoveLegsFallTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
AppearanceComponent appearance = null;
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
Assert.That(appearance.TryGetData(RotationVisuals.RotationState, out RotationState state));
|
||||
Assert.That(state, Is.EqualTo(RotationState.Horizontal));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(LungSystem))]
|
||||
public sealed class LungTest : ContentIntegrationTest
|
||||
public sealed class LungTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -49,8 +49,8 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
public async Task AirConsistencyTest()
|
||||
{
|
||||
// --- Setup
|
||||
var options = new ServerContentIntegrationOption{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
@@ -121,16 +121,14 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
});
|
||||
}
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task NoSuffocationTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapLoader = server.ResolveDependency<IMapLoader>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
@@ -173,7 +171,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
});
|
||||
}
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
[TestFixture]
|
||||
[TestOf(typeof(BuckleComponent))]
|
||||
[TestOf(typeof(StrapComponent))]
|
||||
public sealed class BuckleTest : ContentIntegrationTest
|
||||
public sealed class BuckleTest
|
||||
{
|
||||
private const string BuckleDummyId = "BuckleDummy";
|
||||
private const string StrapDummyId = "StrapDummy";
|
||||
@@ -51,9 +51,11 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
[Test]
|
||||
public async Task BuckleUnbuckleCooldownRangeTest()
|
||||
{
|
||||
var cOptions = new ClientIntegrationOptions {ExtraPrototypes = Prototypes};
|
||||
var sOptions = new ServerIntegrationOptions {ExtraPrototypes = Prototypes};
|
||||
var (_, server) = await StartConnectedServerClientPair(cOptions, sOptions);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid human = default;
|
||||
EntityUid chair = default;
|
||||
@@ -68,9 +70,6 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
var actionBlocker = EntitySystem.Get<ActionBlockerSystem>();
|
||||
var standingState = EntitySystem.Get<StandingStateSystem>();
|
||||
|
||||
var grid = GetMainGrid(mapManager);
|
||||
var coordinates = new EntityCoordinates(grid.GridEntityId, 0, 0);
|
||||
|
||||
human = entityManager.SpawnEntity(BuckleDummyId, coordinates);
|
||||
chair = entityManager.SpawnEntity(StrapDummyId, coordinates);
|
||||
|
||||
@@ -209,13 +208,18 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.Null(buckle.BuckledTo);
|
||||
Assert.IsEmpty(strap.BuckledEntities);
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task BuckledDyingDropItemsTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption {ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid human = default;
|
||||
BuckleComponent buckle = null;
|
||||
@@ -226,12 +230,8 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
var grid = GetMainGrid(mapManager);
|
||||
var coordinates = new EntityCoordinates(grid.GridEntityId, 0, 0);
|
||||
|
||||
human = entityManager.SpawnEntity(BuckleDummyId, coordinates);
|
||||
var chair = entityManager.SpawnEntity(StrapDummyId, coordinates);
|
||||
|
||||
@@ -292,16 +292,18 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
|
||||
buckle.TryUnbuckle(human, true);
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ForceUnbuckleBuckleTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid human = default;
|
||||
EntityUid chair = default;
|
||||
@@ -312,9 +314,6 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
var grid = GetMainGrid(mapManager);
|
||||
var coordinates = new EntityCoordinates(grid.GridEntityId, 0, 0);
|
||||
|
||||
human = entityManager.SpawnEntity(BuckleDummyId, coordinates);
|
||||
chair = entityManager.SpawnEntity(StrapDummyId, coordinates);
|
||||
|
||||
@@ -331,7 +330,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
entityManager.GetComponent<TransformComponent>(human).WorldPosition += (100, 0);
|
||||
});
|
||||
|
||||
await WaitUntil(server, () => !buckle.Buckled, 10);
|
||||
await PoolManager.WaitUntil(server, () => !buckle.Buckled, 10);
|
||||
|
||||
Assert.False(buckle.Buckled);
|
||||
|
||||
@@ -356,6 +355,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.NotNull(buckle.BuckledTo);
|
||||
Assert.True(buckle.Buckled);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
Content.IntegrationTests/Tests/CargoTest.cs
Normal file
39
Content.IntegrationTests/Tests/CargoTest.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Cargo.Systems;
|
||||
using Content.Shared.Cargo.Prototypes;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class CargoTest
|
||||
{
|
||||
[Test]
|
||||
public async Task NoArbitrage()
|
||||
{
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings() {NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var entManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var pricing = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<PricingSystem>();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var mapId = mapManager.CreateMap();
|
||||
|
||||
foreach (var proto in protoManager.EnumeratePrototypes<CargoProductPrototype>())
|
||||
{
|
||||
var ent = entManager.SpawnEntity(proto.Product, new MapCoordinates(Vector2.Zero, mapId));
|
||||
var price = pricing.GetPrice(ent);
|
||||
|
||||
Assert.That(price, Is.LessThan(proto.PointCost), $"Found arbitrage on {proto.ID} cargo product!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Chemistry;
|
||||
// reactions can change this assumption
|
||||
[TestFixture]
|
||||
[TestOf(typeof(SolutionContainerSystem))]
|
||||
public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
public sealed class SolutionSystemTests
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -25,22 +25,19 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
beaker:
|
||||
maxVol: 50
|
||||
";
|
||||
|
||||
[Test]
|
||||
public async Task TryAddTwoNonReactiveReagent()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid beaker;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var oilQuantity = FixedPoint2.New(15);
|
||||
var waterQuantity = FixedPoint2.New(10);
|
||||
@@ -62,7 +59,7 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
Assert.That(oil, Is.EqualTo(oilQuantity));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
// This test mimics current behavior
|
||||
@@ -70,18 +67,17 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
[Test]
|
||||
public async Task TryAddTooMuchNonReactiveReagent()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid beaker;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var oilQuantity = FixedPoint2.New(1500);
|
||||
var waterQuantity = FixedPoint2.New(10);
|
||||
@@ -103,25 +99,24 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
Assert.That(oil, Is.EqualTo(FixedPoint2.Zero));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
// Unlike TryAddSolution this adds and two solution without then splits leaving only threshold in original
|
||||
[Test]
|
||||
public async Task TryMixAndOverflowTooMuchReagent()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid beaker;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
int ratio = 9;
|
||||
int threshold = 20;
|
||||
@@ -152,25 +147,23 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
// TryMixAndOverflow will fail if Threshold larger than MaxVolume
|
||||
[Test]
|
||||
public async Task TryMixAndOverflowTooBigOverflow()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
EntityUid beaker;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
int ratio = 9;
|
||||
int threshold = 60;
|
||||
@@ -190,6 +183,6 @@ public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||
Is.False);
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(ReactionPrototype))]
|
||||
public sealed class TryAllReactionsTest : ContentIntegrationTest
|
||||
public sealed class TryAllReactionsTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -24,19 +24,16 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
||||
solutions:
|
||||
beaker:
|
||||
maxVol: 50";
|
||||
|
||||
[Test]
|
||||
public async Task TryAllTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes<ReactionPrototype>())
|
||||
{
|
||||
@@ -46,7 +43,7 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
||||
EntityUid beaker;
|
||||
Solution component = null;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
beaker = entityManager.SpawnEntity("TestSolutionContainer", coordinates);
|
||||
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||
@@ -63,7 +60,7 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
//you just got linq'd fool
|
||||
//(i'm sorry)
|
||||
@@ -78,8 +75,9 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
||||
|
||||
Assert.That(foundProductsMap.All(x => x.Value));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,37 +4,20 @@ using Content.Client.Clickable;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class ClickableTest : ContentIntegrationTest
|
||||
public sealed class ClickableTest
|
||||
{
|
||||
private ClientIntegrationInstance _client;
|
||||
private ServerIntegrationInstance _server;
|
||||
|
||||
private const double DirSouth = 0;
|
||||
private const double DirNorth = Math.PI;
|
||||
private const double DirEast = Math.PI / 2;
|
||||
private const double DirSouthEast = Math.PI / 4;
|
||||
private const double DirSouthEastJustShy = Math.PI / 4 - 0.1;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public async Task Setup()
|
||||
{
|
||||
(_client, _server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption()
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CVars.NetPVS.Name] = "false"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Parallelizable(ParallelScope.None)]
|
||||
[Test]
|
||||
[TestCase("ClickTestRotatingCornerVisible", 0.25f, 0.25f, DirSouth, 1, ExpectedResult = true)]
|
||||
[TestCase("ClickTestRotatingCornerVisible", 0.35f, 0.5f, DirSouth, 2, ExpectedResult = true)]
|
||||
@@ -64,26 +47,29 @@ namespace Content.IntegrationTests.Tests
|
||||
[TestCase("ClickTestRotatingCornerInvisibleNoRot", 0.25f, 0.25f, DirSouthEastJustShy, 1, ExpectedResult = true)]
|
||||
public async Task<bool> Test(string prototype, float clickPosX, float clickPosY, double angle, float scale)
|
||||
{
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
var client = pairTracker.Pair.Client;
|
||||
EntityUid entity = default;
|
||||
var clientEntManager = _client.ResolveDependency<IEntityManager>();
|
||||
var serverEntManager = _server.ResolveDependency<IEntityManager>();
|
||||
var eyeManager = _client.ResolveDependency<IEyeManager>();
|
||||
var mapManager = _server.ResolveDependency<IMapManager>();
|
||||
var clientEntManager = client.ResolveDependency<IEntityManager>();
|
||||
var serverEntManager = server.ResolveDependency<IEntityManager>();
|
||||
var eyeManager = client.ResolveDependency<IEyeManager>();
|
||||
|
||||
await _server.WaitPost(() =>
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var ent = serverEntManager.SpawnEntity(prototype, GetMainEntityCoordinates(mapManager));
|
||||
var ent = serverEntManager.SpawnEntity(prototype, testMap.GridCoords);
|
||||
serverEntManager.GetComponent<TransformComponent>(ent).WorldRotation = angle;
|
||||
serverEntManager.GetComponent<SpriteComponent>(ent).Scale = (scale, scale);
|
||||
entity = ent;
|
||||
});
|
||||
|
||||
// Let client sync up.
|
||||
await RunTicksSync(_client, _server, 5);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
var hit = false;
|
||||
|
||||
await _client.WaitPost(() =>
|
||||
await client.WaitPost(() =>
|
||||
{
|
||||
// these tests currently all assume player eye is 0
|
||||
eyeManager.CurrentEye.Rotation = 0;
|
||||
@@ -94,11 +80,13 @@ namespace Content.IntegrationTests.Tests
|
||||
hit = clickable.CheckClick((clickPosX, clickPosY) + pos, out _, out _);
|
||||
});
|
||||
|
||||
await _server.WaitPost(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
serverEntManager.DeleteEntity(entity);
|
||||
});
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
|
||||
return hit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,15 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(PardonCommand))]
|
||||
public sealed class PardonCommand : ContentIntegrationTest
|
||||
public sealed class PardonCommand
|
||||
{
|
||||
private static readonly TimeSpan MarginOfError = TimeSpan.FromMinutes(1);
|
||||
|
||||
[Test]
|
||||
public async Task PardonTest()
|
||||
{
|
||||
var (client, server) = await StartConnectedServerClientPair();
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new (){Destructive = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sPlayerManager = server.ResolveDependency<IPlayerManager>();
|
||||
var sConsole = server.ResolveDependency<IServerConsoleHost>();
|
||||
@@ -122,6 +121,7 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
// The list is still returned since that ignores pardons
|
||||
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(RejuvenateCommand))]
|
||||
public sealed class RejuvenateTest : ContentIntegrationTest
|
||||
public sealed class RejuvenateTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -33,8 +33,8 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
[Test]
|
||||
public async Task RejuvenateDeadTest()
|
||||
{
|
||||
var options = new ServerIntegrationOptions{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
@@ -78,6 +78,7 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
|
||||
Assert.That(damageable.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,33 +12,27 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(RestartRoundNowCommand))]
|
||||
public sealed class RestartRoundNowTest : ContentIntegrationTest
|
||||
public sealed class RestartRoundNowTest
|
||||
{
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public async Task RestartRoundAfterStart(bool lobbyEnabled)
|
||||
{
|
||||
var (_, server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
[CCVars.GameMap.Name] = "saltern"
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings(){Dirty = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var configManager = server.ResolveDependency<IConfigurationManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
var gameTicker = entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||
|
||||
await server.WaitRunTicks(30);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
GameTick tickBeforeRestart = default;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.That(configManager.GetCVar<bool>(CCVars.GameLobbyEnabled), Is.EqualTo(false));
|
||||
configManager.SetCVar(CCVars.GameLobbyEnabled, lobbyEnabled);
|
||||
|
||||
Assert.That(gameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
|
||||
@@ -54,17 +48,17 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await server.WaitRunTicks(5);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 15);
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var tickAfterRestart = entityManager.CurrentTick;
|
||||
|
||||
Assert.That(tickBeforeRestart < tickAfterRestart);
|
||||
});
|
||||
|
||||
await server.WaitRunTicks(60);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.IntegrationTests.Tests.Construction
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class ConstructionActionValid : ContentIntegrationTest
|
||||
public sealed class ConstructionActionValid
|
||||
{
|
||||
private bool IsValid(IGraphAction action, IPrototypeManager protoMan, out string prototype)
|
||||
{
|
||||
@@ -49,9 +49,8 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
[Test]
|
||||
public async Task ConstructionGraphSpawnPrototypeValid()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -82,6 +81,7 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
}
|
||||
}
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
|
||||
Assert.That(valid, Is.True, $"One or more SpawnPrototype actions specified invalid entity prototypes!\n{message}");
|
||||
}
|
||||
@@ -89,9 +89,8 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
[Test]
|
||||
public async Task ConstructionGraphNodeEntityPrototypeValid()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -108,6 +107,7 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
message.Append($"Invalid entity prototype \"{node.Entity}\" on node \"{node.Name}\" of graph \"{graph.ID}\"\n");
|
||||
}
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
|
||||
Assert.That(valid, Is.True, $"One or more nodes specified invalid entity prototypes!\n{message}");
|
||||
}
|
||||
@@ -115,9 +115,8 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
[Test]
|
||||
public async Task ConstructionGraphEdgeValid()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -139,6 +138,7 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
}
|
||||
|
||||
Assert.That(valid, Is.True, $"One or more edges specified invalid node targets!\n{message}");
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.IntegrationTests.Tests.Construction
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class ConstructionPrototypeTest : ContentIntegrationTest
|
||||
public sealed class ConstructionPrototypeTest
|
||||
{
|
||||
// discount linter for construction graphs
|
||||
// TODO: Create serialization validators for these?
|
||||
@@ -14,9 +14,8 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
[Test]
|
||||
public async Task TestStartIsValid()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -27,14 +26,14 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
|
||||
Assert.That(graph.Nodes.ContainsKey(start), $"Found no startNode \"{start}\" on graph \"{graph.ID}\" for construction prototype \"{proto.ID}\"!");
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestTargetIsValid()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -45,14 +44,14 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
|
||||
Assert.That(graph.Nodes.ContainsKey(target), $"Found no targetNode \"{target}\" on graph \"{graph.ID}\" for construction prototype \"{proto.ID}\"!");
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestStartReachesValidTarget()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
|
||||
@@ -68,6 +67,7 @@ namespace Content.IntegrationTests.Tests.Construction
|
||||
Assert.That(protoMan.TryIndex(next.Entity, out EntityPrototype entity), $"The next node ({next.Name}) in the path from the start node ({start}) to the target node ({target}) specified an invalid entity prototype ({next.Entity})");
|
||||
Assert.That(entity.Components.ContainsKey("Construction"), $"The next node ({next.Name}) in the path from the start node ({start}) to the target node ({target}) specified an entity prototype ({next.Entity}) without a ConstructionComponent.");
|
||||
}
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ using System.Threading.Tasks;
|
||||
using Content.Server.Storage.Components;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
@@ -12,9 +10,9 @@ using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
public sealed class ContainerOcclusionTest : ContentIntegrationTest
|
||||
public sealed class ContainerOcclusionTest
|
||||
{
|
||||
private const string ExtraPrototypes = @"
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
id: ContainerOcclusionA
|
||||
components:
|
||||
@@ -35,53 +33,21 @@ namespace Content.IntegrationTests.Tests
|
||||
- type: PointLight
|
||||
";
|
||||
|
||||
private async Task<(ClientIntegrationInstance c, ServerIntegrationInstance s)> Start()
|
||||
{
|
||||
var optsServer = new ServerIntegrationOptions
|
||||
{
|
||||
CVarOverrides =
|
||||
{
|
||||
{CVars.NetPVS.Name, "false"}
|
||||
},
|
||||
ExtraPrototypes = ExtraPrototypes
|
||||
};
|
||||
var optsClient = new ClientIntegrationOptions
|
||||
{
|
||||
|
||||
CVarOverrides =
|
||||
{
|
||||
{CVars.NetPVS.Name, "false"}
|
||||
},
|
||||
ExtraPrototypes = ExtraPrototypes
|
||||
};
|
||||
|
||||
var (c, s) = await StartConnectedServerDummyTickerClientPair(optsClient, optsServer);
|
||||
|
||||
s.Post(() =>
|
||||
{
|
||||
IoCManager.Resolve<IPlayerManager>().ServerSessions.Single().JoinGame();
|
||||
|
||||
var mapMan = IoCManager.Resolve<IMapManager>();
|
||||
|
||||
mapMan.CreateMap(new MapId(1));
|
||||
});
|
||||
|
||||
return (c, s);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestA()
|
||||
{
|
||||
var (c, s) = await Start();
|
||||
|
||||
await c.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{ExtraPrototypes = Prototypes});
|
||||
var s = pairTracker.Pair.Server;
|
||||
var c = pairTracker.Pair.Client;
|
||||
|
||||
var cEntities = c.ResolveDependency<IEntityManager>();
|
||||
|
||||
EntityUid dummy = default;
|
||||
s.Post(() =>
|
||||
var ent2 = s.ResolveDependency<IMapManager>();
|
||||
await s.WaitPost(() =>
|
||||
{
|
||||
var pos = new MapCoordinates(Vector2.Zero, new MapId(1));
|
||||
var mapId = ent2.GetAllMapIds().Last();
|
||||
var pos = new MapCoordinates(Vector2.Zero, mapId);
|
||||
var ent = IoCManager.Resolve<IEntityManager>();
|
||||
var container = ent.SpawnEntity("ContainerOcclusionA", pos);
|
||||
dummy = ent.SpawnEntity("ContainerOcclusionDummy", pos);
|
||||
@@ -89,9 +55,9 @@ namespace Content.IntegrationTests.Tests
|
||||
ent.GetComponent<EntityStorageComponent>(container).Insert(dummy);
|
||||
});
|
||||
|
||||
await RunTicksSync(c, s, 5);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
c.Assert(() =>
|
||||
await c.WaitAssertion(() =>
|
||||
{
|
||||
var sprite = cEntities.GetComponent<SpriteComponent>(dummy);
|
||||
var light = cEntities.GetComponent<PointLightComponent>(dummy);
|
||||
@@ -99,22 +65,24 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.True(light.ContainerOccluded);
|
||||
});
|
||||
|
||||
await Task.WhenAll(c.WaitIdleAsync(), s.WaitIdleAsync());
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestB()
|
||||
{
|
||||
var (c, s) = await Start();
|
||||
|
||||
await c.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{ExtraPrototypes = Prototypes});
|
||||
var s = pairTracker.Pair.Server;
|
||||
var c = pairTracker.Pair.Client;
|
||||
|
||||
var cEntities = c.ResolveDependency<IEntityManager>();
|
||||
var ent2 = s.ResolveDependency<IMapManager>();
|
||||
|
||||
EntityUid dummy = default;
|
||||
s.Post(() =>
|
||||
await s.WaitPost(() =>
|
||||
{
|
||||
var pos = new MapCoordinates(Vector2.Zero, new MapId(1));
|
||||
var mapId = ent2.GetAllMapIds().Last();
|
||||
var pos = new MapCoordinates(Vector2.Zero, mapId);
|
||||
var ent = IoCManager.Resolve<IEntityManager>();
|
||||
var container = ent.SpawnEntity("ContainerOcclusionB", pos);
|
||||
dummy = ent.SpawnEntity("ContainerOcclusionDummy", pos);
|
||||
@@ -122,9 +90,9 @@ namespace Content.IntegrationTests.Tests
|
||||
ent.GetComponent<EntityStorageComponent>(container).Insert(dummy);
|
||||
});
|
||||
|
||||
await RunTicksSync(c, s, 5);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
c.Assert(() =>
|
||||
await c.WaitAssertion(() =>
|
||||
{
|
||||
var sprite = cEntities.GetComponent<SpriteComponent>(dummy);
|
||||
var light = cEntities.GetComponent<PointLightComponent>(dummy);
|
||||
@@ -132,22 +100,24 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.False(light.ContainerOccluded);
|
||||
});
|
||||
|
||||
await Task.WhenAll(c.WaitIdleAsync(), s.WaitIdleAsync());
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestAb()
|
||||
{
|
||||
var (c, s) = await Start();
|
||||
|
||||
await c.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{ExtraPrototypes = Prototypes});
|
||||
var s = pairTracker.Pair.Server;
|
||||
var c = pairTracker.Pair.Client;
|
||||
|
||||
var ent2 = s.ResolveDependency<IMapManager>();
|
||||
var cEntities = c.ResolveDependency<IEntityManager>();
|
||||
|
||||
EntityUid dummy = default;
|
||||
s.Post(() =>
|
||||
await s.WaitPost(() =>
|
||||
{
|
||||
var pos = new MapCoordinates(Vector2.Zero, new MapId(1));
|
||||
var mapId = ent2.GetAllMapIds().Last();
|
||||
var pos = new MapCoordinates(Vector2.Zero, mapId);
|
||||
var ent = IoCManager.Resolve<IEntityManager>();
|
||||
var containerA = ent.SpawnEntity("ContainerOcclusionA", pos);
|
||||
var containerB = ent.SpawnEntity("ContainerOcclusionB", pos);
|
||||
@@ -157,9 +127,9 @@ namespace Content.IntegrationTests.Tests
|
||||
ent.GetComponent<EntityStorageComponent>(containerB).Insert(dummy);
|
||||
});
|
||||
|
||||
await RunTicksSync(c, s, 5);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
c.Assert(() =>
|
||||
await c.WaitAssertion(() =>
|
||||
{
|
||||
var sprite = cEntities.GetComponent<SpriteComponent>(dummy);
|
||||
var light = cEntities.GetComponent<PointLightComponent>(dummy);
|
||||
@@ -167,7 +137,7 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.True(light.ContainerOccluded);
|
||||
});
|
||||
|
||||
await Task.WhenAll(c.WaitIdleAsync(), s.WaitIdleAsync());
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Content.IntegrationTests.Tests.Damageable;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DamageSpecifier))]
|
||||
public sealed class DamageSpecifierTest : ContentIntegrationTest
|
||||
public sealed class DamageSpecifierTest
|
||||
{
|
||||
[Test]
|
||||
public void TestDamageSpecifierOperations()
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DamageableComponent))]
|
||||
[TestOf(typeof(DamageableSystem))]
|
||||
public sealed class DamageableTest : ContentIntegrationTest
|
||||
public sealed class DamageableTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
public const string Prototypes = @"
|
||||
# Define some damage groups
|
||||
- type: damageType
|
||||
id: TestDamage1
|
||||
@@ -71,30 +71,17 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
damageContainer: testDamageContainer
|
||||
";
|
||||
|
||||
// public bool & function to determine whether dealing damage resulted in actual damage change
|
||||
public bool DamageChanged = false;
|
||||
public void DamageChangedListener(EntityUid _, DamageableComponent comp, DamageChangedEvent args)
|
||||
{
|
||||
DamageChanged = true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestDamageableComponents()
|
||||
{
|
||||
var server = StartServerDummyTicker(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
sEntityManager.EventBus.SubscribeLocalEvent<DamageableComponent, DamageChangedEvent>(DamageChangedListener);
|
||||
|
||||
EntityUid sDamageableEntity = default;
|
||||
DamageableComponent sDamageableComponent = null;
|
||||
DamageableSystem sDamageableSystem = null;
|
||||
@@ -153,8 +140,7 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
DamageSpecifier damage = new(group3, damageToDeal);
|
||||
|
||||
sDamageableSystem.TryChangeDamage(uid, damage, true);
|
||||
Assert.That(DamageChanged);
|
||||
DamageChanged = false;
|
||||
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
|
||||
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal));
|
||||
foreach (var type in types)
|
||||
@@ -165,8 +151,7 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
|
||||
// Heal
|
||||
sDamageableSystem.TryChangeDamage(uid, -damage);
|
||||
Assert.That(DamageChanged);
|
||||
DamageChanged = false;
|
||||
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero));
|
||||
foreach (var type in types)
|
||||
@@ -180,8 +165,7 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
damageToDeal = FixedPoint2.New(types.Count() * 5 - 1);
|
||||
damage = new DamageSpecifier(group3, damageToDeal);
|
||||
sDamageableSystem.TryChangeDamage(uid, damage, true);
|
||||
Assert.That(DamageChanged);
|
||||
DamageChanged = false;
|
||||
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
|
||||
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal));
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(damageToDeal / types.Count()));
|
||||
@@ -192,8 +176,6 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
|
||||
// Heal
|
||||
sDamageableSystem.TryChangeDamage(uid, -damage);
|
||||
Assert.That(DamageChanged);
|
||||
DamageChanged = false;
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero));
|
||||
foreach (var type in types)
|
||||
@@ -206,7 +188,6 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
damage = new DamageSpecifier(group1, FixedPoint2.New(10)) + new DamageSpecifier(type2b, FixedPoint2.New(10));
|
||||
sDamageableSystem.TryChangeDamage(uid, damage, true);
|
||||
Assert.That(DamageChanged, Is.False);
|
||||
Assert.That(sDamageableComponent.DamagePerGroup.TryGetValue(group1.ID, out groupDamage), Is.False);
|
||||
Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type1.ID, out typeDamage), Is.False);
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
@@ -227,15 +208,13 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
|
||||
// Test Over-Healing
|
||||
sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, FixedPoint2.New(-100)));
|
||||
Assert.That(DamageChanged);
|
||||
DamageChanged = false;
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
|
||||
// Test that if no health change occurred, returns false
|
||||
sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, -100));
|
||||
Assert.That(DamageChanged, Is.False);
|
||||
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@ using Robust.Shared.Map;
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class DeleteInventoryTest : ContentIntegrationTest
|
||||
public sealed class DeleteInventoryTest
|
||||
{
|
||||
// Test that when deleting an entity with an InventoryComponent,
|
||||
// any equipped items also get deleted.
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var server = StartServer();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
@@ -46,6 +47,7 @@ namespace Content.IntegrationTests.Tests
|
||||
// Assert that child item was also deleted.
|
||||
Assert.That(item.Deleted, Is.True);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,20 +15,17 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DamageGroupTrigger))]
|
||||
[TestOf(typeof(AndTrigger))]
|
||||
public sealed class DestructibleDamageGroupTest : ContentIntegrationTest
|
||||
public sealed class DestructibleDamageGroupTest
|
||||
{
|
||||
[Test]
|
||||
public async Task AndTest()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
@@ -39,8 +36,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var gridId = GetMainGrid(sMapManager).GridEntityId;
|
||||
var coordinates = new EntityCoordinates(gridId, 0, 0);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDamageGroupEntityId, coordinates);
|
||||
sDamageableComponent = IoCManager.Resolve<IEntityManager>().GetComponent<DamageableComponent>(sDestructibleEntity);
|
||||
@@ -184,6 +180,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
// No new thresholds reached as triggers once is set to true and it already triggered before
|
||||
Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,20 +14,17 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DamageTypeTrigger))]
|
||||
[TestOf(typeof(AndTrigger))]
|
||||
public sealed class DestructibleDamageTypeTest : ContentIntegrationTest
|
||||
public sealed class DestructibleDamageTypeTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
EntityUid sDestructibleEntity = default;
|
||||
@@ -37,8 +34,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var gridId = GetMainGrid(sMapManager).GridEntityId;
|
||||
var coordinates = new EntityCoordinates(gridId, 0, 0);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDamageTypeEntityId, coordinates);
|
||||
sDamageableComponent = IoCManager.Resolve<IEntityManager>().GetComponent<DamageableComponent>(sDestructibleEntity);
|
||||
@@ -180,6 +176,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
// No new thresholds reached as triggers once is set to true and it already triggered before
|
||||
Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,20 +13,17 @@ using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototy
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Destructible
|
||||
{
|
||||
public sealed class DestructibleDestructionTest : ContentIntegrationTest
|
||||
public sealed class DestructibleDestructionTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
@@ -35,8 +32,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var gridId = GetMainGrid(sMapManager).GridEntityId;
|
||||
var coordinates = new EntityCoordinates(gridId, 0, 0);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
|
||||
sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem<TestDestructibleListenerSystem>();
|
||||
@@ -87,6 +83,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
Assert.That(found, Is.True);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,23 +19,20 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DestructibleComponent))]
|
||||
[TestOf(typeof(DamageThreshold))]
|
||||
public sealed class DestructibleThresholdActivationTest : ContentIntegrationTest
|
||||
public sealed class DestructibleThresholdActivationTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
EntityUid sDestructibleEntity = default;
|
||||
DamageableComponent sDamageableComponent = null;
|
||||
DestructibleComponent sDestructibleComponent = null;
|
||||
@@ -44,8 +41,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var gridId = GetMainGrid(sMapManager).GridEntityId;
|
||||
var coordinates = new EntityCoordinates(gridId, 0, 0);
|
||||
var coordinates = testMap.GridCoords;
|
||||
|
||||
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleEntityId, coordinates);
|
||||
sDamageableComponent = IoCManager.Resolve<IEntityManager>().GetComponent<DamageableComponent>(sDestructibleEntity);
|
||||
@@ -268,6 +264,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
// They shouldn't have been triggered by changing TriggersOnce
|
||||
Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
[TestOf(typeof(DeviceNetworkComponent))]
|
||||
[TestOf(typeof(WiredNetworkComponent))]
|
||||
[TestOf(typeof(WirelessNetworkComponent))]
|
||||
public sealed class DeviceNetworkTest : ContentIntegrationTest
|
||||
public sealed class DeviceNetworkTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -50,17 +50,8 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
[Test]
|
||||
public async Task NetworkDeviceSendAndReceive()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes,
|
||||
ContentBeforeIoC = () => {
|
||||
IoCManager.Resolve<IEntitySystemManager>().LoadExtraSystemType<DeviceNetworkTestSystem>();
|
||||
}
|
||||
};
|
||||
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -81,7 +72,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
["testbool"] = true
|
||||
};
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
mapManager.CreateNewMapEntity(MapId.Nullspace);
|
||||
|
||||
device1 = entityManager.SpawnEntity("DummyNetworkDevice", MapCoordinates.Nullspace);
|
||||
@@ -104,25 +95,17 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
CollectionAssert.AreEquivalent(deviceNetTestSystem.LastPayload, payload);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task WirelessNetworkDeviceSendAndReceive()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes,
|
||||
ContentBeforeIoC = () => {
|
||||
IoCManager.Resolve<IEntitySystemManager>().LoadExtraSystemType<DeviceNetworkTestSystem>();
|
||||
}
|
||||
};
|
||||
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -144,7 +127,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
["testbool"] = true
|
||||
};
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
mapManager.CreateNewMapEntity(MapId.Nullspace);
|
||||
|
||||
device1 = entityManager.SpawnEntity("DummyWirelessNetworkDevice", MapCoordinates.Nullspace);
|
||||
@@ -168,7 +151,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
CollectionAssert.AreEqual(deviceNetTestSystem.LastPayload, payload);
|
||||
|
||||
payload = new NetworkPayload
|
||||
@@ -184,27 +167,18 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
CollectionAssert.AreNotEqual(deviceNetTestSystem.LastPayload, payload);
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task WiredNetworkDeviceSendAndReceive()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes,
|
||||
ContentBeforeIoC = () => {
|
||||
IoCManager.Resolve<IEntitySystemManager>().LoadExtraSystemType<DeviceNetworkTestSystem>();
|
||||
}
|
||||
};
|
||||
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -230,7 +204,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
var map = mapManager.CreateNewMapEntity(MapId.Nullspace);
|
||||
grid = mapManager.CreateGrid(MapId.Nullspace);
|
||||
|
||||
@@ -255,7 +229,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
//CollectionAssert.AreNotEqual(deviceNetTestSystem.LastPayload, payload);
|
||||
|
||||
entityManager.SpawnEntity("CableApcExtension", grid.MapToGrid(new MapCoordinates(new Robust.Shared.Maths.Vector2(0, 1), MapId.Nullspace)));
|
||||
@@ -266,11 +240,11 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork
|
||||
await server.WaitRunTicks(1);
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() => {
|
||||
await server.WaitAssertion(() => {
|
||||
CollectionAssert.AreEqual(deviceNetTestSystem.LastPayload, payload);
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Content.IntegrationTests.Tests.Disposal
|
||||
[TestOf(typeof(DisposalHolderComponent))]
|
||||
[TestOf(typeof(DisposalEntryComponent))]
|
||||
[TestOf(typeof(DisposalUnitComponent))]
|
||||
public sealed class DisposalUnitTest : ContentIntegrationTest
|
||||
public sealed class DisposalUnitTest
|
||||
{
|
||||
[Reflect(false)]
|
||||
private sealed class DisposalUnitTestSystem : EntitySystem
|
||||
@@ -127,9 +127,10 @@ namespace Content.IntegrationTests.Tests.Disposal
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var options = new ServerIntegrationOptions { ExtraPrototypes = Prototypes };
|
||||
var server = StartServer(options);
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
EntityUid human = default!;
|
||||
EntityUid wrench = default!;
|
||||
@@ -137,13 +138,12 @@ namespace Content.IntegrationTests.Tests.Disposal
|
||||
EntityUid disposalTrunk = default!;
|
||||
DisposalUnitComponent unit = default!;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
// Spawn the entities
|
||||
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||
var coordinates = testMap.GridCoords;
|
||||
human = entityManager.SpawnEntity("HumanDummy", coordinates);
|
||||
wrench = entityManager.SpawnEntity("WrenchDummy", coordinates);
|
||||
disposalUnit = entityManager.SpawnEntity("DisposalUnitDummy", coordinates);
|
||||
@@ -208,6 +208,7 @@ namespace Content.IntegrationTests.Tests.Disposal
|
||||
// Re-pressurizing
|
||||
Flush(unit, false);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Content.IntegrationTests.Tests.DoAfter
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DoAfterComponent))]
|
||||
public sealed class DoAfterServerTest : ContentIntegrationTest
|
||||
public sealed class DoAfterServerTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -25,11 +25,11 @@ namespace Content.IntegrationTests.Tests.DoAfter
|
||||
public async Task TestFinished()
|
||||
{
|
||||
Task<DoAfterStatus> task = null;
|
||||
var options = new ServerIntegrationOptions{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
// That it finishes successfully
|
||||
server.Post(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var tickTime = 1.0f / IoCManager.Resolve<IGameTiming>().TickRate;
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
@@ -43,16 +43,19 @@ namespace Content.IntegrationTests.Tests.DoAfter
|
||||
|
||||
await server.WaitRunTicks(1);
|
||||
Assert.That(task.Result == DoAfterStatus.Finished);
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestCancelled()
|
||||
{
|
||||
Task<DoAfterStatus> task = null;
|
||||
var options = new ServerIntegrationOptions{ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
|
||||
server.Post(() =>
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var tickTime = 1.0f / IoCManager.Resolve<IGameTiming>().TickRate;
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
@@ -67,6 +70,8 @@ namespace Content.IntegrationTests.Tests.DoAfter
|
||||
|
||||
await server.WaitRunTicks(3);
|
||||
Assert.That(task.Result == DoAfterStatus.Cancelled, $"Result was {task.Result}");
|
||||
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(AirlockComponent))]
|
||||
public sealed class AirlockTest : ContentIntegrationTest
|
||||
public sealed class AirlockTest
|
||||
{
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -48,10 +48,8 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
[Test]
|
||||
public async Task OpenCloseDestroyTest()
|
||||
{
|
||||
var options = new ServerIntegrationOptions {ExtraPrototypes = Prototypes};
|
||||
var server = StartServer(options);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -59,7 +57,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
EntityUid airlock = default;
|
||||
DoorComponent doorComponent = null;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
mapManager.CreateNewMapEntity(MapId.Nullspace);
|
||||
|
||||
@@ -71,7 +69,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
EntitySystem.Get<DoorSystem>().StartOpening(airlock);
|
||||
Assert.That(doorComponent.State, Is.EqualTo(DoorState.Opening));
|
||||
@@ -79,21 +77,21 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
await WaitUntil(server, () => doorComponent.State == DoorState.Open);
|
||||
await PoolManager.WaitUntil(server, () => doorComponent.State == DoorState.Open);
|
||||
|
||||
Assert.That(doorComponent.State, Is.EqualTo(DoorState.Open));
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
EntitySystem.Get<DoorSystem>().TryClose((EntityUid) airlock);
|
||||
Assert.That(doorComponent.State, Is.EqualTo(DoorState.Closing));
|
||||
});
|
||||
|
||||
await WaitUntil(server, () => doorComponent.State == DoorState.Closed);
|
||||
await PoolManager.WaitUntil(server, () => doorComponent.State == DoorState.Closed);
|
||||
|
||||
Assert.That(doorComponent.State, Is.EqualTo(DoorState.Closed));
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
@@ -103,17 +101,14 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
|
||||
server.RunTicks(5);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AirlockBlockTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
};
|
||||
var server = StartServer(options);
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
@@ -127,7 +122,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
|
||||
var physicsDummyStartingX = -1;
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var mapId = mapManager.CreateMap();
|
||||
|
||||
@@ -151,7 +146,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
for (var i = 0; i < 240; i += 10)
|
||||
{
|
||||
// Keep the airlock awake so they collide
|
||||
server.Post(() => entityManager.GetComponent<IPhysBody>(airlock).WakeBody());
|
||||
await server.WaitPost(() => entityManager.GetComponent<IPhysBody>(airlock).WakeBody());
|
||||
|
||||
await server.WaitRunTicks(10);
|
||||
await server.WaitIdleAsync();
|
||||
@@ -165,6 +160,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
|
||||
// Blocked by the airlock
|
||||
await server.WaitAssertion(() => Assert.That(Math.Abs(entityManager.GetComponent<TransformComponent>(physicsDummy).MapPosition.X - 1) > 0.01f));
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,17 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class DummyIconTest : ContentIntegrationTest
|
||||
public sealed class DummyIconTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Test()
|
||||
{
|
||||
var (client, _) = await StartConnectedServerClientPair(new ClientContentIntegrationOption(){ Pool = false }, new ServerContentIntegrationOption() { Pool = false });
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var client = pairTracker.Pair.Client;
|
||||
|
||||
var prototypeManager = client.ResolveDependency<IPrototypeManager>();
|
||||
var resourceCache = client.ResolveDependency<IResourceCache>();
|
||||
|
||||
await client.WaitRunTicks(5);
|
||||
await client.WaitAssertion(() =>
|
||||
{
|
||||
foreach (var proto in prototypeManager.EnumeratePrototypes<EntityPrototype>())
|
||||
@@ -32,6 +33,8 @@ namespace Content.IntegrationTests.Tests
|
||||
proto.ID);
|
||||
}
|
||||
});
|
||||
await client.WaitRunTicks(5);
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,13 @@ namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(EntityUid))]
|
||||
public sealed class EntityTest : ContentIntegrationTest
|
||||
public sealed class EntityTest
|
||||
{
|
||||
[Test]
|
||||
public async Task SpawnTest()
|
||||
{
|
||||
var options = new ServerContentIntegrationOption()
|
||||
{
|
||||
CVarOverrides = {{CCVars.NPCMaxUpdates.Name, int.MaxValue.ToString()}}
|
||||
};
|
||||
|
||||
var server = StartServer(options);
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Dirty = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityMan = server.ResolveDependency<IEntityManager>();
|
||||
@@ -38,7 +33,7 @@ namespace Content.IntegrationTests.Tests
|
||||
EntityUid testEntity;
|
||||
|
||||
//Build up test environment
|
||||
server.Post(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
// Create a one tile grid to stave off the grid 0 monsters
|
||||
var mapId = mapManager.CreateMap();
|
||||
@@ -56,7 +51,9 @@ namespace Content.IntegrationTests.Tests
|
||||
mapManager.DoMapInitialize(mapId);
|
||||
});
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitRunTicks(5);
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var testLocation = grid.ToCoordinates();
|
||||
|
||||
@@ -80,7 +77,7 @@ namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
Logger.LogS(LogLevel.Debug, "EntityTest", $"Testing: {prototype.ID}");
|
||||
testEntity = entityMan.SpawnEntity(prototype.ID, testLocation);
|
||||
server.RunTicks(2);
|
||||
server.RunTicks(1);
|
||||
if(!entityMan.Deleted(testEntity))
|
||||
entityMan.DeleteEntity(testEntity);
|
||||
}, "Entity '{0}' threw an exception.",
|
||||
@@ -89,7 +86,7 @@ namespace Content.IntegrationTests.Tests
|
||||
});
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -110,12 +107,8 @@ namespace Content.IntegrationTests.Tests
|
||||
- type: entity
|
||||
id: AllComponentsOneToOneDeleteTestEntity";
|
||||
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = testEntity,
|
||||
FailureLogLevel = LogLevel.Error
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = testEntity});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -124,7 +117,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
IMapGrid grid = default;
|
||||
|
||||
server.Post(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
// Create a one tile grid to stave off the grid 0 monsters
|
||||
var mapId = mapManager.CreateMap();
|
||||
@@ -142,7 +135,9 @@ namespace Content.IntegrationTests.Tests
|
||||
mapManager.DoMapInitialize(mapId);
|
||||
});
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitRunTicks(5);
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -179,14 +174,12 @@ namespace Content.IntegrationTests.Tests
|
||||
}, "Component '{0}' threw an exception.",
|
||||
component.Name);
|
||||
|
||||
server.RunTicks(2);
|
||||
|
||||
entityManager.DeleteEntity(entity);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -207,13 +200,8 @@ namespace Content.IntegrationTests.Tests
|
||||
- type: entity
|
||||
id: AllComponentsOneEntityDeleteTestEntity";
|
||||
|
||||
var server = StartServer(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = testEntity,
|
||||
FailureLogLevel = LogLevel.Error,
|
||||
Pool = false
|
||||
});
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = testEntity});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -222,7 +210,7 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
IMapGrid grid = default;
|
||||
|
||||
server.Post(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
// Create a one tile grid to stave off the grid 0 monsters
|
||||
var mapId = mapManager.CreateMap();
|
||||
@@ -237,6 +225,7 @@ namespace Content.IntegrationTests.Tests
|
||||
grid.SetTile(Vector2i.Zero, tile);
|
||||
mapManager.DoMapInitialize(mapId);
|
||||
});
|
||||
await server.WaitRunTicks(5);
|
||||
|
||||
var distinctComponents = new List<(List<CompIdx> components, List<CompIdx> references)>
|
||||
{
|
||||
@@ -272,7 +261,7 @@ namespace Content.IntegrationTests.Tests
|
||||
// Sanity check
|
||||
Assert.That(distinctComponents, Is.Not.Empty);
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -313,14 +302,12 @@ namespace Content.IntegrationTests.Tests
|
||||
}, "Component '{0}' threw an exception.",
|
||||
component.Name);
|
||||
}
|
||||
|
||||
server.RunTicks(2);
|
||||
entityManager.DeleteEntity(entity);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Fluids;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(FluidSpreaderSystem))]
|
||||
public sealed class FluidSpill : ContentIntegrationTest
|
||||
public sealed class FluidSpill
|
||||
{
|
||||
private static PuddleComponent? GetPuddle(IEntityManager entityManager, IMapGrid mapGrid, Vector2i pos)
|
||||
{
|
||||
@@ -46,9 +46,8 @@ public sealed class FluidSpill : ContentIntegrationTest
|
||||
[Test]
|
||||
public async Task SpillEvenlyTest()
|
||||
{
|
||||
// --- Setup
|
||||
var server = StartServer();
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -85,7 +84,7 @@ public sealed class FluidSpill : ContentIntegrationTest
|
||||
var sTimeToWait = (int) Math.Ceiling(2f * gameTiming.TickRate);
|
||||
await server.WaitRunTicks(sTimeToWait);
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var grid = mapManager.GetGrid(gridId);
|
||||
var puddle = GetPuddle(entityManager, grid, _origin);
|
||||
@@ -102,16 +101,15 @@ public sealed class FluidSpill : ContentIntegrationTest
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task SpillSmallOverflowTest()
|
||||
{
|
||||
// --- Setup
|
||||
var server = StartServer();
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||
@@ -147,9 +145,9 @@ public sealed class FluidSpill : ContentIntegrationTest
|
||||
});
|
||||
|
||||
var sTimeToWait = (int) Math.Ceiling(2f * gameTiming.TickRate);
|
||||
await server.WaitRunTicks(sTimeToWait);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, sTimeToWait);
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var grid = mapManager.GetGrid(gridId);
|
||||
var puddle = GetPuddle(entityManager, grid, _origin);
|
||||
@@ -178,6 +176,6 @@ public sealed class FluidSpill : ContentIntegrationTest
|
||||
Assert.That(fullField, Is.EqualTo(1));
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,50 +14,52 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(PuddleComponent))]
|
||||
public sealed class PuddleTest : ContentIntegrationTest
|
||||
public sealed class PuddleTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TilePuddleTest()
|
||||
{
|
||||
var server = StartServer();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
var spillSystem = entitySystemManager.GetEntitySystem<SpillableSystem>();
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var solution = new Solution("Water", FixedPoint2.New(20));
|
||||
var grid = GetMainGrid(mapManager);
|
||||
var (x, y) = GetMainTile(grid).GridIndices;
|
||||
var coordinates = new EntityCoordinates(grid.GridEntityId, x, y);
|
||||
var tile = testMap.Tile;
|
||||
var gridUid = tile.GridUid;
|
||||
var (x, y) = tile.GridIndices;
|
||||
var coordinates = new EntityCoordinates(gridUid, x, y);
|
||||
var puddle = spillSystem.SpillAt(solution, coordinates, "PuddleSmear");
|
||||
|
||||
Assert.NotNull(puddle);
|
||||
});
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task SpaceNoPuddleTest()
|
||||
{
|
||||
var server = StartServer();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||
var spillSystem = entitySystemManager.GetEntitySystem<SpillableSystem>();
|
||||
|
||||
IMapGrid grid = null;
|
||||
|
||||
// Remove all tiles
|
||||
server.Post(() =>
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
grid = GetMainGrid(mapManager);
|
||||
grid = testMap.MapGrid;
|
||||
|
||||
foreach (var tile in grid.GetAllTiles())
|
||||
{
|
||||
@@ -65,9 +67,9 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, 5);
|
||||
|
||||
server.Assert(() =>
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var coordinates = grid.ToCoordinates();
|
||||
var solution = new Solution("Water", FixedPoint2.New(20));
|
||||
@@ -75,15 +77,14 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
Assert.Null(puddle);
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PuddlePauseTest()
|
||||
{
|
||||
var server = StartServer();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
var sTileDefinitionManager = server.ResolveDependency<ITileDefinitionManager>();
|
||||
@@ -154,8 +155,8 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
});
|
||||
|
||||
// Wait enough time for it to evaporate if it was unpaused
|
||||
var sTimeToWait = (5 + (int)Math.Ceiling(amount * evaporateTime * sGameTiming.TickRate));
|
||||
await server.WaitRunTicks(sTimeToWait);
|
||||
var sTimeToWait = 5 + (int)Math.Ceiling(amount * evaporateTime * sGameTiming.TickRate);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, sTimeToWait);
|
||||
|
||||
// No evaporation due to being paused
|
||||
await server.WaitAssertion(() =>
|
||||
@@ -181,7 +182,7 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
});
|
||||
|
||||
// Wait enough time for it to evaporate
|
||||
await server.WaitRunTicks(sTimeToWait);
|
||||
await PoolManager.RunTicksSync(pairTracker.Pair, sTimeToWait);
|
||||
|
||||
// Puddle evaporation should have ticked
|
||||
await server.WaitAssertion(() =>
|
||||
@@ -189,6 +190,7 @@ namespace Content.IntegrationTests.Tests.Fluids
|
||||
// Check that puddle has been deleted
|
||||
Assert.True(puddle.Deleted);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user