Merge remote-tracking branch 'upstream/master' into ed-05-08-2024-upstream

# Conflicts:
#	Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs
This commit is contained in:
Ed
2024-08-08 12:29:20 +03:00
155 changed files with 17151 additions and 15001 deletions

View File

@@ -1,4 +1,5 @@
using Content.Server.Popups;
using Content.Shared.Abilities.Mime;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;
using Content.Shared.Alert;
@@ -29,6 +30,9 @@ namespace Content.Server.Abilities.Mime
base.Initialize();
SubscribeLocalEvent<MimePowersComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<MimePowersComponent, InvisibleWallActionEvent>(OnInvisibleWall);
SubscribeLocalEvent<MimePowersComponent, BreakVowAlertEvent>(OnBreakVowAlert);
SubscribeLocalEvent<MimePowersComponent, RetakeVowAlertEvent>(OnRetakeVowAlert);
}
public override void Update(float frameTime)
@@ -99,6 +103,22 @@ namespace Content.Server.Abilities.Mime
args.Handled = true;
}
private void OnBreakVowAlert(Entity<MimePowersComponent> ent, ref BreakVowAlertEvent args)
{
if (args.Handled)
return;
BreakVow(ent, ent);
args.Handled = true;
}
private void OnRetakeVowAlert(Entity<MimePowersComponent> ent, ref RetakeVowAlertEvent args)
{
if (args.Handled)
return;
RetakeVow(ent, ent);
args.Handled = true;
}
/// <summary>
/// Break this mime's vow to not speak.
/// </summary>

View File

@@ -16,6 +16,7 @@ public sealed partial class AdminLogManager
// TODO ADMIN LOGS make this thread safe or remove thread safety from the main partial class
private readonly Dictionary<int, List<SharedAdminLog>> _roundsLogCache = new(MaxRoundsCached);
private readonly Queue<int> _roundsLogCacheQueue = new();
private static readonly Gauge CacheRoundCount = Metrics.CreateGauge(
"admin_logs_cache_round_count",
@@ -28,19 +29,21 @@ public sealed partial class AdminLogManager
// TODO ADMIN LOGS cache previous {MaxRoundsCached} rounds on startup
public void CacheNewRound()
{
List<SharedAdminLog> list;
var oldestRound = _currentRoundId - MaxRoundsCached;
List<SharedAdminLog>? list = null;
if (_roundsLogCache.Remove(oldestRound, out var oldestList))
_roundsLogCacheQueue.Enqueue(_currentRoundId);
if (_roundsLogCacheQueue.Count > MaxRoundsCached)
{
list = oldestList;
list.Clear();
}
else
{
list = new List<SharedAdminLog>(LogListInitialSize);
var oldestRound = _roundsLogCacheQueue.Dequeue();
if (_roundsLogCache.Remove(oldestRound, out var oldestList))
{
list = oldestList;
list.Clear();
}
}
list ??= new List<SharedAdminLog>(LogListInitialSize);
_roundsLogCache.Add(_currentRoundId, list);
CacheRoundCount.Set(_roundsLogCache.Count);
}

View File

@@ -1,22 +0,0 @@
using Content.Shared.Alert;
using Content.Server.Abilities.Mime;
namespace Content.Server.Alert.Click
{
///<summary>
/// Break your mime vows
///</summary>
[DataDefinition]
public sealed partial class BreakVow : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
if (entManager.TryGetComponent(player, out MimePowersComponent? mimePowers))
{
entManager.System<MimePowersSystem>().BreakVow(player, mimePowers);
}
}
}
}

View File

@@ -1,21 +0,0 @@
using Content.Server.Cuffs;
using Content.Shared.Alert;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Try to remove handcuffs from yourself
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class RemoveCuffs : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
var cuffableSys = entityManager.System<CuffableSystem>();
cuffableSys.TryUncuff(player, player);
}
}
}

View File

@@ -1,28 +0,0 @@
using Content.Server.Ensnaring;
using Content.Shared.Alert;
using Content.Shared.Ensnaring.Components;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click;
[UsedImplicitly]
[DataDefinition]
public sealed partial class RemoveEnsnare : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
if (entManager.TryGetComponent(player, out EnsnareableComponent? ensnareableComponent))
{
foreach (var ensnare in ensnareableComponent.Container.ContainedEntities)
{
if (!entManager.TryGetComponent(ensnare, out EnsnaringComponent? ensnaringComponent))
return;
entManager.EntitySysManager.GetEntitySystem<EnsnareableSystem>().TryFree(player, player, ensnare, ensnaringComponent);
// Only one snare at a time.
break;
}
}
}
}

View File

@@ -1,25 +0,0 @@
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Alert;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Resist fire
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class ResistFire : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
if (entManager.TryGetComponent(player, out FlammableComponent? flammable))
{
entManager.System<FlammableSystem>().Resist(player, flammable);
}
}
}
}

View File

@@ -1,22 +0,0 @@
using Content.Shared.Alert;
using Content.Server.Abilities.Mime;
namespace Content.Server.Alert.Click
{
///<summary>
/// Retake your mime vows
///</summary>
[DataDefinition]
public sealed partial class RetakeVow : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
if (entManager.TryGetComponent(player, out MimePowersComponent? mimePowers))
{
entManager.System<MimePowersSystem>().RetakeVow(player, mimePowers);
}
}
}
}

View File

@@ -1,29 +0,0 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Alert;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Stop pulling something
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class StopBeingPulled : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!entityManager.System<ActionBlockerSystem>().CanInteract(player, null))
return;
if (entityManager.TryGetComponent(player, out PullableComponent? playerPullable))
{
entityManager.System<PullingSystem>().TryStopPull(player, playerPullable, user: player);
}
}
}
}

