EVENT BASED WEIGHTLESSNESS (#37971)
* Init Commit * Typos * Commit 2 * Save Interaction Test Mob from failing * ssss * Confident I've gotten all the correct prototypes * Whoops forgot to edit those * aaaaa * Better solution * Test fail fixes * Yaml fix * THE FINAL TEST FIX * Final fix(?) * whoops * Added a WeightlessnessChangedEvent * Check out this diff * Wait I'm dumb * Final optimization and don't duplicate code * Death to IsWeightless * File scoped namespaces * REVIEW * Fix test fails * FIX TEST FAILS REAL * A * Commit of doom * borgar * We don't need to specify on map init apparently * Fuck it * LOAD BEARING COMMENT --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5cd9ba6016
commit
9de76e70c7
@@ -21,6 +21,7 @@ namespace Content.IntegrationTests.Tests.Doors
|
||||
components:
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: GravityAffected
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
- type: Alerts
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: GravityAffected
|
||||
|
||||
- type: entity
|
||||
name: WeightlessGravityGeneratorDummy
|
||||
|
||||
@@ -76,8 +76,8 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(generatorComponent.GravityActive, Is.True);
|
||||
Assert.That(!entityMan.GetComponent<GravityComponent>(grid1).EnabledVV);
|
||||
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).EnabledVV);
|
||||
Assert.That(!entityMan.GetComponent<GravityComponent>(grid1).Enabled);
|
||||
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).Enabled);
|
||||
});
|
||||
|
||||
// Re-enable needs power so it turns off again.
|
||||
@@ -94,7 +94,7 @@ namespace Content.IntegrationTests.Tests
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(generatorComponent.GravityActive, Is.False);
|
||||
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).EnabledVV, Is.False);
|
||||
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).Enabled, Is.False);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ public abstract partial class InteractionTest
|
||||
- type: Stripping
|
||||
- type: Puller
|
||||
- type: Physics
|
||||
- type: GravityAffected
|
||||
- type: Tag
|
||||
tags:
|
||||
- CanPilot
|
||||
|
||||
@@ -29,6 +29,7 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Electrocution;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Mobs;
|
||||
@@ -675,6 +676,11 @@ public sealed partial class AdminVerbSystem
|
||||
grav.Weightless = true;
|
||||
|
||||
Dirty(args.Target, grav);
|
||||
|
||||
EnsureComp<GravityAffectedComponent>(args.Target, out var weightless);
|
||||
weightless.Weightless = true;
|
||||
|
||||
Dirty(args.Target, weightless);
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
Message = string.Join(": ", noGravityName, Loc.GetString("admin-smite-remove-gravity-description"))
|
||||
|
||||
@@ -166,7 +166,7 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
if (TryComp<PhysicsComponent>(user, out var body))
|
||||
{
|
||||
if (_gravity.IsWeightless(user, body))
|
||||
if (_gravity.IsWeightless(user))
|
||||
{
|
||||
// push back the player
|
||||
_physics.ApplyLinearImpulse(user, -impulseDirection * entity.Comp.PushbackAmount, body: body);
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Content.Server.Gravity
|
||||
/// </summary>
|
||||
public void RefreshGravity(EntityUid uid, GravityComponent? gravity = null)
|
||||
{
|
||||
if (!Resolve(uid, ref gravity))
|
||||
if (!GravityQuery.Resolve(uid, ref gravity))
|
||||
return;
|
||||
|
||||
if (gravity.Inherent)
|
||||
@@ -61,7 +61,7 @@ namespace Content.Server.Gravity
|
||||
/// </summary>
|
||||
public void EnableGravity(EntityUid uid, GravityComponent? gravity = null)
|
||||
{
|
||||
if (!Resolve(uid, ref gravity))
|
||||
if (!GravityQuery.Resolve(uid, ref gravity))
|
||||
return;
|
||||
|
||||
if (gravity.Enabled || gravity.Inherent)
|
||||
|
||||
@@ -6,10 +6,13 @@ namespace Content.Shared.Clothing.EntitySystems;
|
||||
|
||||
public sealed class AntiGravityClothingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] SharedGravitySystem _gravity = default!;
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<IsWeightlessEvent>>(OnIsWeightless);
|
||||
SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotEquippedEvent>(OnEquipped);
|
||||
SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotUnequippedEvent>(OnUnequipped);
|
||||
}
|
||||
|
||||
private void OnIsWeightless(Entity<AntiGravityClothingComponent> ent, ref InventoryRelayedEvent<IsWeightlessEvent> args)
|
||||
@@ -20,4 +23,14 @@ public sealed class AntiGravityClothingSystem : EntitySystem
|
||||
args.Args.Handled = true;
|
||||
args.Args.IsWeightless = true;
|
||||
}
|
||||
|
||||
private void OnEquipped(Entity<AntiGravityClothingComponent> entity, ref ClothingGotEquippedEvent args)
|
||||
{
|
||||
_gravity.RefreshWeightless(args.Wearer, true);
|
||||
}
|
||||
|
||||
private void OnUnequipped(Entity<AntiGravityClothingComponent> entity, ref ClothingGotUnequippedEvent args)
|
||||
{
|
||||
_gravity.RefreshWeightless(args.Wearer, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -16,10 +17,4 @@ public sealed partial class MagbootsComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool RequiresGrid = true;
|
||||
|
||||
/// <summary>
|
||||
/// Slot the clothing has to be worn in to work.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Slot = "shoes";
|
||||
}
|
||||
|
||||
@@ -32,15 +32,9 @@ public sealed class SharedMagbootsSystem : EntitySystem
|
||||
|
||||
private void OnToggled(Entity<MagbootsComponent> ent, ref ItemToggledEvent args)
|
||||
{
|
||||
var (uid, comp) = ent;
|
||||
// only stick to the floor if being worn in the correct slot
|
||||
if (_container.TryGetContainingContainer((uid, null, null), out var container) &&
|
||||
_inventory.TryGetSlotEntity(container.Owner, comp.Slot, out var worn)
|
||||
&& uid == worn)
|
||||
{
|
||||
if (_container.TryGetContainingContainer((ent.Owner, null, null), out var container))
|
||||
UpdateMagbootEffects(container.Owner, ent, args.Activated);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGotUnequipped(Entity<MagbootsComponent> ent, ref ClothingGotUnequippedEvent args)
|
||||
{
|
||||
@@ -58,6 +52,8 @@ public sealed class SharedMagbootsSystem : EntitySystem
|
||||
if (TryComp<MovedByPressureComponent>(user, out var moved))
|
||||
moved.Enabled = !state;
|
||||
|
||||
_gravity.RefreshWeightless(user, !state);
|
||||
|
||||
if (state)
|
||||
_alerts.ShowAlert(user, ent.Comp.MagbootsAlert);
|
||||
else
|
||||
|
||||
@@ -164,12 +164,11 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
||||
if (args.Target is { } target && !xformQuery.TryGetComponent(target, out targetXform))
|
||||
return true;
|
||||
|
||||
TransformComponent? usedXform = null;
|
||||
if (args.Used is { } @using && !xformQuery.TryGetComponent(@using, out usedXform))
|
||||
if (args.Used is { } @using && !xformQuery.HasComp(@using))
|
||||
return true;
|
||||
|
||||
// TODO: Re-use existing xform query for these calculations.
|
||||
if (args.BreakOnMove && !(!args.BreakOnWeightlessMove && _gravity.IsWeightless(args.User, xform: userXform)))
|
||||
if (args.BreakOnMove && !(!args.BreakOnWeightlessMove && _gravity.IsWeightless(args.User)))
|
||||
{
|
||||
// Whether the user has moved too much from their original position.
|
||||
if (!_transform.InRange(userXform.Coordinates, doAfter.UserPosition, args.MovementThreshold))
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Content.Shared.Friction
|
||||
|
||||
// If we're not touching the ground, don't use tileFriction.
|
||||
// TODO: Make IsWeightless event-based; we already have grid traversals tracked so just raise events
|
||||
if (body.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(uid, body, xform) || !xform.Coordinates.IsValid(EntityManager))
|
||||
if (body.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(uid) || !xform.Coordinates.IsValid(EntityManager))
|
||||
friction = xform.GridUid == null || !_gridQuery.HasComp(xform.GridUid) ? _offGridDamping : _airDamping;
|
||||
else
|
||||
friction = _frictionModifier * GetTileFriction(uid, body, xform);
|
||||
|
||||
@@ -10,20 +10,17 @@ public sealed partial class FloatingVisualsComponent : Component
|
||||
/// <summary>
|
||||
/// How long it takes to go from the bottom of the animation to the top.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField, AutoNetworkedField]
|
||||
public float AnimationTime = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// How far it goes in any direction.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField, AutoNetworkedField]
|
||||
public Vector2 Offset = new(0, 0.2f);
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public bool CanFloat = false;
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool CanFloat;
|
||||
|
||||
public readonly string AnimationKey = "gravity";
|
||||
}
|
||||
|
||||
17
Content.Shared/Gravity/GravityAffectedComponent.cs
Normal file
17
Content.Shared/Gravity/GravityAffectedComponent.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Gravity;
|
||||
|
||||
/// <summary>
|
||||
/// This Component allows a target to be considered "weightless" when Weightless is true. Without this component, the
|
||||
/// target will never be weightless.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class GravityAffectedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, this entity will be considered "weightless"
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Weightless = true;
|
||||
}
|
||||
@@ -5,34 +5,20 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared.Gravity
|
||||
{
|
||||
[RegisterComponent]
|
||||
[AutoGenerateComponentState]
|
||||
[NetworkedComponent]
|
||||
public sealed partial class GravityComponent : Component
|
||||
{
|
||||
[DataField("gravityShakeSound")]
|
||||
[DataField, AutoNetworkedField]
|
||||
public SoundSpecifier GravityShakeSound { get; set; } = new SoundPathSpecifier("/Audio/Effects/alert.ogg");
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool EnabledVV
|
||||
{
|
||||
get => Enabled;
|
||||
set
|
||||
{
|
||||
if (Enabled == value) return;
|
||||
Enabled = value;
|
||||
var ev = new GravityChangedEvent(Owner, value);
|
||||
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(Owner, ref ev);
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
[DataField("enabled")]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Inherent gravity ensures GravitySystem won't change Enabled according to the gravity generators attached to this entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("inherent")]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Inherent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@ namespace Content.Shared.Gravity;
|
||||
/// </summary>
|
||||
public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedGravitySystem GravitySystem = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChanged);
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, EntParentChangedMessage>(OnEntParentChanged);
|
||||
SubscribeLocalEvent<FloatingVisualsComponent, WeightlessnessChangedEvent>(OnWeightlessnessChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -24,48 +23,28 @@ public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
||||
/// </summary>
|
||||
public virtual void FloatAnimation(EntityUid uid, Vector2 offset, string animationKey, float animationTime, bool stop = false) { }
|
||||
|
||||
protected bool CanFloat(EntityUid uid, FloatingVisualsComponent component, TransformComponent? transform = null)
|
||||
protected bool CanFloat(Entity<FloatingVisualsComponent> entity)
|
||||
{
|
||||
if (!Resolve(uid, ref transform))
|
||||
return false;
|
||||
|
||||
if (transform.MapID == MapId.Nullspace)
|
||||
return false;
|
||||
|
||||
component.CanFloat = GravitySystem.IsWeightless(uid, xform: transform);
|
||||
Dirty(uid, component);
|
||||
return component.CanFloat;
|
||||
entity.Comp.CanFloat = _gravity.IsWeightless(entity.Owner);
|
||||
Dirty(entity);
|
||||
return entity.Comp.CanFloat;
|
||||
}
|
||||
|
||||
private void OnComponentStartup(EntityUid uid, FloatingVisualsComponent component, ComponentStartup args)
|
||||
private void OnComponentStartup(Entity<FloatingVisualsComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
if (CanFloat(uid, component))
|
||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
if (CanFloat(entity))
|
||||
FloatAnimation(entity, entity.Comp.Offset, entity.Comp.AnimationKey, entity.Comp.AnimationTime);
|
||||
}
|
||||
|
||||
private void OnGravityChanged(ref GravityChangedEvent args)
|
||||
private void OnWeightlessnessChanged(Entity<FloatingVisualsComponent> entity, ref WeightlessnessChangedEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<FloatingVisualsComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var floating, out var transform))
|
||||
{
|
||||
if (transform.MapID == MapId.Nullspace)
|
||||
continue;
|
||||
if (entity.Comp.CanFloat == args.Weightless)
|
||||
return;
|
||||
|
||||
if (transform.GridUid != args.ChangedGridIndex)
|
||||
continue;
|
||||
entity.Comp.CanFloat = CanFloat(entity);
|
||||
Dirty(entity);
|
||||
|
||||
floating.CanFloat = !args.HasGravity;
|
||||
Dirty(uid, floating);
|
||||
|
||||
if (!args.HasGravity)
|
||||
FloatAnimation(uid, floating.Offset, floating.AnimationKey, floating.AnimationTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent component, ref EntParentChangedMessage args)
|
||||
{
|
||||
var transform = args.Transform;
|
||||
if (CanFloat(uid, component, transform))
|
||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
||||
if (args.Weightless)
|
||||
FloatAnimation(entity, entity.Comp.Offset, entity.Comp.AnimationKey, entity.Comp.AnimationTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Gravity
|
||||
{
|
||||
namespace Content.Shared.Gravity;
|
||||
|
||||
public abstract partial class SharedGravitySystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
@@ -17,31 +19,139 @@ namespace Content.Shared.Gravity
|
||||
|
||||
public static readonly ProtoId<AlertPrototype> WeightlessAlert = "Weightless";
|
||||
|
||||
private EntityQuery<GravityComponent> _gravityQuery;
|
||||
protected EntityQuery<GravityComponent> GravityQuery;
|
||||
private EntityQuery<GravityAffectedComponent> _weightlessQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
||||
public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, TransformComponent? xform = null)
|
||||
public override void Initialize()
|
||||
{
|
||||
Resolve(uid, ref body, false);
|
||||
base.Initialize();
|
||||
// Grid Gravity
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChange);
|
||||
|
||||
if ((body?.BodyType & (BodyType.Static | BodyType.Kinematic)) != 0)
|
||||
// Weightlessness
|
||||
SubscribeLocalEvent<GravityAffectedComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<GravityAffectedComponent, EntParentChangedMessage>(OnEntParentChanged);
|
||||
SubscribeLocalEvent<GravityAffectedComponent, PhysicsBodyTypeChangedEvent>(OnBodyTypeChanged);
|
||||
|
||||
// Alerts
|
||||
SubscribeLocalEvent<AlertSyncEvent>(OnAlertsSync);
|
||||
SubscribeLocalEvent<AlertsComponent, WeightlessnessChangedEvent>(OnWeightlessnessChanged);
|
||||
SubscribeLocalEvent<AlertsComponent, EntParentChangedMessage>(OnAlertsParentChange);
|
||||
|
||||
// Impulse
|
||||
SubscribeLocalEvent<GravityAffectedComponent, ShooterImpulseEvent>(OnShooterImpulse);
|
||||
SubscribeLocalEvent<GravityAffectedComponent, ThrowerImpulseEvent>(OnThrowerImpulse);
|
||||
|
||||
GravityQuery = GetEntityQuery<GravityComponent>();
|
||||
_weightlessQuery = GetEntityQuery<GravityAffectedComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
UpdateShake();
|
||||
}
|
||||
|
||||
public bool IsWeightless(Entity<GravityAffectedComponent?> entity)
|
||||
{
|
||||
// If we can be weightless and are weightless, return true, otherwise return false
|
||||
return _weightlessQuery.Resolve(entity, ref entity.Comp, false) && entity.Comp.Weightless;
|
||||
}
|
||||
|
||||
private bool GetWeightless(Entity<GravityAffectedComponent, PhysicsComponent?> entity)
|
||||
{
|
||||
if (!_physicsQuery.Resolve(entity, ref entity.Comp2, false))
|
||||
return false;
|
||||
|
||||
if (TryComp<MovementIgnoreGravityComponent>(uid, out var ignoreGravityComponent))
|
||||
return ignoreGravityComponent.Weightless;
|
||||
if (entity.Comp2.BodyType is BodyType.Static or BodyType.Kinematic)
|
||||
return false;
|
||||
|
||||
var ev = new IsWeightlessEvent(uid);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
// Check if something other than the grid or map is overriding our gravity
|
||||
var ev = new IsWeightlessEvent();
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
if (ev.Handled)
|
||||
return ev.IsWeightless;
|
||||
|
||||
if (!Resolve(uid, ref xform))
|
||||
return true;
|
||||
return !EntityGridOrMapHaveGravity(entity.Owner);
|
||||
}
|
||||
|
||||
// If grid / map has gravity
|
||||
if (EntityGridOrMapHaveGravity((uid, xform)))
|
||||
return false;
|
||||
/// <summary>
|
||||
/// Refreshes weightlessness status, needs to be called anytime it would change.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity we are updating the weightless status of</param>
|
||||
public void RefreshWeightless(Entity<GravityAffectedComponent?> entity)
|
||||
{
|
||||
if (!_weightlessQuery.Resolve(entity, ref entity.Comp))
|
||||
return;
|
||||
|
||||
return true;
|
||||
UpdateWeightless(entity!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overload of <see cref="RefreshWeightless(Entity{GravityAffectedComponent?})"/> which also takes a bool for the weightlessness value we want to change to.
|
||||
/// This method is LOAD BEARING for UninitializedSaveTest. DO NOT REMOVE IT.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity we are updating the weightless status of</param>
|
||||
/// <param name="weightless">The weightless value we are trying to change to, helps avoid needless networking</param>
|
||||
public void RefreshWeightless(Entity<GravityAffectedComponent?> entity, bool weightless)
|
||||
{
|
||||
if (!_weightlessQuery.Resolve(entity, ref entity.Comp))
|
||||
return;
|
||||
|
||||
// Only update if we're changing our weightless status
|
||||
if (entity.Comp.Weightless == weightless)
|
||||
return;
|
||||
|
||||
UpdateWeightless(entity!);
|
||||
}
|
||||
|
||||
private void UpdateWeightless(Entity<GravityAffectedComponent> entity)
|
||||
{
|
||||
var newWeightless = GetWeightless(entity);
|
||||
|
||||
// Don't network or raise events if it's not changing
|
||||
if (newWeightless == entity.Comp.Weightless)
|
||||
return;
|
||||
|
||||
entity.Comp.Weightless = newWeightless;
|
||||
Dirty(entity);
|
||||
|
||||
var ev = new WeightlessnessChangedEvent(entity.Comp.Weightless);
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<GravityAffectedComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
RefreshWeightless((entity.Owner, entity.Comp));
|
||||
}
|
||||
|
||||
private void OnWeightlessnessChanged(Entity<AlertsComponent> entity, ref WeightlessnessChangedEvent args)
|
||||
{
|
||||
if (args.Weightless)
|
||||
_alerts.ShowAlert(entity, WeightlessAlert);
|
||||
else
|
||||
_alerts.ClearAlert(entity, WeightlessAlert);
|
||||
}
|
||||
|
||||
private void OnEntParentChanged(Entity<GravityAffectedComponent> entity, ref EntParentChangedMessage args)
|
||||
{
|
||||
// If we've moved but are still on the same grid, then don't do anything.
|
||||
if (args.OldParent == args.Transform.GridUid)
|
||||
return;
|
||||
|
||||
RefreshWeightless((entity.Owner, entity.Comp), !EntityGridOrMapHaveGravity((entity, args.Transform)));
|
||||
}
|
||||
|
||||
private void OnBodyTypeChanged(Entity<GravityAffectedComponent> entity, ref PhysicsBodyTypeChangedEvent args)
|
||||
{
|
||||
// No need to update weightlessness if we're not weightless and we're a body type that can't be weightless
|
||||
if (args.New is BodyType.Static or BodyType.Kinematic && entity.Comp.Weightless == false)
|
||||
return;
|
||||
|
||||
RefreshWeightless((entity.Owner, entity.Comp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,11 +161,10 @@ namespace Content.Shared.Gravity
|
||||
{
|
||||
entity.Comp ??= Transform(entity);
|
||||
|
||||
return _gravityQuery.HasComp(entity.Comp.GridUid) ||
|
||||
_gravityQuery.HasComp(entity.Comp.MapUid);
|
||||
return GravityQuery.HasComp(entity.Comp.GridUid) ||
|
||||
GravityQuery.HasComp(entity.Comp.MapUid);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given entity is currently standing on a grid or map that has gravity of some kind.
|
||||
/// </summary>
|
||||
@@ -63,88 +172,42 @@ namespace Content.Shared.Gravity
|
||||
{
|
||||
entity.Comp ??= Transform(entity);
|
||||
|
||||
return _gravityQuery.TryComp(entity.Comp.GridUid, out var gravity) && gravity.Enabled ||
|
||||
_gravityQuery.TryComp(entity.Comp.MapUid, out var mapGravity) && mapGravity.Enabled;
|
||||
// DO NOT SET TO WEIGHTLESS IF THEY'RE IN NULL-SPACE
|
||||
// TODO: If entities actually properly pause when leaving PVS rather than entering null-space this can probably go.
|
||||
if (entity.Comp.MapID == MapId.Nullspace)
|
||||
return true;
|
||||
|
||||
return GravityQuery.TryComp(entity.Comp.GridUid, out var gravity) && gravity.Enabled ||
|
||||
GravityQuery.TryComp(entity.Comp.MapUid, out var mapGravity) && mapGravity.Enabled;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
private void OnGravityChange(ref GravityChangedEvent args)
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||
SubscribeLocalEvent<AlertSyncEvent>(OnAlertsSync);
|
||||
SubscribeLocalEvent<AlertsComponent, EntParentChangedMessage>(OnAlertsParentChange);
|
||||
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChange);
|
||||
SubscribeLocalEvent<GravityComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<GravityComponent, ComponentHandleState>(OnHandleState);
|
||||
|
||||
_gravityQuery = GetEntityQuery<GravityComponent>();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
var gravity = AllEntityQuery<GravityAffectedComponent, TransformComponent>();
|
||||
while(gravity.MoveNext(out var uid, out var weightless, out var xform))
|
||||
{
|
||||
base.Update(frameTime);
|
||||
UpdateShake();
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, GravityComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not GravityComponentState state)
|
||||
return;
|
||||
|
||||
if (component.EnabledVV == state.Enabled)
|
||||
return;
|
||||
component.EnabledVV = state.Enabled;
|
||||
var ev = new GravityChangedEvent(uid, component.EnabledVV);
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, GravityComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new GravityComponentState(component.EnabledVV);
|
||||
}
|
||||
|
||||
private void OnGravityChange(ref GravityChangedEvent ev)
|
||||
{
|
||||
var alerts = AllEntityQuery<AlertsComponent, TransformComponent>();
|
||||
while(alerts.MoveNext(out var uid, out _, out var xform))
|
||||
{
|
||||
if (xform.GridUid != ev.ChangedGridIndex)
|
||||
if (xform.GridUid != args.ChangedGridIndex)
|
||||
continue;
|
||||
|
||||
if (!ev.HasGravity)
|
||||
{
|
||||
_alerts.ShowAlert(uid, WeightlessAlert);
|
||||
}
|
||||
else
|
||||
{
|
||||
_alerts.ClearAlert(uid, WeightlessAlert);
|
||||
}
|
||||
RefreshWeightless((uid, weightless), !args.HasGravity);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAlertsSync(AlertSyncEvent ev)
|
||||
{
|
||||
if (IsWeightless(ev.Euid))
|
||||
{
|
||||
_alerts.ShowAlert(ev.Euid, WeightlessAlert);
|
||||
}
|
||||
else
|
||||
{
|
||||
_alerts.ClearAlert(ev.Euid, WeightlessAlert);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAlertsParentChange(EntityUid uid, AlertsComponent component, ref EntParentChangedMessage args)
|
||||
{
|
||||
if (IsWeightless(uid))
|
||||
{
|
||||
_alerts.ShowAlert(uid, WeightlessAlert);
|
||||
}
|
||||
else
|
||||
{
|
||||
_alerts.ClearAlert(uid, WeightlessAlert);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGridInit(GridInitializeEvent ev)
|
||||
{
|
||||
@@ -161,11 +224,31 @@ namespace Content.Shared.Gravity
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnThrowerImpulse(Entity<GravityAffectedComponent> entity, ref ThrowerImpulseEvent args)
|
||||
{
|
||||
args.Push = true;
|
||||
}
|
||||
|
||||
private void OnShooterImpulse(Entity<GravityAffectedComponent> entity, ref ShooterImpulseEvent args)
|
||||
{
|
||||
args.Push = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised to determine if an entity's weightlessness is being overwritten by a component or item with a component.
|
||||
/// </summary>
|
||||
/// <param name="IsWeightless">Whether we should be weightless</param>
|
||||
/// <param name="Handled">Whether something is trying to override our weightlessness</param>
|
||||
[ByRefEvent]
|
||||
public record struct IsWeightlessEvent(EntityUid Entity, bool IsWeightless = false, bool Handled = false) : IInventoryRelayEvent
|
||||
public record struct IsWeightlessEvent(bool IsWeightless = false, bool Handled = false) : IInventoryRelayEvent
|
||||
{
|
||||
SlotFlags IInventoryRelayEvent.TargetSlots => ~SlotFlags.POCKET;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity when their weightless status changes.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct WeightlessnessChangedEvent(bool Weightless);
|
||||
|
||||
@@ -1,34 +1,17 @@
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Movement.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Ignores gravity entirely.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class MovementIgnoreGravityComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not gravity is on or off for this object.
|
||||
/// Whether gravity is on or off for this object. This will always override the current Gravity State.
|
||||
/// </summary>
|
||||
[DataField("gravityState")] public bool Weightless = false;
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class MovementIgnoreGravityComponentState : ComponentState
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Weightless;
|
||||
|
||||
public MovementIgnoreGravityComponentState(MovementIgnoreGravityComponent component)
|
||||
{
|
||||
Weightless = component.Weightless;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public sealed class FrictionContactsSystem : EntitySystem
|
||||
var frictionNoInput = 0.0f;
|
||||
var acceleration = 0.0f;
|
||||
|
||||
var isAirborne = physicsComponent.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(entity, physicsComponent);
|
||||
var isAirborne = physicsComponent.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(entity.Owner);
|
||||
|
||||
var remove = true;
|
||||
var entries = 0;
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Movement.Systems;
|
||||
|
||||
public sealed class MovementIgnoreGravitySystem : EntitySystem
|
||||
{
|
||||
[Dependency] SharedGravitySystem _gravity = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentGetState>(GetState);
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentHandleState>(HandleState);
|
||||
SubscribeLocalEvent<MovementAlwaysTouchingComponent, CanWeightlessMoveEvent>(OnWeightless);
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, IsWeightlessEvent>(OnIsWeightless);
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentStartup>(OnComponentStartup);
|
||||
}
|
||||
|
||||
private void OnWeightless(EntityUid uid, MovementAlwaysTouchingComponent component, ref CanWeightlessMoveEvent args)
|
||||
private void OnWeightless(Entity<MovementAlwaysTouchingComponent> entity, ref CanWeightlessMoveEvent args)
|
||||
{
|
||||
args.CanMove = true;
|
||||
}
|
||||
|
||||
private void HandleState(EntityUid uid, MovementIgnoreGravityComponent component, ref ComponentHandleState args)
|
||||
private void OnIsWeightless(Entity<MovementIgnoreGravityComponent> entity, ref IsWeightlessEvent args)
|
||||
{
|
||||
if (args.Next is null)
|
||||
return;
|
||||
// We don't check if the event has been handled as this component takes precedent over other things.
|
||||
|
||||
component.Weightless = ((MovementIgnoreGravityComponentState) args.Next).Weightless;
|
||||
args.IsWeightless = entity.Comp.Weightless;
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void GetState(EntityUid uid, MovementIgnoreGravityComponent component, ref ComponentGetState args)
|
||||
private void OnComponentStartup(Entity<MovementIgnoreGravityComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
args.State = new MovementIgnoreGravityComponentState(component);
|
||||
EnsureComp<GravityAffectedComponent>(entity);
|
||||
_gravity.RefreshWeightless(entity.Owner, entity.Comp.Weightless);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +195,7 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
}
|
||||
|
||||
// If the body is in air but isn't weightless then it can't move
|
||||
// TODO: MAKE ISWEIGHTLESS EVENT BASED
|
||||
var weightless = _gravity.IsWeightless(uid, physicsComponent, xform);
|
||||
var weightless = _gravity.IsWeightless(uid);
|
||||
var inAirHelpless = false;
|
||||
|
||||
if (physicsComponent.BodyStatus != BodyStatus.OnGround && !CanMoveInAirQuery.HasComponent(uid))
|
||||
@@ -624,8 +623,7 @@ public abstract partial class SharedMoverController : VirtualController
|
||||
if (!TryComp<PhysicsComponent>(ent, out var physicsComponent) || !XformQuery.TryComp(ent, out var xform))
|
||||
return;
|
||||
|
||||
// TODO: Make IsWeightless event based!!!
|
||||
if (physicsComponent.BodyStatus != BodyStatus.OnGround || _gravity.IsWeightless(ent, physicsComponent, xform))
|
||||
if (physicsComponent.BodyStatus != BodyStatus.OnGround || _gravity.IsWeightless(ent.Owner))
|
||||
args.Modifier *= ent.Comp.BaseWeightlessFriction;
|
||||
else
|
||||
args.Modifier *= ent.Comp.BaseFriction;
|
||||
|
||||
@@ -85,7 +85,7 @@ public sealed class SpeedModifierContactsSystem : EntitySystem
|
||||
var sprintSpeed = 0.0f;
|
||||
|
||||
// Cache the result of the airborne check, as it's expensive and independent of contacting entities, hence need only be done once.
|
||||
var isAirborne = physicsComponent.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(uid, physicsComponent);
|
||||
var isAirborne = physicsComponent.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(uid);
|
||||
|
||||
bool remove = true;
|
||||
var entries = 0;
|
||||
|
||||
@@ -216,7 +216,7 @@ public abstract class SharedConveyorController : VirtualController
|
||||
return true;
|
||||
|
||||
if (physics.BodyStatus == BodyStatus.InAir ||
|
||||
_gravity.IsWeightless(entity, physics, xform))
|
||||
_gravity.IsWeightless(entity.Owner))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
// and the entity is flying or currently weightless
|
||||
// Makes sense simulation wise to have this be part of steptrigger directly IMO
|
||||
if (!component.IgnoreWeightless && TryComp<PhysicsComponent>(otherUid, out var physics) &&
|
||||
(physics.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(otherUid, physics)))
|
||||
(physics.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(otherUid)))
|
||||
return false;
|
||||
|
||||
var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid };
|
||||
|
||||
@@ -242,7 +242,7 @@ public sealed class ThrowingSystem : EntitySystem
|
||||
RaiseLocalEvent(user.Value, ref pushEv);
|
||||
const float massLimit = 5f;
|
||||
|
||||
if (pushEv.Push || _gravity.IsWeightless(user.Value))
|
||||
if (pushEv.Push)
|
||||
_physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(massLimit, physics.Mass), body: userPhysics);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
var shooterEv = new ShooterImpulseEvent();
|
||||
RaiseLocalEvent(user, ref shooterEv);
|
||||
|
||||
if (shooterEv.Push || _gravity.IsWeightless(user, userPhysics))
|
||||
if (shooterEv.Push)
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
noRot: true
|
||||
drawdepth: Mobs
|
||||
- type: MobCollision
|
||||
- type: GravityAffected
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: MovementIgnoreGravity
|
||||
weightless: true
|
||||
- type: Sprite
|
||||
sprite: Objects/Fun/immovable_rod.rsi
|
||||
state: icon
|
||||
noRot: false
|
||||
- type: ImmovableRod
|
||||
- type: GravityAffected
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
linearDamping: 0
|
||||
@@ -78,8 +80,6 @@
|
||||
damage:
|
||||
types:
|
||||
Blunt: 190
|
||||
- type: MovementIgnoreGravity
|
||||
gravityState: true
|
||||
- type: InputMover
|
||||
- type: MovementSpeedModifier
|
||||
baseWeightlessAcceleration: 5
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
- type: Pullable
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: GravityAffected
|
||||
- type: Clickable
|
||||
- type: WiresPanel
|
||||
- type: Fixtures
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
soundHit:
|
||||
collection: MetalThud
|
||||
- type: CollisionWake
|
||||
- type: GravityAffected
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
fixedRotation: false
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- type: Transform
|
||||
anchored: true
|
||||
- type: Clickable
|
||||
- type: GravityAffected
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
|
||||
Reference in New Issue
Block a user