public bool CanFTL(EntityUid?uid, [NotNullWhen(false)] out string?reason, TransformComponent?xform = null) { reason = null; if (!TryComp <IMapGridComponent>(uid, out var grid) || !Resolve(uid.Value, ref xform)) { return(true); } var bounds = grid.Grid.WorldAABB.Enlarged(ShuttleFTLRange); var bodyQuery = GetEntityQuery <PhysicsComponent>(); foreach (var other in _mapManager.FindGridsIntersecting(xform.MapID, bounds)) { if (grid.GridIndex == other.Index || !bodyQuery.TryGetComponent(other.GridEntityId, out var body) || body.Mass < ShuttleFTLMassThreshold) { continue; } reason = Loc.GetString("shuttle-console-proximity"); return(false); } return(true); }
/// <summary> /// Sets the shuttle's movement mode. Does minimal revalidation. /// </summary> private void SetShuttleMode(ShuttleMode mode, ShuttleConsoleComponent consoleComponent, ShuttleComponent shuttleComponent, TransformComponent?consoleXform = null) { // Re-validate if (!this.IsPowered(consoleComponent.Owner, EntityManager) || !Resolve(consoleComponent.Owner, ref consoleXform) || !consoleXform.Anchored || consoleXform.GridID != Transform(shuttleComponent.Owner).GridID) { return; } shuttleComponent.Mode = mode; switch (mode) { case ShuttleMode.Strafing: break; case ShuttleMode.Cruise: break; default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// Get the body's total angular velocity. This is the rate of change of the entity's world rotation. /// </summary> /// <remarks> /// Consider using <see cref="GetMapVelocities"/> if you need linear and angular at the same time. /// </remarks> public float GetMapAngularVelocity( EntityUid uid, PhysicsComponent?component = null, TransformComponent?xform = null, EntityQuery <TransformComponent>?xformQuery = null, EntityQuery <PhysicsComponent>?physicsQuery = null) { if (!Resolve(uid, ref component)) { return(0); } xformQuery ??= EntityManager.GetEntityQuery <TransformComponent>(); physicsQuery ??= EntityManager.GetEntityQuery <PhysicsComponent>(); xform ??= xformQuery.Value.GetComponent(uid); var parent = xform.ParentUid; var angularVelocity = component.AngularVelocity; while (parent.IsValid()) { var parentXform = xformQuery.Value.GetComponent(parent); if (physicsQuery.Value.TryGetComponent(parent, out var body)) { angularVelocity += body.AngularVelocity; } parent = parentXform.ParentUid; } return(angularVelocity); }
private void UserSplit(EntityUid uid, EntityUid userUid, int amount, StackComponent?stack = null, TransformComponent?userTransform = null) { if (!Resolve(uid, ref stack)) { return; } if (!Resolve(userUid, ref userTransform)) { return; } if (amount <= 0) { _popupSystem.PopupCursor(Loc.GetString("comp-stack-split-too-small"), Filter.Entities(userUid)); return; } if (Split(uid, amount, userTransform.Coordinates, stack) is not { } split) { return; } if (TryComp <HandsComponent>(userUid, out var hands) && TryComp <ItemComponent>(split, out var item)) { hands.PutInHandOrDrop(item); } _popupSystem.PopupCursor(Loc.GetString("comp-stack-split"), Filter.Entities(userUid)); }
/// <summary> /// Tries to anchor the entity. /// </summary> /// <returns>true if anchored, false otherwise</returns> public async Task <bool> TryAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent?anchorable = null, TransformComponent?transform = null, SharedPullableComponent?pullable = null, ToolComponent?usingTool = null) { if (!Resolve(uid, ref anchorable, ref transform)) { return(false); } // Optional resolves. Resolve(uid, ref pullable, false); if (!Resolve(usingUid, ref usingTool)) { return(false); } if (!(await Valid(uid, userUid, usingUid, true, anchorable, usingTool))) { return(false); } // Snap rotation to cardinal (multiple of 90) var rot = transform.LocalRotation; transform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2); if (pullable is { Puller : {} })
/// <summary> /// Spills the specified solution at the entity's location if possible. /// </summary> /// <param name="uid"> /// The entity to use as a location to spill the solution at. /// </param> /// <param name="solution">Initial solution for the prototype.</param> /// <param name="prototype">The prototype to use.</param> /// <param name="sound">Play the spill sound.</param> /// <param name="combine">Whether to attempt to merge with existing puddles</param> /// <param name="transformComponent">Optional Transform component</param> /// <returns>The puddle if one was created, null otherwise.</returns> public PuddleComponent?SpillAt(EntityUid uid, Solution solution, string prototype, bool sound = true, bool combine = true, TransformComponent?transformComponent = null) { return(!Resolve(uid, ref transformComponent, false) ? null : SpillAt(solution, transformComponent.Coordinates, prototype, sound: sound, combine: combine)); }
public Box2 GetHardAABB(PhysicsComponent body, TransformComponent?xform = null, FixturesComponent?fixtures = null) { if (!Resolve(body.Owner, ref xform, ref fixtures)) { throw new InvalidOperationException(); } var(worldPos, worldRot) = xform.GetWorldPositionRotation(); var transform = new Transform(worldPos, (float)worldRot.Theta); var bounds = new Box2(transform.Position, transform.Position); foreach (var fixture in fixtures.Fixtures.Values) { if (!fixture.Hard) { continue; } for (var i = 0; i < fixture.Shape.ChildCount; i++) { var boundy = fixture.Shape.ComputeAABB(transform, i); bounds = bounds.Union(boundy); } } return(bounds); }
public EntityUid?TakeAmmo(AmmoBoxComponent ammoBox, TransformComponent?xform = null) { if (!Resolve(ammoBox.Owner, ref xform)) { return(null); } if (ammoBox.SpawnedAmmo.TryPop(out var ammo)) { ammoBox.AmmoContainer.Remove(ammo); return(ammo); } if (ammoBox.UnspawnedCount > 0) { ammo = EntityManager.SpawnEntity(ammoBox.FillPrototype, xform.Coordinates); // when dumping from held ammo box, this detaches the spawned ammo from the player. EntityManager.GetComponent <TransformComponent>(ammo).AttachParentToContainerOrGrid(); ammoBox.UnspawnedCount--; } return(ammo); }
/// <summary> /// Tries to unanchor the entity. /// </summary> /// <returns>true if unanchored, false otherwise</returns> private void TryUnAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent?anchorable = null, TransformComponent?transform = null, ToolComponent?usingTool = null) { if (!Resolve(uid, ref anchorable, ref transform) || anchorable.CancelToken != null) { return; } if (!Resolve(usingUid, ref usingTool)) { return; } if (!Valid(uid, userUid, usingUid, false)) { return; } anchorable.CancelToken = new CancellationTokenSource(); _toolSystem.UseTool(usingUid, userUid, uid, 0f, anchorable.Delay, usingTool.Qualities, new TryUnanchorCompletedEvent(), new TryUnanchorCancelledEvent(), uid, cancelToken: anchorable.CancelToken.Token); }
private void UpdateAppearance(EntityUid uid, AppearanceComponent?appearance = null, NodeContainerComponent?container = null, TransformComponent?xform = null) { if (!Resolve(uid, ref appearance, ref container, ref xform, false)) { return; } if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) { return; } // get connected entities var anyPipeNodes = false; HashSet <EntityUid> connected = new(); foreach (var node in container.Nodes.Values) { if (node is not PipeNode) { continue; } anyPipeNodes = true; foreach (var connectedNode in node.ReachableNodes) { if (connectedNode is PipeNode) { connected.Add(connectedNode.Owner); } } } if (!anyPipeNodes) { return; } // find the cardinal directions of any connected entities var netConnectedDirections = PipeDirection.None; var tile = grid.TileIndicesFor(xform.Coordinates); foreach (var neighbour in connected) { var otherTile = grid.TileIndicesFor(Transform(neighbour).Coordinates); netConnectedDirections |= (otherTile - tile) switch { (0, 1) => PipeDirection.North, (0, -1) => PipeDirection.South, (1, 0) => PipeDirection.East, (-1, 0) => PipeDirection.West, _ => PipeDirection.None }; } appearance.SetData(PipeVisuals.VisualState, netConnectedDirections); }
/// <summary> /// Force bomb to explode immediately /// </summary> public void ActivateBomb(EntityUid uid, NukeComponent?component = null, TransformComponent?transform = null) { if (!Resolve(uid, ref component, ref transform)) { return; } if (component.Exploded) { return; } component.Exploded = true; _explosions.QueueExplosion(uid, component.ExplosionType, component.TotalIntensity, component.IntensitySlope, component.MaxIntensity); RaiseLocalEvent(new NukeExplodedEvent()); EntityManager.DeleteEntity(uid); }
/// <summary> /// Try to find the closest entity from whitelist on a current map /// Will return null if can't find anything /// </summary> private EntityUid?FindTargetFromWhitelist(EntityUid uid, EntityWhitelist whitelist, TransformComponent?transform = null) { if (!Resolve(uid, ref transform)) { return(null); } var mapId = transform.MapID; var ents = _entityLookup.GetEntitiesInMap(mapId); // sort all entities in distance increasing order var l = new SortedList <float, EntityUid>(); foreach (var e in ents) { if (whitelist.IsValid(e)) { var dist = (EntityManager.GetComponent <TransformComponent>(e).WorldPosition - transform.WorldPosition).LengthSquared; l.TryAdd(dist, e); } } // return uid with a smallest distacne return(l.Count > 0 ? l.First().Value : null); }
/// <summary> /// Force bomb to explode immediately /// </summary> public void ActivateBomb(EntityUid uid, NukeComponent?component = null, TransformComponent?transform = null) { if (!Resolve(uid, ref component, ref transform)) { return; } // gib anyone in a blast radius // its lame, but will work for now var pos = transform.Coordinates; var ents = _lookup.GetEntitiesInRange(pos, component.BlastRadius); foreach (var ent in ents) { var entUid = ent; if (!EntityManager.EntityExists(entUid)) { continue; } if (EntityManager.TryGetComponent(entUid, out SharedBodyComponent? body)) { body.Gib(); } } EntityManager.DeleteEntity(uid); }
private void UserSplit(EntityUid uid, EntityUid userUid, int amount, StackComponent?stack = null, TransformComponent?userTransform = null) { if (!Resolve(uid, ref stack)) { return; } if (!Resolve(userUid, ref userTransform)) { return; } if (amount <= 0) { PopupSystem.PopupCursor(Loc.GetString("comp-stack-split-too-small"), Filter.Entities(userUid)); return; } if (Split(uid, amount, userTransform.Coordinates, stack) is not { } split) { return; } HandsSystem.PickupOrDrop(userUid, split); PopupSystem.PopupCursor(Loc.GetString("comp-stack-split"), Filter.Entities(userUid)); }
/// <summary> /// Try to find the closest entity from whitelist on a current map /// Will return null if can't find anything /// </summary> private EntityUid?FindTargetFromComponent(EntityUid uid, Type whitelist, TransformComponent?transform = null) { var xformQuery = GetEntityQuery <TransformComponent>(); if (transform == null) { xformQuery.TryGetComponent(uid, out transform); } if (transform == null) { return(null); } // sort all entities in distance increasing order var mapId = transform.MapID; var l = new SortedList <float, EntityUid>(); var worldPos = _transform.GetWorldPosition(transform, xformQuery); foreach (var comp in EntityManager.GetAllComponents(whitelist)) { if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) { continue; } var dist = (_transform.GetWorldPosition(compXform, xformQuery) - worldPos).LengthSquared; l.TryAdd(dist, comp.Owner); } // return uid with a smallest distacne return(l.Count > 0 ? l.First().Value : null); }
public virtual void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent?anchorable = null, TransformComponent?transform = null, SharedPullableComponent?pullable = null, ToolComponent?usingTool = null) { // Thanks tool system. return; }
public void SetAirblocked(AirtightComponent airtight, bool airblocked, TransformComponent?xform = null) { if (!Resolve(airtight.Owner, ref xform)) { return; } airtight.AirBlocked = airblocked; UpdatePosition(airtight, xform); RaiseLocalEvent(airtight.Owner, new AirtightChanged(airtight)); }
private void TryFindAndSetProvider(ExtensionCableReceiverComponent receiver, TransformComponent?xform = null) { if (!TryFindAvailableProvider(receiver.Owner, receiver.ReceptionRange, out var provider, xform)) { return; } receiver.Provider = provider; provider.LinkedReceivers.Add(receiver); RaiseLocalEvent(receiver.Owner, new ProviderConnectedEvent(provider), broadcast: false); RaiseLocalEvent(provider.Owner, new ReceiverConnectedEvent(receiver), broadcast: false); }
protected override void InsertItem(int index, EntityComponent item) { TransformComponent?oldTransformComponent = Entity.Transform; base.InsertItem(index, item); if (item is TransformComponent) { if (oldTransformComponent != null) { Remove(oldTransformComponent); } } }
public void UpdatePosition(AirtightComponent airtight, TransformComponent?xform = null) { if (!Resolve(airtight.Owner, ref xform)) { return; } if (!xform.Anchored || !_mapManager.TryGetGrid(xform.GridUid, out var grid)) { return; } airtight.LastPosition = (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)); InvalidatePosition(airtight.LastPosition.Item1, airtight.LastPosition.Item2, airtight.FixVacuum && !airtight.AirBlocked); }
public (Vector2, float) GetMapVelocities( EntityUid uid, PhysicsComponent?component = null, TransformComponent?xform = null, EntityQuery <TransformComponent>?xformQuery = null, EntityQuery <PhysicsComponent>?physicsQuery = null) { if (!Resolve(uid, ref component)) { return(Vector2.Zero, 0); } xformQuery ??= EntityManager.GetEntityQuery <TransformComponent>(); physicsQuery ??= EntityManager.GetEntityQuery <PhysicsComponent>(); xform ??= xformQuery.Value.GetComponent(uid); var parent = xform.ParentUid; var localPos = xform.LocalPosition; var linearVelocity = component.LinearVelocity; var angularVelocity = component.AngularVelocity; Vector2 linearVelocityAngularContribution = Vector2.Zero; while (parent.IsValid()) { var parentXform = xformQuery.Value.GetComponent(parent); if (physicsQuery.Value.TryGetComponent(parent, out var body)) { angularVelocity += body.AngularVelocity; // add linear velocity of parent relative to it's own parent (again, in map coordinates) linearVelocity += body.LinearVelocity; // add the component of the linear velocity that results from the parent's rotation. This is NOT in map // coordinates, this is the velocity in the parentXform.Parent's frame. linearVelocityAngularContribution += Vector2.Cross(body.AngularVelocity, localPos - body.LocalCenter); linearVelocityAngularContribution = parentXform.LocalRotation.RotateVec(linearVelocityAngularContribution); } localPos = parentXform.LocalPosition + parentXform.LocalRotation.RotateVec(localPos); parent = parentXform.ParentUid; } return(linearVelocity + linearVelocityAngularContribution, angularVelocity); }
/// <summary> /// This is the total rate of change of the entity's map-position, resulting from the linear and angular /// velocities of this entity and any parents. /// </summary> /// <remarks> /// Use <see cref="GetMapVelocities"/> if you need linear and angular at the same time. /// </remarks> public Vector2 GetMapLinearVelocity( EntityUid uid, PhysicsComponent?component = null, TransformComponent?xform = null, EntityQuery <TransformComponent>?xformQuery = null, EntityQuery <PhysicsComponent>?physicsQuery = null) { if (!Resolve(uid, ref component)) { return(Vector2.Zero); } xformQuery ??= EntityManager.GetEntityQuery <TransformComponent>(); physicsQuery ??= EntityManager.GetEntityQuery <PhysicsComponent>(); xform ??= xformQuery.Value.GetComponent(uid); var parent = xform.ParentUid; var localPos = xform.LocalPosition; var velocity = component.LinearVelocity; Vector2 angularComponent = Vector2.Zero; while (parent.IsValid()) { var parentXform = xformQuery.Value.GetComponent(parent); if (physicsQuery.Value.TryGetComponent(parent, out var body)) { // add linear velocity of parent relative to it's own parent (again, in map coordinates) velocity += body.LinearVelocity; // add angular velocity that results from the parent's rotation (NOT in map coordinates, but in the parentXform.Parent's frame) angularComponent += Vector2.Cross(body.AngularVelocity, localPos - body.LocalCenter); angularComponent = parentXform.LocalRotation.RotateVec(angularComponent); } localPos = parentXform.LocalPosition + parentXform.LocalRotation.RotateVec(localPos); parent = parentXform.ParentUid; } // angular component of the velocity should now be in terms of map coordinates and can be added onto the sum of // linear velocities. return(velocity + angularComponent); }
/// <summary> /// Tries to toggle the anchored status of this component's owner. /// </summary> /// <returns>true if toggled, false otherwise</returns> public override void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent?anchorable = null, TransformComponent?transform = null, SharedPullableComponent?pullable = null, ToolComponent?usingTool = null) { if (!Resolve(uid, ref transform)) { return; } if (transform.Anchored) { TryUnAnchor(uid, userUid, usingUid, anchorable, transform, usingTool); } else { TryAnchor(uid, userUid, usingUid, anchorable, transform, pullable, usingTool); } }
/// <summary> /// If this node should be considered for connection by other nodes. /// </summary> public virtual bool Connectable(IEntityManager entMan, TransformComponent?xform = null) { if (Deleting) { return(false); } if (entMan.IsQueuedForDeletion(Owner)) { return(false); } if (!NeedAnchored) { return(true); } xform ??= entMan.GetComponent <TransformComponent>(Owner); return(xform.Anchored); }
private void SetEnabled(CargoTelepadComponent component, ApcPowerReceiverComponent?receiver = null, TransformComponent?xform = null) { // False due to AllCompsOneEntity test where they may not have the powerreceiver. if (!Resolve(component.Owner, ref receiver, ref xform, false)) { return; } var disabled = !receiver.Powered || !xform.Anchored; // Setting idle state should be handled by Update(); if (disabled) { return; } TryComp <AppearanceComponent>(component.Owner, out var appearance); component.CurrentState = CargoTelepadState.Unpowered; appearance?.SetData(CargoTelepadVisuals.State, CargoTelepadState.Unpowered); }
public bool IsWeightless(EntityUid uid, PhysicsComponent?body = null, TransformComponent?xform = null) { Resolve(uid, ref body, false); if ((body?.BodyType & (BodyType.Static | BodyType.Kinematic)) != 0) { return(false); } if (TryComp <MovementIgnoreGravityComponent>(uid, out var ignoreGravityComponent)) { return(ignoreGravityComponent.Weightless); } if (!Resolve(uid, ref xform)) { return(true); } // If grid / map has gravity if ((TryComp <GravityComponent>(xform.GridUid, out var gravity) || TryComp(xform.MapUid, out gravity)) && gravity.Enabled) { return(false); } // Something holding us down // If the planet has gravity component and no gravity it will still give gravity // If there's no gravity comp at all (i.e. space) then they don't work. if (gravity != null && _inventory.TryGetSlotEntity(uid, "shoes", out var ent)) { if (TryComp <MagbootsComponent>(ent, out var boots) && boots.On) { return(false); } } return(true); }
public void UpdateBounds(EntityUid uid, TransformComponent?xform = null) { var xformQuery = EntityManager.GetEntityQuery <TransformComponent>(); if (xform == null) { xformQuery.TryGetComponent(uid, out xform); } if (xform == null) { Logger.Error($"Unable to resolve transform on {EntityManager.ToPrettyString(uid)}"); DebugTools.Assert(false); return; } if (xform.Anchored || _container.IsEntityInContainer(uid, xform)) { return; } var lookup = GetLookup(uid, xform, xformQuery); if (lookup == null) { return; } var lookupXform = xformQuery.GetComponent(lookup.Owner); var coordinates = _transform.GetMoverCoordinates(xform.Coordinates, xformQuery); // If we're contained then LocalRotation should be 0 anyway. var aabb = GetAABB(xform.Owner, coordinates.Position, _transform.GetWorldRotation(xform) - _transform.GetWorldRotation(lookupXform), xform, xformQuery); // TODO: Only container children need updating so could manually do this slightly better. AddToEntityTree(lookup, xform, aabb, xformQuery); }
/// <summary> /// Retract the guardian if either the host or the guardian move away from each other. /// </summary> private void CheckGuardianMove( EntityUid hostUid, EntityUid guardianUid, GuardianHostComponent?hostComponent = null, GuardianComponent?guardianComponent = null, TransformComponent?hostXform = null, TransformComponent?guardianXform = null) { if (!Resolve(hostUid, ref hostComponent, ref hostXform) || !Resolve(guardianUid, ref guardianComponent, ref guardianXform)) { return; } if (!guardianComponent.GuardianLoose) { return; } if (!guardianXform.Coordinates.InRange(EntityManager, hostXform.Coordinates, guardianComponent.DistanceAllowed)) { RetractGuardian(hostComponent, guardianComponent); } }
public SuitSensorStatus?GetSensorState(EntityUid uid, SuitSensorComponent?sensor = null, TransformComponent?transform = null) { if (!Resolve(uid, ref sensor, ref transform)) { return(null); } // check if sensor is enabled and worn by user if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null) { return(null); } // try to get mobs id from ID slot var userName = Loc.GetString("suit-sensor-component-unknown-name"); var userJob = Loc.GetString("suit-sensor-component-unknown-job"); if (_idCardSystem.TryFindIdCard(sensor.User.Value, out var card)) { if (card.FullName != null) { userName = card.FullName; } if (card.JobTitle != null) { userJob = card.JobTitle; } } // get health mob state var isAlive = false; if (EntityManager.TryGetComponent(sensor.User.Value, out MobStateComponent? mobState)) { isAlive = mobState.IsAlive(); } // get mob total damage var totalDamage = 0; if (EntityManager.TryGetComponent(sensor.User.Value, out DamageableComponent? damageable)) { totalDamage = damageable.TotalDamage.Int(); } // finally, form suit sensor status var status = new SuitSensorStatus(userName, userJob); switch (sensor.Mode) { case SuitSensorMode.SensorBinary: status.IsAlive = isAlive; break; case SuitSensorMode.SensorVitals: status.IsAlive = isAlive; status.TotalDamage = totalDamage; break; case SuitSensorMode.SensorCords: status.IsAlive = isAlive; status.TotalDamage = totalDamage; status.Coordinates = transform.MapPosition; break; } return(status); }
private bool IsCancelled(IEntityManager entityManager) { if (!entityManager.EntityExists(EventArgs.User) || EventArgs.Target is {} target&& !entityManager.EntityExists(target)) { return(true); } //https://github.com/tgstation/tgstation/blob/1aa293ea337283a0191140a878eeba319221e5df/code/__HELPERS/mobs.dm if (EventArgs.CancelToken.IsCancellationRequested) { return(true); } // TODO :Handle inertia in space. if (EventArgs.BreakOnUserMove && !entityManager.GetComponent <TransformComponent>(EventArgs.User).Coordinates.InRange( entityManager, UserGrid, EventArgs.MovementThreshold)) { return(true); } if (EventArgs.Target != null && EventArgs.BreakOnTargetMove && !entityManager.GetComponent <TransformComponent>(EventArgs.Target !.Value).Coordinates.InRange(entityManager, TargetGrid, EventArgs.MovementThreshold)) { return(true); } if (EventArgs.ExtraCheck != null && !EventArgs.ExtraCheck.Invoke()) { return(true); } if (EventArgs.BreakOnStun && entityManager.HasComponent <StunnedComponent>(EventArgs.User)) { return(true); } if (EventArgs.NeedHand) { if (!entityManager.TryGetComponent(EventArgs.User, out HandsComponent? handsComponent)) { // If we had a hand but no longer have it that's still a paddlin' if (_activeHand != null) { return(true); } } else { var currentActiveHand = handsComponent.ActiveHand?.Name; if (_activeHand != currentActiveHand) { return(true); } var currentItem = handsComponent.ActiveHandEntity; if (_activeItem != currentItem) { return(true); } } } if (EventArgs.DistanceThreshold != null) { var xformQuery = entityManager.GetEntityQuery <TransformComponent>(); TransformComponent?userXform = null; // Check user distance to target AND used entities. if (EventArgs.Target != null && !EventArgs.User.Equals(EventArgs.Target)) { //recalculate Target location in case Target has also moved var targetCoordinates = xformQuery.GetComponent(EventArgs.Target.Value).Coordinates; userXform ??= xformQuery.GetComponent(EventArgs.User); if (!userXform.Coordinates.InRange(entityManager, targetCoordinates, EventArgs.DistanceThreshold.Value)) { return(true); } } if (EventArgs.Used != null) { var targetCoordinates = xformQuery.GetComponent(EventArgs.Used.Value).Coordinates; userXform ??= xformQuery.GetComponent(EventArgs.User); if (!userXform.Coordinates.InRange(entityManager, targetCoordinates, EventArgs.DistanceThreshold.Value)) { return(true); } } } return(false); }