View File

@@ -1,26 +0,0 @@
using Content.Server.Shuttles.Systems;
using Content.Shared.Alert;
using Content.Shared.Shuttles.Components;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Stop piloting shuttle
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class StopPiloting : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
if (entManager.TryGetComponent(player, out PilotComponent? pilotComponent)
&& pilotComponent.Console != null)
{
entManager.System<ShuttleConsoleSystem>().RemovePilot(player, pilotComponent);
}
}
}
}

View File

@@ -1,27 +0,0 @@
using Content.Shared.Alert;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Stop pulling something
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class StopPulling : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var entManager = IoCManager.Resolve<IEntityManager>();
var ps = entManager.System<PullingSystem>();
if (entManager.TryGetComponent(player, out PullerComponent? puller) &&
entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp))
{
ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player);
}
}
}
}

View File

@@ -1,19 +0,0 @@
using Content.Server.Body.Systems;
using Content.Shared.Alert;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click;
/// <summary>
/// Attempts to toggle the internals for a particular entity
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class ToggleInternals : IAlertClick
{
public void AlertClicked(EntityUid player)
{
var internalsSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InternalsSystem>();
internalsSystem.ToggleInternals(player, player, false);
}
}

View File

@@ -1,19 +0,0 @@
using Content.Shared.Alert;
using Content.Shared.Buckle;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Unbuckles if player is currently buckled.
/// </summary>
[UsedImplicitly]
[DataDefinition]
public sealed partial class Unbuckle : IAlertClick
{
public void AlertClicked(EntityUid player)
{
IoCManager.Resolve<IEntityManager>().System<SharedBuckleSystem>().TryUnbuckle(player, player);
}
}
}

View File

@@ -13,11 +13,15 @@ using Content.Server.Roles.Jobs;
using Content.Server.Shuttles.Components;
using Content.Server.Station.Systems;
using Content.Shared.Antag;
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
using Content.Shared.GameTicking.Components;
using Content.Shared.Ghost;
using Content.Shared.Humanoid;
using Content.Shared.Mind;
using Content.Shared.Players;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Content.Shared.Whitelist;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
@@ -25,6 +29,7 @@ using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -35,10 +40,13 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IServerPreferencesManager _pref = default!;
[Dependency] private readonly ActorSystem _actors = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
[Dependency] private readonly JobSystem _jobs = default!;
[Dependency] private readonly LoadoutSystem _loadout = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
[Dependency] private readonly TransformSystem _transform = default!;
@@ -224,7 +232,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
for (var i = 0; i < count; i++)
{
var session = (ICommonSession?) null;
var session = (ICommonSession?)null;
if (picking)
{
if (!playerPool.TryPickAndTake(RobustRandom, out session) && noSpawner)
@@ -324,17 +332,29 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
// The following is where we apply components, equipment, and other changes to our antagonist entity.
EntityManager.AddComponents(player, def.Components);
_stationSpawning.EquipStartingGear(player, def.StartingGear);
// Equip the entity's RoleLoadout and LoadoutGroup
List<ProtoId<StartingGearPrototype>>? gear = new();
if (def.StartingGear is not null)
gear.Add(def.StartingGear.Value);
_loadout.Equip(player, gear, def.RoleLoadout);
if (session != null)
{
var curMind = _mind.CreateMind(session.UserId, Name(antagEnt.Value));
_mind.SetUserId(curMind, session.UserId);
_mind.TransferTo(curMind, antagEnt, ghostCheckOverride: true);
_role.MindAddRoles(curMind, def.MindComponents, null, true);
ent.Comp.SelectedMinds.Add((curMind, Name(player)));
var curMind = session.GetMind();
if (curMind == null ||
!TryComp<MindComponent>(curMind.Value, out var mindComp) ||
mindComp.OwnedEntity != antagEnt)
{
curMind = _mind.CreateMind(session.UserId, Name(antagEnt.Value));
_mind.SetUserId(curMind.Value, session.UserId);
}
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
SendBriefing(session, def.Briefing);
}
@@ -447,7 +467,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
private void OnObjectivesTextGetInfo(Entity<AntagSelectionComponent> ent, ref ObjectivesTextGetInfoEvent args)
{
if (ent.Comp.AgentName is not {} name)
if (ent.Comp.AgentName is not { } name)
return;
args.Minds = ent.Comp.SelectedMinds;

View File

@@ -1,6 +1,7 @@
using Content.Server.Administration.Systems;
using Content.Shared.Antag;
using Content.Shared.Destructible.Thresholds;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Content.Shared.Storage;
using Content.Shared.Whitelist;
@@ -154,6 +155,12 @@ public partial struct AntagSelectionDefinition()
[DataField]
public ProtoId<StartingGearPrototype>? StartingGear;
/// <summary>
/// A list of role loadouts, from which a randomly selected one will be equipped.
/// </summary>
[DataField]
public List<ProtoId<RoleLoadoutPrototype>>? RoleLoadout;
/// <summary>
/// A briefing shown to the player.
/// </summary>

View File

@@ -237,7 +237,7 @@ namespace Content.Server.Atmos.EntitySystems
// TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs.
if (throwTarget != EntityCoordinates.Invalid)
{
var pos = ((throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition).Normalized() + dirVec).Normalized();
var pos = ((_transformSystem.ToMapCoordinates(throwTarget).Position - _transformSystem.GetWorldPosition(xform)).Normalized() + dirVec).Normalized();
_physics.ApplyLinearImpulse(uid, pos * moveForce, body: physics);
}
else

View File

@@ -73,6 +73,7 @@ namespace Content.Server.Atmos.EntitySystems
SubscribeLocalEvent<FlammableComponent, IsHotEvent>(OnIsHot);
SubscribeLocalEvent<FlammableComponent, TileFireEvent>(OnTileFire);
SubscribeLocalEvent<FlammableComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<FlammableComponent, ResistFireAlertEvent>(OnResistFireAlert);
SubscribeLocalEvent<IgniteOnCollideComponent, StartCollideEvent>(IgniteOnCollide);
SubscribeLocalEvent<IgniteOnCollideComponent, LandEvent>(OnIgniteLand);
@@ -251,6 +252,15 @@ namespace Content.Server.Atmos.EntitySystems
Extinguish(uid, component);
}
private void OnResistFireAlert(Entity<FlammableComponent> ent, ref ResistFireAlertEvent args)
{
if (args.Handled)
return;
Resist(ent, ent);
args.Handled = true;
}
public void UpdateAppearance(EntityUid uid, FlammableComponent? flammable = null, AppearanceComponent? appearance = null)
{
if (!Resolve(uid, ref flammable, ref appearance))

View File

@@ -0,0 +1,90 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Atmos.Piping.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
namespace Content.Server.Atmos.EntitySystems;
[UsedImplicitly]
public sealed class GasMinerSystem : SharedGasMinerSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
}
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
{
var miner = ent.Comp;
var oldState = miner.MinerState;
float toSpawn;
if (!GetValidEnvironment(ent, out var environment) || !Transform(ent).Anchored)
{
miner.MinerState = GasMinerState.Disabled;
}
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
else if ((toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment)) == 0)
{
miner.MinerState = GasMinerState.Idle;
}
else
{
miner.MinerState = GasMinerState.Working;
// Time to mine some gas.
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
merger.SetMoles(miner.SpawnGas, toSpawn);
_atmosphereSystem.Merge(environment, merger);
}
if (miner.MinerState != oldState)
{
Dirty(ent);
}
}
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
{
var (uid, miner) = ent;
var transform = Transform(uid);
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
// Treat space as an invalid environment
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
{
environment = null;
return false;
}
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
return environment != null;
}
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
{
var (uid, miner) = ent;
// How many moles could we theoretically spawn. Cap by pressure and amount.
var allowableMoles = Math.Min(
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
miner.MaxExternalAmount - environment.TotalMoles);
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
if (toSpawnReal < Atmospherics.GasMinMoles) {
return 0f;
}
return toSpawnReal;
}
}

