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:
|
components:
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
|
- type: GravityAffected
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
|||||||
- type: Alerts
|
- type: Alerts
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
|
- type: GravityAffected
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: WeightlessGravityGeneratorDummy
|
name: WeightlessGravityGeneratorDummy
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ namespace Content.IntegrationTests.Tests
|
|||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(generatorComponent.GravityActive, Is.True);
|
Assert.That(generatorComponent.GravityActive, Is.True);
|
||||||
Assert.That(!entityMan.GetComponent<GravityComponent>(grid1).EnabledVV);
|
Assert.That(!entityMan.GetComponent<GravityComponent>(grid1).Enabled);
|
||||||
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).EnabledVV);
|
Assert.That(entityMan.GetComponent<GravityComponent>(grid2).Enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-enable needs power so it turns off again.
|
// Re-enable needs power so it turns off again.
|
||||||
@@ -94,7 +94,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(generatorComponent.GravityActive, Is.False);
|
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: Stripping
|
||||||
- type: Puller
|
- type: Puller
|
||||||
- type: Physics
|
- type: Physics
|
||||||
|
- type: GravityAffected
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- CanPilot
|
- CanPilot
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.Damage.Systems;
|
using Content.Shared.Damage.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Electrocution;
|
using Content.Shared.Electrocution;
|
||||||
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Interaction.Components;
|
using Content.Shared.Interaction.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
@@ -675,6 +676,11 @@ public sealed partial class AdminVerbSystem
|
|||||||
grav.Weightless = true;
|
grav.Weightless = true;
|
||||||
|
|
||||||
Dirty(args.Target, grav);
|
Dirty(args.Target, grav);
|
||||||
|
|
||||||
|
EnsureComp<GravityAffectedComponent>(args.Target, out var weightless);
|
||||||
|
weightless.Weightless = true;
|
||||||
|
|
||||||
|
Dirty(args.Target, weightless);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", noGravityName, Loc.GetString("admin-smite-remove-gravity-description"))
|
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 (TryComp<PhysicsComponent>(user, out var body))
|
||||||
{
|
{
|
||||||
if (_gravity.IsWeightless(user, body))
|
if (_gravity.IsWeightless(user))
|
||||||
{
|
{
|
||||||
// push back the player
|
// push back the player
|
||||||
_physics.ApplyLinearImpulse(user, -impulseDirection * entity.Comp.PushbackAmount, body: body);
|
_physics.ApplyLinearImpulse(user, -impulseDirection * entity.Comp.PushbackAmount, body: body);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Content.Server.Gravity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RefreshGravity(EntityUid uid, GravityComponent? gravity = null)
|
public void RefreshGravity(EntityUid uid, GravityComponent? gravity = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref gravity))
|
if (!GravityQuery.Resolve(uid, ref gravity))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gravity.Inherent)
|
if (gravity.Inherent)
|
||||||
@@ -61,7 +61,7 @@ namespace Content.Server.Gravity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void EnableGravity(EntityUid uid, GravityComponent? gravity = null)
|
public void EnableGravity(EntityUid uid, GravityComponent? gravity = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref gravity))
|
if (!GravityQuery.Resolve(uid, ref gravity))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gravity.Enabled || gravity.Inherent)
|
if (gravity.Enabled || gravity.Inherent)
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ namespace Content.Shared.Clothing.EntitySystems;
|
|||||||
|
|
||||||
public sealed class AntiGravityClothingSystem : EntitySystem
|
public sealed class AntiGravityClothingSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] SharedGravitySystem _gravity = default!;
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<IsWeightlessEvent>>(OnIsWeightless);
|
SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<IsWeightlessEvent>>(OnIsWeightless);
|
||||||
|
SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotEquippedEvent>(OnEquipped);
|
||||||
|
SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotUnequippedEvent>(OnUnequipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnIsWeightless(Entity<AntiGravityClothingComponent> ent, ref InventoryRelayedEvent<IsWeightlessEvent> args)
|
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.Handled = true;
|
||||||
args.Args.IsWeightless = 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.Alert;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -16,10 +17,4 @@ public sealed partial class MagbootsComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool RequiresGrid = true;
|
public bool RequiresGrid = true;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Slot the clothing has to be worn in to work.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public string Slot = "shoes";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,8 @@ public sealed class SharedMagbootsSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnToggled(Entity<MagbootsComponent> ent, ref ItemToggledEvent args)
|
private void OnToggled(Entity<MagbootsComponent> ent, ref ItemToggledEvent args)
|
||||||
{
|
{
|
||||||
var (uid, comp) = ent;
|
if (_container.TryGetContainingContainer((ent.Owner, null, null), out var container))
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
UpdateMagbootEffects(container.Owner, ent, args.Activated);
|
UpdateMagbootEffects(container.Owner, ent, args.Activated);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGotUnequipped(Entity<MagbootsComponent> ent, ref ClothingGotUnequippedEvent args)
|
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))
|
if (TryComp<MovedByPressureComponent>(user, out var moved))
|
||||||
moved.Enabled = !state;
|
moved.Enabled = !state;
|
||||||
|
|
||||||
|
_gravity.RefreshWeightless(user, !state);
|
||||||
|
|
||||||
if (state)
|
if (state)
|
||||||
_alerts.ShowAlert(user, ent.Comp.MagbootsAlert);
|
_alerts.ShowAlert(user, ent.Comp.MagbootsAlert);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -164,12 +164,11 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
|||||||
if (args.Target is { } target && !xformQuery.TryGetComponent(target, out targetXform))
|
if (args.Target is { } target && !xformQuery.TryGetComponent(target, out targetXform))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
TransformComponent? usedXform = null;
|
if (args.Used is { } @using && !xformQuery.HasComp(@using))
|
||||||
if (args.Used is { } @using && !xformQuery.TryGetComponent(@using, out usedXform))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// TODO: Re-use existing xform query for these calculations.
|
// 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.
|
// Whether the user has moved too much from their original position.
|
||||||
if (!_transform.InRange(userXform.Coordinates, doAfter.UserPosition, args.MovementThreshold))
|
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.
|
// 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
|
// 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;
|
friction = xform.GridUid == null || !_gridQuery.HasComp(xform.GridUid) ? _offGridDamping : _airDamping;
|
||||||
else
|
else
|
||||||
friction = _frictionModifier * GetTileFriction(uid, body, xform);
|
friction = _frictionModifier * GetTileFriction(uid, body, xform);
|
||||||
|
|||||||
@@ -10,20 +10,17 @@ public sealed partial class FloatingVisualsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long it takes to go from the bottom of the animation to the top.
|
/// How long it takes to go from the bottom of the animation to the top.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public float AnimationTime = 2f;
|
public float AnimationTime = 2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How far it goes in any direction.
|
/// How far it goes in any direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public Vector2 Offset = new(0, 0.2f);
|
public Vector2 Offset = new(0, 0.2f);
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField, AutoNetworkedField]
|
||||||
[AutoNetworkedField]
|
public bool CanFloat;
|
||||||
public bool CanFloat = false;
|
|
||||||
|
|
||||||
public readonly string AnimationKey = "gravity";
|
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
|
namespace Content.Shared.Gravity
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
|
[AutoGenerateComponentState]
|
||||||
[NetworkedComponent]
|
[NetworkedComponent]
|
||||||
public sealed partial class GravityComponent : Component
|
public sealed partial class GravityComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("gravityShakeSound")]
|
[DataField, AutoNetworkedField]
|
||||||
public SoundSpecifier GravityShakeSound { get; set; } = new SoundPathSpecifier("/Audio/Effects/alert.ogg");
|
public SoundSpecifier GravityShakeSound { get; set; } = new SoundPathSpecifier("/Audio/Effects/alert.ogg");
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField, AutoNetworkedField]
|
||||||
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")]
|
|
||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inherent gravity ensures GravitySystem won't change Enabled according to the gravity generators attached to this entity.
|
/// Inherent gravity ensures GravitySystem won't change Enabled according to the gravity generators attached to this entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField, AutoNetworkedField]
|
||||||
[DataField("inherent")]
|
|
||||||
public bool Inherent;
|
public bool Inherent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,14 @@ namespace Content.Shared.Gravity;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedGravitySystem GravitySystem = default!;
|
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<FloatingVisualsComponent, ComponentStartup>(OnComponentStartup);
|
SubscribeLocalEvent<FloatingVisualsComponent, ComponentStartup>(OnComponentStartup);
|
||||||
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChanged);
|
SubscribeLocalEvent<FloatingVisualsComponent, WeightlessnessChangedEvent>(OnWeightlessnessChanged);
|
||||||
SubscribeLocalEvent<FloatingVisualsComponent, EntParentChangedMessage>(OnEntParentChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -24,48 +23,28 @@ public abstract class SharedFloatingVisualizerSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void FloatAnimation(EntityUid uid, Vector2 offset, string animationKey, float animationTime, bool stop = false) { }
|
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))
|
entity.Comp.CanFloat = _gravity.IsWeightless(entity.Owner);
|
||||||
return false;
|
Dirty(entity);
|
||||||
|
return entity.Comp.CanFloat;
|
||||||
if (transform.MapID == MapId.Nullspace)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
component.CanFloat = GravitySystem.IsWeightless(uid, xform: transform);
|
|
||||||
Dirty(uid, component);
|
|
||||||
return component.CanFloat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentStartup(EntityUid uid, FloatingVisualsComponent component, ComponentStartup args)
|
private void OnComponentStartup(Entity<FloatingVisualsComponent> entity, ref ComponentStartup args)
|
||||||
{
|
{
|
||||||
if (CanFloat(uid, component))
|
if (CanFloat(entity))
|
||||||
FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
|
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>();
|
if (entity.Comp.CanFloat == args.Weightless)
|
||||||
while (query.MoveNext(out var uid, out var floating, out var transform))
|
return;
|
||||||
{
|
|
||||||
if (transform.MapID == MapId.Nullspace)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (transform.GridUid != args.ChangedGridIndex)
|
entity.Comp.CanFloat = CanFloat(entity);
|
||||||
continue;
|
Dirty(entity);
|
||||||
|
|
||||||
floating.CanFloat = !args.HasGravity;
|
if (args.Weightless)
|
||||||
Dirty(uid, floating);
|
FloatAnimation(entity, entity.Comp.Offset, entity.Comp.AnimationKey, entity.Comp.AnimationTime);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,171 +1,254 @@
|
|||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Throwing;
|
||||||
using Robust.Shared.GameStates;
|
using Content.Shared.Weapons.Ranged.Systems;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Events;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Gravity
|
namespace Content.Shared.Gravity;
|
||||||
|
|
||||||
|
public abstract partial class SharedGravitySystem : EntitySystem
|
||||||
{
|
{
|
||||||
public abstract partial class SharedGravitySystem : EntitySystem
|
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
|
|
||||||
|
public static readonly ProtoId<AlertPrototype> WeightlessAlert = "Weightless";
|
||||||
|
|
||||||
|
protected EntityQuery<GravityComponent> GravityQuery;
|
||||||
|
private EntityQuery<GravityAffectedComponent> _weightlessQuery;
|
||||||
|
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
base.Initialize();
|
||||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
// Grid Gravity
|
||||||
|
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||||
|
SubscribeLocalEvent<GravityChangedEvent>(OnGravityChange);
|
||||||
|
|
||||||
public static readonly ProtoId<AlertPrototype> WeightlessAlert = "Weightless";
|
// Weightlessness
|
||||||
|
SubscribeLocalEvent<GravityAffectedComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<GravityAffectedComponent, EntParentChangedMessage>(OnEntParentChanged);
|
||||||
|
SubscribeLocalEvent<GravityAffectedComponent, PhysicsBodyTypeChangedEvent>(OnBodyTypeChanged);
|
||||||
|
|
||||||
private EntityQuery<GravityComponent> _gravityQuery;
|
// Alerts
|
||||||
|
SubscribeLocalEvent<AlertSyncEvent>(OnAlertsSync);
|
||||||
|
SubscribeLocalEvent<AlertsComponent, WeightlessnessChangedEvent>(OnWeightlessnessChanged);
|
||||||
|
SubscribeLocalEvent<AlertsComponent, EntParentChangedMessage>(OnAlertsParentChange);
|
||||||
|
|
||||||
public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, TransformComponent? xform = null)
|
// Impulse
|
||||||
{
|
SubscribeLocalEvent<GravityAffectedComponent, ShooterImpulseEvent>(OnShooterImpulse);
|
||||||
Resolve(uid, ref body, false);
|
SubscribeLocalEvent<GravityAffectedComponent, ThrowerImpulseEvent>(OnThrowerImpulse);
|
||||||
|
|
||||||
if ((body?.BodyType & (BodyType.Static | BodyType.Kinematic)) != 0)
|
GravityQuery = GetEntityQuery<GravityComponent>();
|
||||||
return false;
|
_weightlessQuery = GetEntityQuery<GravityAffectedComponent>();
|
||||||
|
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
if (TryComp<MovementIgnoreGravityComponent>(uid, out var ignoreGravityComponent))
|
public override void Update(float frameTime)
|
||||||
return ignoreGravityComponent.Weightless;
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
UpdateShake();
|
||||||
|
}
|
||||||
|
|
||||||
var ev = new IsWeightlessEvent(uid);
|
public bool IsWeightless(Entity<GravityAffectedComponent?> entity)
|
||||||
RaiseLocalEvent(uid, ref ev);
|
{
|
||||||
if (ev.Handled)
|
// If we can be weightless and are weightless, return true, otherwise return false
|
||||||
return ev.IsWeightless;
|
return _weightlessQuery.Resolve(entity, ref entity.Comp, false) && entity.Comp.Weightless;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Resolve(uid, ref xform))
|
private bool GetWeightless(Entity<GravityAffectedComponent, PhysicsComponent?> entity)
|
||||||
return true;
|
{
|
||||||
|
if (!_physicsQuery.Resolve(entity, ref entity.Comp2, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
// If grid / map has gravity
|
if (entity.Comp2.BodyType is BodyType.Static or BodyType.Kinematic)
|
||||||
if (EntityGridOrMapHaveGravity((uid, xform)))
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
return !EntityGridOrMapHaveGravity(entity.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
|
||||||
|
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>
|
||||||
|
/// Checks if a given entity is currently standing on a grid or map that supports having gravity at all.
|
||||||
|
/// </summary>
|
||||||
|
public bool EntityOnGravitySupportingGridOrMap(Entity<TransformComponent?> entity)
|
||||||
|
{
|
||||||
|
entity.Comp ??= Transform(entity);
|
||||||
|
|
||||||
|
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>
|
||||||
|
public bool EntityGridOrMapHaveGravity(Entity<TransformComponent?> entity)
|
||||||
|
{
|
||||||
|
entity.Comp ??= Transform(entity);
|
||||||
|
|
||||||
|
// 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 true;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
return GravityQuery.TryComp(entity.Comp.GridUid, out var gravity) && gravity.Enabled ||
|
||||||
/// Checks if a given entity is currently standing on a grid or map that supports having gravity at all.
|
GravityQuery.TryComp(entity.Comp.MapUid, out var mapGravity) && mapGravity.Enabled;
|
||||||
/// </summary>
|
}
|
||||||
public bool EntityOnGravitySupportingGridOrMap(Entity<TransformComponent?> entity)
|
|
||||||
|
private void OnGravityChange(ref GravityChangedEvent args)
|
||||||
|
{
|
||||||
|
var gravity = AllEntityQuery<GravityAffectedComponent, TransformComponent>();
|
||||||
|
while(gravity.MoveNext(out var uid, out var weightless, out var xform))
|
||||||
{
|
{
|
||||||
entity.Comp ??= Transform(entity);
|
if (xform.GridUid != args.ChangedGridIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
return _gravityQuery.HasComp(entity.Comp.GridUid) ||
|
RefreshWeightless((uid, weightless), !args.HasGravity);
|
||||||
_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>
|
|
||||||
public bool EntityGridOrMapHaveGravity(Entity<TransformComponent?> entity)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ev.HasGravity)
|
|
||||||
{
|
|
||||||
_alerts.ShowAlert(uid, WeightlessAlert);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_alerts.ClearAlert(uid, WeightlessAlert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
EnsureComp<GravityComponent>(ev.EntityUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
private sealed class GravityComponentState : ComponentState
|
|
||||||
{
|
|
||||||
public bool Enabled { get; }
|
|
||||||
|
|
||||||
public GravityComponentState(bool enabled)
|
|
||||||
{
|
|
||||||
Enabled = enabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ByRefEvent]
|
private void OnAlertsSync(AlertSyncEvent ev)
|
||||||
public record struct IsWeightlessEvent(EntityUid Entity, bool IsWeightless = false, bool Handled = false) : IInventoryRelayEvent
|
|
||||||
{
|
{
|
||||||
SlotFlags IInventoryRelayEvent.TargetSlots => ~SlotFlags.POCKET;
|
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)
|
||||||
|
{
|
||||||
|
EnsureComp<GravityComponent>(ev.EntityUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
private sealed class GravityComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public bool Enabled { get; }
|
||||||
|
|
||||||
|
public GravityComponentState(bool enabled)
|
||||||
|
{
|
||||||
|
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(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.GameStates;
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Physics;
|
|
||||||
using Robust.Shared.Physics.Components;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Components
|
namespace Content.Shared.Movement.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ignores gravity entirely.
|
/// Ignores gravity entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed partial class MovementIgnoreGravityComponent : Component
|
public sealed partial class MovementIgnoreGravityComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
[DataField("gravityState")] public bool Weightless = false;
|
[DataField, AutoNetworkedField]
|
||||||
}
|
|
||||||
|
|
||||||
[NetSerializable, Serializable]
|
|
||||||
public sealed class MovementIgnoreGravityComponentState : ComponentState
|
|
||||||
{
|
|
||||||
public bool Weightless;
|
public bool Weightless;
|
||||||
|
|
||||||
public MovementIgnoreGravityComponentState(MovementIgnoreGravityComponent component)
|
|
||||||
{
|
|
||||||
Weightless = component.Weightless;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public sealed class FrictionContactsSystem : EntitySystem
|
|||||||
var frictionNoInput = 0.0f;
|
var frictionNoInput = 0.0f;
|
||||||
var acceleration = 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 remove = true;
|
||||||
var entries = 0;
|
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 Content.Shared.Movement.Events;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Systems;
|
namespace Content.Shared.Movement.Systems;
|
||||||
|
|
||||||
public sealed class MovementIgnoreGravitySystem : EntitySystem
|
public sealed class MovementIgnoreGravitySystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] SharedGravitySystem _gravity = default!;
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentGetState>(GetState);
|
|
||||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentHandleState>(HandleState);
|
|
||||||
SubscribeLocalEvent<MovementAlwaysTouchingComponent, CanWeightlessMoveEvent>(OnWeightless);
|
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;
|
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)
|
// We don't check if the event has been handled as this component takes precedent over other things.
|
||||||
return;
|
|
||||||
|
|
||||||
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
|
// 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);
|
||||||
var weightless = _gravity.IsWeightless(uid, physicsComponent, xform);
|
|
||||||
var inAirHelpless = false;
|
var inAirHelpless = false;
|
||||||
|
|
||||||
if (physicsComponent.BodyStatus != BodyStatus.OnGround && !CanMoveInAirQuery.HasComponent(uid))
|
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))
|
if (!TryComp<PhysicsComponent>(ent, out var physicsComponent) || !XformQuery.TryComp(ent, out var xform))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: Make IsWeightless event based!!!
|
if (physicsComponent.BodyStatus != BodyStatus.OnGround || _gravity.IsWeightless(ent.Owner))
|
||||||
if (physicsComponent.BodyStatus != BodyStatus.OnGround || _gravity.IsWeightless(ent, physicsComponent, xform))
|
|
||||||
args.Modifier *= ent.Comp.BaseWeightlessFriction;
|
args.Modifier *= ent.Comp.BaseWeightlessFriction;
|
||||||
else
|
else
|
||||||
args.Modifier *= ent.Comp.BaseFriction;
|
args.Modifier *= ent.Comp.BaseFriction;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public sealed class SpeedModifierContactsSystem : EntitySystem
|
|||||||
var sprintSpeed = 0.0f;
|
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.
|
// 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;
|
bool remove = true;
|
||||||
var entries = 0;
|
var entries = 0;
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public abstract class SharedConveyorController : VirtualController
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (physics.BodyStatus == BodyStatus.InAir ||
|
if (physics.BodyStatus == BodyStatus.InAir ||
|
||||||
_gravity.IsWeightless(entity, physics, xform))
|
_gravity.IsWeightless(entity.Owner))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
|||||||
// and the entity is flying or currently weightless
|
// and the entity is flying or currently weightless
|
||||||
// Makes sense simulation wise to have this be part of steptrigger directly IMO
|
// Makes sense simulation wise to have this be part of steptrigger directly IMO
|
||||||
if (!component.IgnoreWeightless && TryComp<PhysicsComponent>(otherUid, out var physics) &&
|
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;
|
return false;
|
||||||
|
|
||||||
var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid };
|
var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid };
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
RaiseLocalEvent(user.Value, ref pushEv);
|
RaiseLocalEvent(user.Value, ref pushEv);
|
||||||
const float massLimit = 5f;
|
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);
|
_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();
|
var shooterEv = new ShooterImpulseEvent();
|
||||||
RaiseLocalEvent(user, ref shooterEv);
|
RaiseLocalEvent(user, ref shooterEv);
|
||||||
|
|
||||||
if (shooterEv.Push || _gravity.IsWeightless(user, userPhysics))
|
if (shooterEv.Push)
|
||||||
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
noRot: true
|
noRot: true
|
||||||
drawdepth: Mobs
|
drawdepth: Mobs
|
||||||
- type: MobCollision
|
- type: MobCollision
|
||||||
|
- type: GravityAffected
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: KinematicController
|
bodyType: KinematicController
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: MovementIgnoreGravity
|
- type: MovementIgnoreGravity
|
||||||
|
weightless: true
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Fun/immovable_rod.rsi
|
sprite: Objects/Fun/immovable_rod.rsi
|
||||||
state: icon
|
state: icon
|
||||||
noRot: false
|
noRot: false
|
||||||
- type: ImmovableRod
|
- type: ImmovableRod
|
||||||
|
- type: GravityAffected
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
linearDamping: 0
|
linearDamping: 0
|
||||||
@@ -78,8 +80,6 @@
|
|||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Blunt: 190
|
Blunt: 190
|
||||||
- type: MovementIgnoreGravity
|
|
||||||
gravityState: true
|
|
||||||
- type: InputMover
|
- type: InputMover
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWeightlessAcceleration: 5
|
baseWeightlessAcceleration: 5
|
||||||
|
|||||||
@@ -64,6 +64,7 @@
|
|||||||
- type: Pullable
|
- type: Pullable
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: KinematicController
|
bodyType: KinematicController
|
||||||
|
- type: GravityAffected
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: WiresPanel
|
- type: WiresPanel
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
soundHit:
|
soundHit:
|
||||||
collection: MetalThud
|
collection: MetalThud
|
||||||
- type: CollisionWake
|
- type: CollisionWake
|
||||||
|
- type: GravityAffected
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
fixedRotation: false
|
fixedRotation: false
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: true
|
anchored: true
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
|
- type: GravityAffected
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Static
|
bodyType: Static
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
|
|||||||
Reference in New Issue
Block a user