/// <summary> /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// </summary> /// <param name="entity">The entity being thrown.</param> /// <param name="direction">A vector pointing from the entity to its destination.</param> /// <param name="strength">How much the direction vector should be multiplied for velocity.</param> /// <param name="user"></param> /// <param name="pushbackRatio">The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced</param> internal static void TryThrow(this EntityUid entity, Vector2 direction, float strength = 1.0f, EntityUid?user = null, float pushbackRatio = 10.0f) { var entities = IoCManager.Resolve <IEntityManager>(); if (entities.GetComponent <MetaDataComponent>(entity).EntityDeleted || strength <= 0f || !entities.TryGetComponent(entity, out PhysicsComponent? physicsComponent)) { return; } if (physicsComponent.BodyType == BodyType.Static) { Logger.Warning("Tried to throw entity {entity} but can't throw static bodies!"); return; } if (entities.HasComponent <MobStateComponent>(entity)) { Logger.Warning("Throwing not supported for mobs!"); return; } var comp = entity.EnsureComponent <ThrownItemComponent>(); if (entities.HasComponent <SharedItemComponent>(entity)) { comp.Thrower = user; // Give it a l'il spin. if (!entity.HasTag("NoSpinOnThrow")) { physicsComponent.ApplyAngularImpulse(ThrowAngularImpulse); } else if (direction != Vector2.Zero) { entities.GetComponent <TransformComponent>(entity).LocalRotation = direction.ToWorldAngle() - Math.PI; } if (user != null) { EntitySystem.Get <InteractionSystem>().ThrownInteraction(user.Value, entity); } } var impulseVector = direction.Normalized * strength * physicsComponent.Mass; physicsComponent.ApplyLinearImpulse(impulseVector); // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = (direction / strength).Length; if (time < FlyTime) { physicsComponent.BodyStatus = BodyStatus.OnGround; EntitySystem.Get <ThrownItemSystem>().LandComponent(comp); } else { physicsComponent.BodyStatus = BodyStatus.InAir; Timer.Spawn(TimeSpan.FromSeconds(time - FlyTime), () => { if (physicsComponent.Deleted) { return; } physicsComponent.BodyStatus = BodyStatus.OnGround; EntitySystem.Get <ThrownItemSystem>().LandComponent(comp); }); } // Give thrower an impulse in the other direction if (user != null && pushbackRatio > 0.0f && entities.TryGetComponent(user.Value, out IPhysBody? body)) { var msg = new ThrowPushbackAttemptEvent(); entities.EventBus.RaiseLocalEvent(body.Owner, msg); if (!msg.Cancelled) { body.ApplyLinearImpulse(-impulseVector * pushbackRatio); } } }
public async Task TagComponentTest() { var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; var server = StartServer(options); await server.WaitIdleAsync(); var sMapManager = server.ResolveDependency <IMapManager>(); var sEntityManager = server.ResolveDependency <IEntityManager>(); var sPrototypeManager = server.ResolveDependency <IPrototypeManager>(); EntityUid sTagDummy = default; TagComponent sTagComponent = null !; await server.WaitPost(() => { sMapManager.CreateNewMapEntity(MapId.Nullspace); sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace); sTagComponent = IoCManager.Resolve <IEntityManager>().GetComponent <TagComponent>(sTagDummy); }); await server.WaitAssertion(() => { // Has one tag, the starting tag Assert.That(sTagComponent.Tags.Count, Is.EqualTo(1)); sPrototypeManager.Index <TagPrototype>(StartingTag); Assert.That(sTagComponent.Tags, Contains.Item(StartingTag)); // Single Assert.True(sTagDummy.HasTag(StartingTag)); Assert.True(sTagComponent.HasTag(StartingTag)); // Any Assert.True(sTagDummy.HasAnyTag(StartingTag)); Assert.True(sTagComponent.HasAnyTag(StartingTag)); // All Assert.True(sTagDummy.HasAllTags(StartingTag)); Assert.True(sTagComponent.HasAllTags(StartingTag)); // Does not have the added tag var addedTagPrototype = sPrototypeManager.Index <TagPrototype>(AddedTag); Assert.That(sTagComponent.Tags, Does.Not.Contains(addedTagPrototype)); // Single Assert.False(sTagDummy.HasTag(AddedTag)); Assert.False(sTagComponent.HasTag(AddedTag)); // Any Assert.False(sTagDummy.HasAnyTag(AddedTag)); Assert.False(sTagComponent.HasAnyTag(AddedTag)); // All Assert.False(sTagDummy.HasAllTags(AddedTag)); Assert.False(sTagComponent.HasAllTags(AddedTag)); // Does not have the unused tag var unusedTagPrototype = sPrototypeManager.Index <TagPrototype>(UnusedTag); Assert.That(sTagComponent.Tags, Does.Not.Contains(unusedTagPrototype)); // Single Assert.False(sTagDummy.HasTag(UnusedTag)); Assert.False(sTagComponent.HasTag(UnusedTag)); // Any Assert.False(sTagDummy.HasAnyTag(UnusedTag)); Assert.False(sTagComponent.HasAnyTag(UnusedTag)); // All Assert.False(sTagDummy.HasAllTags(UnusedTag)); Assert.False(sTagComponent.HasAllTags(UnusedTag)); // Throws when checking for an unregistered tag Assert.Throws <UnknownPrototypeException>(() => { sPrototypeManager.Index <TagPrototype>(UnregisteredTag); }); // Single Assert.Throws <UnknownPrototypeException>(() => { sTagDummy.HasTag(UnregisteredTag); }); Assert.Throws <UnknownPrototypeException>(() => { sTagComponent.HasTag(UnregisteredTag); }); // Any Assert.Throws <UnknownPrototypeException>(() => { sTagDummy.HasAnyTag(UnregisteredTag); }); Assert.Throws <UnknownPrototypeException>(() => { sTagComponent.HasAnyTag(UnregisteredTag); }); // All Assert.Throws <UnknownPrototypeException>(() => { sTagDummy.HasAllTags(UnregisteredTag); }); Assert.Throws <UnknownPrototypeException>(() => { sTagComponent.HasAllTags(UnregisteredTag); }); // Cannot add the starting tag again Assert.That(sTagComponent.AddTag(StartingTag), Is.False); Assert.That(sTagComponent.AddTags(StartingTag, StartingTag), Is.False); Assert.That(sTagComponent.AddTags(new List <string> { StartingTag, StartingTag }), Is.False); // Has the starting tag Assert.That(sTagComponent.HasTag(StartingTag), Is.True); Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True); Assert.That(sTagComponent.HasAllTags(new List <string> { StartingTag, StartingTag }), Is.True); Assert.That(sTagComponent.HasAnyTag(StartingTag, StartingTag), Is.True); Assert.That(sTagComponent.HasAnyTag(new List <string> { StartingTag, StartingTag }), Is.True); // Does not have the added tag yet Assert.That(sTagComponent.HasTag(AddedTag), Is.False); Assert.That(sTagComponent.HasAllTags(AddedTag, AddedTag), Is.False); Assert.That(sTagComponent.HasAllTags(new List <string> { AddedTag, AddedTag }), Is.False); Assert.That(sTagComponent.HasAnyTag(AddedTag, AddedTag), Is.False); Assert.That(sTagComponent.HasAnyTag(new List <string> { AddedTag, AddedTag }), Is.False); // Has a combination of the two tags Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True); Assert.That(sTagComponent.HasAnyTag(new List <string> { StartingTag, AddedTag }), Is.True); // Does not have both tags Assert.That(sTagComponent.HasAllTags(StartingTag, AddedTag), Is.False); Assert.That(sTagComponent.HasAllTags(new List <string> { StartingTag, AddedTag }), Is.False); // Cannot remove a tag that does not exist Assert.That(sTagComponent.RemoveTag(AddedTag), Is.False); Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.False); Assert.That(sTagComponent.RemoveTags(new List <string> { AddedTag, AddedTag }), Is.False); // Can add the new tag Assert.That(sTagComponent.AddTag(AddedTag), Is.True); // Cannot add it twice Assert.That(sTagComponent.AddTag(AddedTag), Is.False); // Cannot add existing tags Assert.That(sTagComponent.AddTags(StartingTag, AddedTag), Is.False); Assert.That(sTagComponent.AddTags(new List <string> { StartingTag, AddedTag }), Is.False); // Now has two tags Assert.That(sTagComponent.Tags.Count, Is.EqualTo(2)); // Has both tags Assert.That(sTagComponent.HasTag(StartingTag), Is.True); Assert.That(sTagComponent.HasTag(AddedTag), Is.True); Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True); Assert.That(sTagComponent.HasAllTags(AddedTag, StartingTag), Is.True); Assert.That(sTagComponent.HasAllTags(new List <string> { StartingTag, AddedTag }), Is.True); Assert.That(sTagComponent.HasAllTags(new List <string> { AddedTag, StartingTag }), Is.True); Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True); Assert.That(sTagComponent.HasAnyTag(AddedTag, StartingTag), Is.True); // Remove the existing starting tag Assert.That(sTagComponent.RemoveTag(StartingTag), Is.True); // Remove the existing added tag Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.True); // No tags left to remove Assert.That(sTagComponent.RemoveTags(new List <string> { StartingTag, AddedTag }), Is.False); // No tags left in the component Assert.That(sTagComponent.Tags, Is.Empty); }); }