View File

@@ -1,43 +0,0 @@
using Content.Shared.Atmos;
namespace Content.Server.Atmos.Piping.Other.Components
{
[RegisterComponent]
public sealed partial class GasMinerComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
public bool Enabled { get; set; } = true;
[ViewVariables(VVAccess.ReadOnly)]
public bool Idle { get; set; } = false;
/// <summary>
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxExternalAmount")]
public float MaxExternalAmount { get; set; } = float.PositiveInfinity;
/// <summary>
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxExternalPressure")]
public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnGas")]
public Gas? SpawnGas { get; set; } = null;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnTemperature")]
public float SpawnTemperature { get; set; } = Atmospherics.T20C;
/// <summary>
/// Number of moles created per second when the miner is working.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnAmount")]
public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f;
}
}

View File

@@ -1,84 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Other.Components;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
namespace Content.Server.Atmos.Piping.Other.EntitySystems
{
[UsedImplicitly]
public sealed class GasMinerSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
}
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
{
var miner = ent.Comp;
if (!GetValidEnvironment(ent, out var environment))
{
miner.Idle = true;
return;
}
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment);
miner.Idle = toSpawn == 0;
if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue)
return;
// Time to mine some gas.
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
merger.SetMoles(miner.SpawnGas.Value, toSpawn);
_atmosphereSystem.Merge(environment, merger);
}
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
{
var (uid, miner) = ent;
var transform = Transform(uid);
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
// Treat space as an invalid environment
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
{
environment = null;
return false;
}
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
return environment != null;
}
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
{
var (uid, miner) = ent;
// How many moles could we theoretically spawn. Cap by pressure and amount.
var allowableMoles = Math.Min(
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
miner.MaxExternalAmount - environment.TotalMoles);
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
if (toSpawnReal < Atmospherics.GasMinMoles) {
return 0f;
}
return toSpawnReal;
}
}
}

View File

@@ -25,4 +25,5 @@ namespace Content.Server.Body.Components
[DataField]
public ProtoId<AlertPrototype> InternalsAlert = "Internals";
}
}

View File

@@ -38,6 +38,7 @@ public sealed class InternalsSystem : EntitySystem
SubscribeLocalEvent<InternalsComponent, ComponentShutdown>(OnInternalsShutdown);
SubscribeLocalEvent<InternalsComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
SubscribeLocalEvent<InternalsComponent, InternalsDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<InternalsComponent, ToggleInternalsAlertEvent>(OnToggleInternalsAlert);
SubscribeLocalEvent<InternalsComponent, StartingGearEquippedEvent>(OnStartingGear);
}
@@ -161,6 +162,14 @@ public sealed class InternalsSystem : EntitySystem
args.Handled = true;
}
private void OnToggleInternalsAlert(Entity<InternalsComponent> ent, ref ToggleInternalsAlertEvent args)
{
if (args.Handled)
return;
ToggleInternals(ent, ent, false, internals: ent.Comp);
args.Handled = true;
}
private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args)
{
_alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));

View File

@@ -28,6 +28,7 @@ namespace Content.Server.Chemistry.EntitySystems
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly ReactiveSystem _reactive = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
private const float ReactTime = 0.125f;
@@ -69,7 +70,7 @@ namespace Content.Server.Chemistry.EntitySystems
_throwing.TryThrow(vapor, dir, speed, user: user);
var distance = (target.Position - vaporXform.WorldPosition).Length();
var distance = (target.Position - _transformSystem.GetWorldPosition(vaporXform)).Length();
var time = (distance / physics.LinearVelocity.Length());
despawn.Lifetime = MathF.Min(aliveTime, time);
}

View File

@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Robust.Server.Player;
using Robust.Shared.Console;
@@ -55,13 +55,15 @@ namespace Content.Server.Commands
{
var entMan = IoCManager.Resolve<IEntityManager>();
var transform = entMan.GetComponent<TransformComponent>(ent);
var transformSystem = entMan.System<SharedTransformSystem>();
var worldPosition = transformSystem.GetWorldPosition(transform);
// gross, is there a better way to do this?
ruleString = ruleString.Replace("$ID", ent.ToString());
ruleString = ruleString.Replace("$WX",
transform.WorldPosition.X.ToString(CultureInfo.InvariantCulture));
worldPosition.X.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$WY",
transform.WorldPosition.Y.ToString(CultureInfo.InvariantCulture));
worldPosition.Y.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$LX",
transform.LocalPosition.X.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$LY",
@@ -73,12 +75,13 @@ namespace Content.Server.Commands
if (player.AttachedEntity is {Valid: true} p)
{
var pTransform = entMan.GetComponent<TransformComponent>(p);
var pWorldPosition = transformSystem.GetWorldPosition(pTransform);
ruleString = ruleString.Replace("$PID", ent.ToString());
ruleString = ruleString.Replace("$PWX",
pTransform.WorldPosition.X.ToString(CultureInfo.InvariantCulture));
pWorldPosition.X.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$PWY",
pTransform.WorldPosition.Y.ToString(CultureInfo.InvariantCulture));
pWorldPosition.Y.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$PLX",
pTransform.LocalPosition.X.ToString(CultureInfo.InvariantCulture));
ruleString = ruleString.Replace("$PLY",

View File

@@ -6,6 +6,8 @@ namespace Content.Server.DeviceNetwork.Systems
[UsedImplicitly]
public sealed class WirelessNetworkSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
public override void Initialize()
{
base.Initialize();
@@ -25,7 +27,7 @@ namespace Content.Server.DeviceNetwork.Systems
return;
if (xform.MapID != args.SenderTransform.MapID
|| (ownPosition - xform.WorldPosition).Length() > sendingComponent.Range)
|| (ownPosition - _transformSystem.GetWorldPosition(xform)).Length() > sendingComponent.Range)
{
args.Cancel();
}

View File

@@ -156,7 +156,7 @@ public sealed partial class DragonSystem : EntitySystem
}
// cant put a rift on solars
foreach (var tile in grid.GetTilesIntersecting(new Circle(xform.WorldPosition, RiftTileRadius), false))
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
{
if (!tile.IsSpace(_tileDef))
continue;

View File

@@ -28,6 +28,7 @@ public sealed partial class EnsnareableSystem
SubscribeLocalEvent<EnsnaringComponent, StepTriggeredOffEvent>(OnStepTrigger);
SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit);
SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
SubscribeLocalEvent<EnsnareableComponent, RemoveEnsnareAlertEvent>(OnRemoveEnsnareAlert);
}
private void OnAttemptPacifiedThrow(Entity<EnsnaringComponent> ent, ref AttemptPacifiedThrowEvent args)
@@ -35,6 +36,24 @@ public sealed partial class EnsnareableSystem
args.Cancel("pacified-cannot-throw-snare");
}
private void OnRemoveEnsnareAlert(Entity<EnsnareableComponent> ent, ref RemoveEnsnareAlertEvent args)
{
if (args.Handled)
return;
foreach (var ensnare in ent.Comp.Container.ContainedEntities)
{
if (!TryComp<EnsnaringComponent>(ensnare, out var ensnaringComponent))
return;
TryFree(ent, ent, ensnare, ensnaringComponent);
args.Handled = true;
// Only one snare at a time.
break;
}
}
private void OnComponentRemove(EntityUid uid, EnsnaringComponent component, ComponentRemove args)
{
if (!TryComp<EnsnareableComponent>(component.Ensnared, out var ensnared))

View File

@@ -105,7 +105,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
var xform = xforms.GetComponent(gridToTransform);
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = xform.GetWorldPositionRotationMatrixWithInv(xforms);
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform, xforms);
var localEpicentre = (Vector2i) Vector2.Transform(epicentre.Position, invGridWorldMatrid);
var matrix = offsetMatrix * gridWorldMatrix * targetMatrix;

View File

@@ -406,7 +406,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
if (player.AttachedEntity is not EntityUid uid)
continue;
var playerPos = Transform(player.AttachedEntity!.Value).WorldPosition;
var playerPos = _transformSystem.GetWorldPosition(player.AttachedEntity!.Value);
var delta = epicenter.Position - playerPos;
if (delta.EqualsApprox(Vector2.Zero))

View File

@@ -30,13 +30,12 @@ public sealed class TwoStageTriggerSystem : EntitySystem
{
foreach (var (name, entry) in component.SecondStageComponents)
{
var comp = (Component) _factory.GetComponent(name);
var temp = (object) comp;
var comp = (Component)_factory.GetComponent(name);
var temp = (object)comp;
if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c))
RemComp(uid, c);
comp.Owner = uid;
_serializationManager.CopyTo(entry.Component, ref temp);
EntityManager.AddComponent(uid, comp);
}

View File

@@ -1,30 +0,0 @@
using Content.Server.GameTicking.Rules;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.GameTicking.Rules.Components;
/// <summary>
/// Gamerule for simple antagonists that have fixed objectives.
/// </summary>
[RegisterComponent, Access(typeof(GenericAntagRuleSystem))]
public sealed partial class GenericAntagRuleComponent : Component
{
/// <summary>
/// All antag minds that are using this rule.
/// </summary>
[DataField]
public List<EntityUid> Minds = new();
/// <summary>
/// Locale id for the name of the antag used by the roundend summary.
/// </summary>
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public string AgentName = string.Empty;
/// <summary>
/// List of objective entity prototypes to add to the antag when a mind is added.
/// </summary>
[DataField(required: true)]
public List<EntProtoId> Objectives = new();
}

View File

@@ -1,56 +0,0 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Objectives;
using Content.Shared.Mind;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Content.Server.GameTicking.Rules;
/// <summary>
/// Handles round end text for simple antags.
/// Adding objectives is handled in its own system.
/// </summary>
public sealed class GenericAntagRuleSystem : GameRuleSystem<GenericAntagRuleComponent>
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GenericAntagRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
}
/// <summary>
/// Start a simple antag's game rule.
/// If it is invalid the rule is deleted and null is returned.
/// </summary>
public bool StartRule(string rule, EntityUid mindId, [NotNullWhen(true)] out EntityUid? ruleId, [NotNullWhen(true)] out GenericAntagRuleComponent? comp)
{
ruleId = GameTicker.AddGameRule(rule);
if (!TryComp<GenericAntagRuleComponent>(ruleId, out comp))
{
Log.Error($"Simple antag rule prototype {rule} is invalid, deleting it.");
Del(ruleId);
ruleId = null;
return false;
}
if (!GameTicker.StartGameRule(ruleId.Value))
{
Log.Error($"Simple antag rule prototype {rule} failed to start, deleting it.");
Del(ruleId);
ruleId = null;
comp = null;
return false;
}
comp.Minds.Add(mindId);
return true;
}
private void OnObjectivesTextGetInfo(EntityUid uid, GenericAntagRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
{
// just temporary until this is deleted
args.Minds = comp.Minds.Select(mindId => (mindId, Comp<MindComponent>(mindId).CharacterName ?? "?")).ToList();
args.AgentName = Loc.GetString(comp.AgentName);
}
}

View File

@@ -1,30 +0,0 @@
using Content.Server.GameTicking.Rules.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.GenericAntag;
/// <summary>
/// Added to a mob to make it a generic antagonist where all its objectives are fixed.
/// This is unlike say traitor where it gets objectives picked randomly using difficulty.
/// </summary>
/// <remarks>
/// A GenericAntag is not necessarily an antagonist, that depends on the roles you do or do not add after.
/// </remarks>
[RegisterComponent, Access(typeof(GenericAntagSystem))]
public sealed partial class GenericAntagComponent : Component
{
/// <summary>
/// Gamerule to start when a mind is added.
/// This must have <see cref="GenericAntagRuleComponent"/> or it will not work.
/// </summary>
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public EntProtoId Rule = string.Empty;
/// <summary>
/// The rule that's been spawned.
/// Used to prevent spawning multiple rules.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public EntityUid? RuleEntity;
}

View File

@@ -1,67 +0,0 @@
using Content.Server.GameTicking.Rules;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
namespace Content.Server.GenericAntag;
/// <summary>
/// Handles adding objectives to <see cref="GenericAntagComponent"/>s.
/// Roundend summary is handled by <see cref="GenericAntagRuleSystem"/>.
/// </summary>
public sealed class GenericAntagSystem : EntitySystem
{
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly GenericAntagRuleSystem _genericAntagRule = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GenericAntagComponent, MindAddedMessage>(OnMindAdded);
}
private void OnMindAdded(EntityUid uid, GenericAntagComponent comp, MindAddedMessage args)
{
if (!TryComp<MindContainerComponent>(uid, out var mindContainer) || mindContainer.Mind == null)
return;
var mindId = mindContainer.Mind.Value;
MakeAntag(uid, mindId, comp);
}
/// <summary>
/// Turns a player into this antagonist.
/// Does the same thing that having a mind added does, use for antag ctrl.
/// </summary>
public void MakeAntag(EntityUid uid, EntityUid mindId, GenericAntagComponent? comp = null, MindComponent? mind = null)
{
if (!Resolve(uid, ref comp) || !Resolve(mindId, ref mind))
return;
// only add the rule once
if (comp.RuleEntity != null)
return;
// start the rule
if (!_genericAntagRule.StartRule(comp.Rule, mindId, out comp.RuleEntity, out var rule))
return;
// let other systems know the antag was created so they can add briefing, roles, etc.
// its important that this is before objectives are added since they may depend on roles added here
var ev = new GenericAntagCreatedEvent(mindId, mind);
RaiseLocalEvent(uid, ref ev);
// add the objectives from the rule
foreach (var id in rule.Objectives)
{
_mind.TryAddObjective(mindId, mind, id);
}
}
}
/// <summary>
/// Event raised on a player's entity after its simple antag rule is started.
/// Use this to add a briefing, roles, etc.
/// </summary>
[ByRefEvent]
public record struct GenericAntagCreatedEvent(EntityUid MindId, MindComponent Mind);

View File

@@ -201,7 +201,7 @@ namespace Content.Server.Hands.Systems
throwEnt = splitStack.Value;
}
var direction = coordinates.ToMapPos(EntityManager, _transformSystem) - Transform(player).WorldPosition;
var direction = _transformSystem.ToMapCoordinates(coordinates).Position - _transformSystem.GetWorldPosition(player);
if (direction == Vector2.Zero)
return true;

View File

@@ -50,8 +50,7 @@ public sealed class RandomHumanoidSystem : EntitySystem
{
foreach (var entry in prototype.Components.Values)
{
var comp = (Component) _serialization.CreateCopy(entry.Component, notNullableOverride: true);
comp.Owner = humanoid; // This .owner must survive for now.
var comp = (Component)_serialization.CreateCopy(entry.Component, notNullableOverride: true);
EntityManager.RemoveComponent(humanoid, comp.GetType());
EntityManager.AddComponent(humanoid, comp);
}

View File

@@ -23,12 +23,11 @@ namespace Content.Server.Jobs
foreach (var (name, data) in Components)
{
var component = (Component) factory.GetComponent(name);
component.Owner = mob;
var temp = (object) component;
var temp = (object)component;
serializationManager.CopyTo(data.Component, ref temp);
entityManager.RemoveComponent(mob, temp!.GetType());
entityManager.AddComponent(mob, (Component) temp);
entityManager.AddComponent(mob, (Component)temp);
}
}
}

View File

@@ -12,6 +12,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
{
[Dependency] private readonly IConGroupController _admin = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
private readonly HashSet<ICommonSession> _draggers = new();
@@ -76,8 +77,6 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem
return;
}
var gridXform = Transform(grid);
gridXform.WorldPosition = msg.WorldPosition;
_transformSystem.SetWorldPosition(grid, msg.WorldPosition);
}
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Content.Server.Interaction;
using Content.Server.Mech.Equipment.Components;
using Content.Server.Mech.Systems;
@@ -85,7 +85,7 @@ public sealed class MechGrabberSystem : EntitySystem
var (mechPos, mechRot) = _transform.GetWorldPositionRotation(mechxform);
var offset = mechPos + mechRot.RotateVec(component.DepositOffset);
_transform.SetWorldPositionRotation(xform, offset, Angle.Zero);
_transform.SetWorldPositionRotation(toRemove, offset, Angle.Zero);
_mech.UpdateUserInterface(mech);
}

View File

@@ -39,7 +39,7 @@ public sealed class StressTestMovementSystem : EntitySystem
var x = MathF.Sin(stressTest.Progress * MathHelper.TwoPi);
var y = MathF.Cos(stressTest.Progress * MathHelper.TwoPi);
_transform.SetWorldPosition(transform, stressTest.Origin + new Vector2(x, y) * 5);
_transform.SetWorldPosition((uid, transform), stressTest.Origin + new Vector2(x, y) * 5);
}
}
}

View File

@@ -12,6 +12,7 @@ namespace Content.Server.Pointing.EntitySystems
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
private EntityUid? RandomNearbyPlayer(EntityUid uid, RoguePointingArrowComponent? component = null, TransformComponent? transform = null)
{
@@ -66,27 +67,28 @@ namespace Content.Server.Pointing.EntitySystems
}
component.TurningDelay -= frameTime;
var (transformPos, transformRot) = _transformSystem.GetWorldPositionRotation(transform);
if (component.TurningDelay > 0)
{
var difference = Comp<TransformComponent>(chasing).WorldPosition - transform.WorldPosition;
var difference = _transformSystem.GetWorldPosition(chasing) - transformPos;
var angle = difference.ToAngle();
var adjusted = angle.Degrees + 90;
var newAngle = Angle.FromDegrees(adjusted);
transform.WorldRotation = newAngle;
_transformSystem.SetWorldRotation(transform, newAngle);
UpdateAppearance(uid, component, transform);
continue;
}
transform.WorldRotation += Angle.FromDegrees(20);
_transformSystem.SetWorldRotation(transform, transformRot + Angle.FromDegrees(20));
UpdateAppearance(uid, component, transform);
var toChased = Comp<TransformComponent>(chasing).WorldPosition - transform.WorldPosition;
var toChased = _transformSystem.GetWorldPosition(chasing) - transformPos;
transform.WorldPosition += toChased * frameTime * component.ChasingSpeed;
_transformSystem.SetWorldPosition((uid, transform), transformPos + (toChased * frameTime * component.ChasingSpeed));
component.ChasingTime -= frameTime;

View File

@@ -1,4 +1,4 @@
using Content.Server.Administration.Logs;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
@@ -157,7 +157,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
var tile = tileRef.GridIndices;
var found = false;
var (gridPos, _, gridMatrix) = xform.GetWorldPositionRotationMatrix();
var (gridPos, _, gridMatrix) = _transform.GetWorldPositionRotationMatrix(xform);
var gridBounds = gridMatrix.TransformBox(grid.LocalAABB);
//Obviously don't put anything ridiculous in here

View File

@@ -42,6 +42,7 @@ public sealed partial class RevenantSystem
[Dependency] private readonly GhostSystem _ghost = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
private void InitializeAbilities()
{
@@ -227,7 +228,7 @@ public sealed partial class RevenantSystem
var xform = Transform(uid);
if (!TryComp<MapGridComponent>(xform.GridUid, out var map))
return;
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(xform.WorldPosition,
var tiles = map.GetTilesIntersecting(Box2.CenteredAround(_transformSystem.GetWorldPosition(xform),
new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray();
_random.Shuffle(tiles);

View File

@@ -71,6 +71,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
SubscribeLocalEvent<UndockEvent>(OnUndock);
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<PilotComponent, StopPilotingAlertEvent>(OnStopPilotingAlert);
SubscribeLocalEvent<FTLDestinationComponent, ComponentStartup>(OnFtlDestStartup);
SubscribeLocalEvent<FTLDestinationComponent, ComponentShutdown>(OnFtlDestShutdown);
@@ -196,6 +197,14 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
args.State = new PilotComponentState(GetNetEntity(component.Console));
}
private void OnStopPilotingAlert(Entity<PilotComponent> ent, ref StopPilotingAlertEvent args)
{
if (ent.Comp.Console != null)
{
RemovePilot(ent, ent);
}
}
/// <summary>
/// Returns the position and angle of all dockingcomponents.
/// </summary>

View File

@@ -22,6 +22,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
[Dependency] private readonly PhysicsSystem _physics = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedPointLightSystem _light = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly TagSystem _tags = default!;
public override void Initialize()
@@ -116,7 +117,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
private void OnUnanchorAttempt(EntityUid uid, ContainmentFieldGeneratorComponent component,
UnanchorAttemptEvent args)
{
if (component.Enabled)
if (component.Enabled || component.IsConnected)
{
_popupSystem.PopupEntity(Loc.GetString("comp-containment-anchor-warning"), args.User, args.User, PopupType.LargeCaution);
args.Cancel();
@@ -234,7 +235,7 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
if (!gen1XForm.Anchored)
return false;
var genWorldPosRot = gen1XForm.GetWorldPositionRotation();
var genWorldPosRot = _transformSystem.GetWorldPositionRotation(gen1XForm);
var dirRad = dir.ToAngle() + genWorldPosRot.WorldRotation; //needs to be like this for the raycast to work properly
var ray = new CollisionRay(genWorldPosRot.WorldPosition, dirRad.ToVec(), component.CollisionMask);

View File

@@ -1,4 +1,4 @@
using Content.Server.Popups;
using Content.Server.Popups;
using Content.Server.Shuttles.Components;
using Content.Server.Singularity.Events;
using Content.Shared.Popups;
@@ -13,6 +13,7 @@ public sealed class ContainmentFieldSystem : EntitySystem
{
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
public override void Initialize()
{
@@ -34,8 +35,8 @@ public sealed class ContainmentFieldSystem : EntitySystem
if (TryComp<PhysicsComponent>(otherBody, out var physics) && physics.Mass <= component.MaxMass && physics.Hard)
{
var fieldDir = Transform(uid).WorldPosition;
var playerDir = Transform(otherBody).WorldPosition;
var fieldDir = _transformSystem.GetWorldPosition(uid);
var playerDir = _transformSystem.GetWorldPosition(otherBody);
_throwing.TryThrow(otherBody, playerDir-fieldDir, baseThrowSpeed: component.ThrowForce);
}

View File

@@ -137,13 +137,22 @@ public sealed class RadiationCollectorSystem : EntitySystem
private void OnExamined(EntityUid uid, RadiationCollectorComponent component, ExaminedEvent args)
{
if (!TryGetLoadedGasTank(uid, out var gasTank))
using (args.PushGroup(nameof(RadiationCollectorComponent)))
{
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-missing"));
return;
}
args.PushMarkup(Loc.GetString("power-radiation-collector-enabled", ("state", component.Enabled)));
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-present"));
if (!TryGetLoadedGasTank(uid, out var gasTank))
{
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-missing"));
}
else
{
_appearance.TryGetData<int>(uid, RadiationCollectorVisuals.PressureState, out var state);
args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-present",
("fullness", state)));
}
}
}
private void OnAnalyzed(EntityUid uid, RadiationCollectorComponent component, GasAnalyzerScanEvent args)

View File

@@ -18,6 +18,7 @@ namespace Content.Server.Solar.EntitySystems
{
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
/// <summary>
/// Maximum panel angular velocity range - used to stop people rotating panels fast enough that the lag prevention becomes noticable
@@ -112,7 +113,7 @@ namespace Content.Server.Solar.EntitySystems
while (query.MoveNext(out var uid, out var panel, out var xform))
{
TotalPanelPower += panel.MaxSupply * panel.Coverage;
xform.WorldRotation = TargetPanelRotation;
_transformSystem.SetWorldRotation(xform, TargetPanelRotation);
_updateQueue.Enqueue((uid, panel));
}
}
@@ -135,7 +136,7 @@ namespace Content.Server.Solar.EntitySystems
// directly downwards (abs(theta) = pi) = coverage -1
// as TowardsSun + = CCW,
// panelRelativeToSun should - = CW
var panelRelativeToSun = xform.WorldRotation - TowardsSun;
var panelRelativeToSun = _transformSystem.GetWorldRotation(xform) - TowardsSun;
// essentially, given cos = X & sin = Y & Y is 'downwards',
// then for the first 90 degrees of rotation in either direction,
// this plots the lower-right quadrant of a circle.
@@ -153,7 +154,7 @@ namespace Content.Server.Solar.EntitySystems
if (coverage > 0)
{
// Determine if the solar panel is occluded, and zero out coverage if so.
var ray = new CollisionRay(xform.WorldPosition, TowardsSun.ToWorldVec(), (int) CollisionGroup.Opaque);
var ray = new CollisionRay(_transformSystem.GetWorldPosition(xform), TowardsSun.ToWorldVec(), (int) CollisionGroup.Opaque);
var rayCastResults = _physicsSystem.IntersectRayWithPredicate(
xform.MapID,
ray,

View File

@@ -6,7 +6,7 @@ namespace Content.Server.Speech
{
public sealed class AccentSystem : EntitySystem
{
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?])", RegexOptions.Compiled);
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?‽])(?![\.!\?‽])", RegexOptions.Compiled);
public override void Initialize()
{

View File

@@ -7,5 +7,4 @@ namespace Content.Server.Speech.Components;
/// </summary>
[RegisterComponent]
[Access(typeof(FrenchAccentSystem))]
public sealed partial class FrenchAccentComponent : Component
{ }
public sealed partial class FrenchAccentComponent : Component {}

View File

@@ -1,7 +1,4 @@
namespace Content.Server.Speech.Components
{
[RegisterComponent]
public sealed partial class SpanishAccentComponent : Component
{
}
}
namespace Content.Server.Speech.Components;
[RegisterComponent]
public sealed partial class SpanishAccentComponent : Component {}

View File

@@ -27,10 +27,10 @@ public sealed class FrenchAccentSystem : EntitySystem
msg = _replacement.ApplyReplacements(msg, "french");
// replaces th with dz
// replaces th with z
msg = RegexTh.Replace(msg, "'z");
// removes the letter h from the start of words.
// replaces h with ' at the start of words.
msg = RegexStartH.Replace(msg, "'");
// spaces out ! ? : and ;.

View File

@@ -1,3 +1,4 @@
using System.Text;
using Content.Server.Speech.Components;
namespace Content.Server.Speech.EntitySystems
@@ -14,7 +15,7 @@ namespace Content.Server.Speech.EntitySystems
// Insert E before every S
message = InsertS(message);
// If a sentence ends with ?, insert a reverse ? at the beginning of the sentence
message = ReplaceQuestionMark(message);
message = ReplacePunctuation(message);
return message;
}
@@ -36,24 +37,32 @@ namespace Content.Server.Speech.EntitySystems
return msg;
}
private string ReplaceQuestionMark(string message)
private string ReplacePunctuation(string message)
{
var sentences = AccentSystem.SentenceRegex.Split(message);
var msg = "";
var msg = new StringBuilder();
foreach (var s in sentences)
{
if (s.EndsWith("?", StringComparison.Ordinal)) // We've got a question => add ¿ to the beginning
var toInsert = new StringBuilder();
for (var i = s.Length - 1; i >= 0 && "?!‽".Contains(s[i]); i--)
{
// Because we don't split by whitespace, we may have some spaces in front of the sentence.
// So we add the symbol before the first non space char
msg += s.Insert(s.Length - s.TrimStart().Length, "¿");
toInsert.Append(s[i] switch
{
'?' => '¿',
'!' => '¡',
'‽' => '⸘',
_ => ' '
});
}
else
if (toInsert.Length == 0)
{
msg += s;
msg.Append(s);
} else
{
msg.Append(s.Insert(s.Length - s.TrimStart().Length, toInsert.ToString()));
}
}
return msg;
return msg.ToString();
}
private void OnAccent(EntityUid uid, SpanishAccentComponent component, AccentGetEvent args)

View File

@@ -54,7 +54,6 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
foreach (var data in ChunkComponents.Values)
{
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
entityManager.AddComponent(target, comp);
}
}

View File

@@ -30,7 +30,6 @@ public sealed partial class WorldgenConfigPrototype : IPrototype
foreach (var data in Components.Values)
{
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
entityManager.AddComponent(target, comp);
}
}

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Server.Worldgen.Components;
using JetBrains.Annotations;
@@ -12,6 +12,7 @@ namespace Content.Server.Worldgen.Systems;
public abstract class BaseWorldSystem : EntitySystem
{
[Dependency] private readonly WorldControllerSystem _worldController = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
/// <summary>
/// Gets a chunk's coordinates in chunk space as an integer value.
@@ -25,7 +26,7 @@ public abstract class BaseWorldSystem : EntitySystem
if (!Resolve(ent, ref xform))
throw new Exception("Failed to resolve transform, somehow.");
return WorldGen.WorldToChunkCoords(xform.WorldPosition).Floored();
return WorldGen.WorldToChunkCoords(_transformSystem.GetWorldPosition(xform)).Floored();
}
/// <summary>
@@ -40,7 +41,7 @@ public abstract class BaseWorldSystem : EntitySystem
if (!Resolve(ent, ref xform))
throw new Exception("Failed to resolve transform, somehow.");
return WorldGen.WorldToChunkCoords(xform.WorldPosition);
return WorldGen.WorldToChunkCoords(_transformSystem.GetWorldPosition(xform));
}
/// <summary>

View File

@@ -182,13 +182,12 @@ public sealed partial class ArtifactSystem
EntityManager.RemoveComponent(uid, reg.Type);
}
var comp = (Component) _componentFactory.GetComponent(reg);
comp.Owner = uid;
var comp = (Component)_componentFactory.GetComponent(reg);
var temp = (object) comp;
var temp = (object)comp;
_serialization.CopyTo(entry.Component, ref temp);
EntityManager.RemoveComponent(uid, temp!.GetType());
EntityManager.AddComponent(uid, (Component) temp!);
EntityManager.AddComponent(uid, (Component)temp!);
}
node.Discovered = true;
@@ -218,12 +217,11 @@ public sealed partial class ArtifactSystem
// if the entity prototype contained the component originally
if (entityPrototype?.Components.TryGetComponent(name, out var entry) ?? false)
{
var comp = (Component) _componentFactory.GetComponent(name);
comp.Owner = uid;
var temp = (object) comp;
var comp = (Component)_componentFactory.GetComponent(name);
var temp = (object)comp;
_serialization.CopyTo(entry, ref temp);
EntityManager.RemoveComponent(uid, temp!.GetType());
EntityManager.AddComponent(uid, (Component) temp);
EntityManager.AddComponent(uid, (Component)temp);
continue;
}

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Shared.Maps;
@@ -31,7 +31,7 @@ public sealed class ThrowArtifactSystem : EntitySystem
if (TryComp<MapGridComponent>(xform.GridUid, out var grid))
{
var tiles = grid.GetTilesIntersecting(
Box2.CenteredAround(xform.WorldPosition, new Vector2(component.Range * 2, component.Range)));
Box2.CenteredAround(_transform.GetWorldPosition(xform), new Vector2(component.Range * 2, component.Range)));
foreach (var tile in tiles)
{