/// <summary> /// Inserts storable entities into this storage container if possible, otherwise return to the hand of the user /// </summary> /// <returns>true if inserted, false otherwise</returns> private void OnInteractUsing(EntityUid uid, ServerStorageComponent storageComp, InteractUsingEvent args) { if (args.Handled) { return; } if (!storageComp.ClickInsert) { return; } if (TryComp(uid, out LockComponent? lockComponent) && lockComponent.Locked) { return; } Logger.DebugS(storageComp.LoggerName, $"Storage (UID {uid}) attacked by user (UID {args.User}) with entity (UID {args.Used})."); if (HasComp <PlaceableSurfaceComponent>(uid)) { return; } if (PlayerInsertHeldEntity(uid, args.User, storageComp)) { args.Handled = true; } }
private void AddTransferVerbs(EntityUid uid, ServerStorageComponent component, GetVerbsEvent <UtilityVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } var entities = component.Storage?.ContainedEntities; if (entities == null || entities.Count == 0) { return; } if (TryComp(uid, out LockComponent? lockComponent) && lockComponent.Locked) { return; } // if the target is storage, add a verb to transfer storage. if (TryComp(args.Target, out ServerStorageComponent? targetStorage) && (!TryComp(uid, out LockComponent? targetLock) || !targetLock.Locked)) { UtilityVerb verb = new() { Text = Loc.GetString("storage-component-transfer-verb"), IconEntity = args.Using, Act = () => TransferEntities(uid, args.Target, component, lockComponent, targetStorage, targetLock) }; args.Verbs.Add(verb); } }
private void OnBoundUIOpen(EntityUid uid, ServerStorageComponent storageComp, BoundUIOpenedEvent args) { if (!storageComp.IsOpen) { storageComp.IsOpen = true; UpdateStorageVisualization(uid, storageComp); } }
private void Popup(EntityUid uid, EntityUid player, string message, ServerStorageComponent storageComp) { if (!storageComp.ShowPopup) { return; } _popupSystem.PopupEntity(Loc.GetString(message), player, Filter.Entities(player)); }
private void OnInsertItemMessage(EntityUid uid, ServerStorageComponent storageComp, StorageInsertItemMessage args) { // TODO move this to shared for prediction. if (args.Session.AttachedEntity == null) { return; } PlayerInsertHeldEntity(uid, args.Session.AttachedEntity.Value, storageComp); }
private void OnComponentInit(EntityUid uid, ServerStorageComponent storageComp, ComponentInit args) { base.Initialize(); // ReSharper disable once StringLiteralTypo storageComp.Storage = _containerSystem.EnsureContainer <Container>(uid, "storagebase"); storageComp.Storage.OccludesLight = storageComp.OccludesLight; UpdateStorageVisualization(uid, storageComp); RecalculateStorageUsed(storageComp); UpdateStorageUI(uid, storageComp); }
private void UpdateStorageUI(EntityUid uid, ServerStorageComponent storageComp) { if (storageComp.Storage == null) { return; } var state = new StorageBoundUserInterfaceState((List <EntityUid>)storageComp.Storage.ContainedEntities, storageComp.StorageUsed, storageComp.StorageCapacityMax); _uiSystem.GetUiOrNull(uid, StorageUiKey.Key)?.SetState(state); }
public override void Initialize() { base.Initialize(); Contents = ContainerManagerComponent.Ensure <Container>($"{typeof(EntityStorageComponent).FullName}{Owner.Uid.ToString()}", Owner); if (!Owner.TryGetComponent(out StorageComponent)) { StorageComponent = Owner.AddComponent <ServerStorageComponent>(); // TODO: This is a terrible hack. // Components should not need to be manually initialized in Initialize(). StorageComponent.Initialize(); } entityQuery = new IntersectingEntityQuery(Owner); }
private void OnDestroy(EntityUid uid, ServerStorageComponent storageComp, DestructionEventArgs args) { var storedEntities = storageComp.StoredEntities?.ToList(); if (storedEntities == null) { return; } foreach (var entity in storedEntities) { RemoveAndDrop(uid, entity, storageComp); } }
/// <summary> /// Sends a message to open the storage UI /// </summary> /// <returns></returns> private void OnActivate(EntityUid uid, ServerStorageComponent storageComp, ActivateInWorldEvent args) { if (!TryComp <ActorComponent>(args.User, out var actor)) { return; } if (TryComp(uid, out LockComponent? lockComponent) && lockComponent.Locked) { return; } OpenStorageUI(uid, args.User, storageComp); }
private void UpdateStorageVisualization(EntityUid uid, ServerStorageComponent storageComp) { if (!TryComp <AppearanceComponent>(uid, out var appearance)) { return; } appearance.SetData(StorageVisuals.Open, storageComp.IsOpen); appearance.SetData(SharedBagOpenVisuals.BagState, storageComp.IsOpen ? SharedBagState.Open : SharedBagState.Closed); if (HasComp <ItemCounterComponent>(uid)) { appearance.SetData(StackVisuals.Hide, !storageComp.IsOpen); } }
private void OnBoundUIClosed(EntityUid uid, ServerStorageComponent storageComp, BoundUIClosedEvent args) { if (TryComp <ActorComponent>(args.Session.AttachedEntity, out var actor) && actor?.PlayerSession != null) { CloseNestedInterfaces(uid, actor.PlayerSession, storageComp); } // If UI is closed for everyone if (!_uiSystem.IsUiOpen(uid, args.UiKey)) { storageComp.IsOpen = false; UpdateStorageVisualization(uid, storageComp); if (storageComp.StorageCloseSound is not null) { SoundSystem.Play(storageComp.StorageCloseSound.GetSound(), Filter.Pvs(uid, entityManager: EntityManager), uid, storageComp.StorageCloseSound.Params); } } }
/// <summary> /// This function gets called when the user clicked on an item in the storage UI. This will either place the /// item in the user's hand if it is currently empty, or interact with the item using the user's currently /// held item. /// </summary> private void OnInteractWithItem(EntityUid uid, ServerStorageComponent storageComp, StorageInteractWithItemEvent args) { // TODO move this to shared for prediction. if (args.Session.AttachedEntity is not EntityUid player) { return; } if (!_actionBlockerSystem.CanInteract(player, args.InteractedItemUID)) { return; } if (storageComp.Storage == null || !storageComp.Storage.Contains(args.InteractedItemUID)) { return; } // Does the player have hands? if (!TryComp(player, out HandsComponent? hands) || hands.Count == 0) { return; } // If the user's active hand is empty, try pick up the item. if (hands.ActiveHandEntity == null) { if (_sharedHandsSystem.TryPickupAnyHand(player, args.InteractedItemUID, handsComp: hands) && storageComp.StorageRemoveSound != null) { SoundSystem.Play(storageComp.StorageRemoveSound.GetSound(), Filter.Pvs(uid, entityManager: EntityManager), uid, AudioParams.Default); } return; } // Else, interact using the held item _interactionSystem.InteractUsing(player, hands.ActiveHandEntity.Value, args.InteractedItemUID, Transform(args.InteractedItemUID).Coordinates, checkCanInteract: false); }
private void RecalculateStorageUsed(ServerStorageComponent storageComp) { storageComp.StorageUsed = 0; storageComp.SizeCache.Clear(); if (storageComp.Storage == null) { return; } var itemQuery = GetEntityQuery <ItemComponent>(); foreach (var entity in storageComp.Storage.ContainedEntities) { if (!itemQuery.TryGetComponent(entity, out var itemComp)) { continue; } storageComp.StorageUsed += itemComp.Size; storageComp.SizeCache.Add(entity, itemComp.Size); } }
private void CheckSubscribedEntities(ServerStorageComponent storageComp) { // We have to cache the set of sessions because Unsubscribe modifies the original. _sessionCache.Clear(); _sessionCache.AddRange(storageComp.SubscribedSessions); if (_sessionCache.Count == 0) { return; } var storagePos = storageComp.Owner.Transform.WorldPosition; var storageMap = storageComp.Owner.Transform.MapID; foreach (var session in _sessionCache) { var attachedEntity = session.AttachedEntity; // The component manages the set of sessions, so this invalid session should be removed soon. if (attachedEntity == null || !attachedEntity.IsValid()) { continue; } if (storageMap != attachedEntity.Transform.MapID) { continue; } var distanceSquared = (storagePos - attachedEntity.Transform.WorldPosition).LengthSquared; if (distanceSquared > InteractionSystem.InteractionRangeSquared) { storageComp.UnsubscribeSession(session); } } }
private void AddOpenUiVerb(EntityUid uid, ServerStorageComponent component, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } if (TryComp <LockComponent>(uid, out var lockComponent) && lockComponent.Locked) { return; } // Get the session for the user if (!TryComp <ActorComponent>(args.User, out var actor) || actor?.PlayerSession == null) { return; } // Does this player currently have the storage UI open? bool uiOpen = _uiSystem.SessionHasOpenUi(uid, StorageUiKey.Key, actor.PlayerSession); ActivationVerb verb = new(); verb.Act = () => OpenStorageUI(uid, args.User, component); if (uiOpen) { verb.Text = Loc.GetString("verb-common-close-ui"); verb.IconTexture = "/Textures/Interface/VerbIcons/close.svg.192dpi.png"; } else { verb.Text = Loc.GetString("verb-common-open-ui"); verb.IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png"; } args.Verbs.Add(verb); }
/// <summary> /// Allows a user to pick up entities by clicking them, or pick up all entities in a certain radius /// around a click. /// </summary> /// <returns></returns> private async void AfterInteract(EntityUid uid, ServerStorageComponent storageComp, AfterInteractEvent eventArgs) { if (!eventArgs.CanReach) { return; } if (storageComp.CancelToken != null) { storageComp.CancelToken.Cancel(); storageComp.CancelToken = null; return; } // Pick up all entities in a radius around the clicked location. // The last half of the if is because carpets exist and this is terrible if (storageComp.AreaInsert && (eventArgs.Target == null || !HasComp <ItemComponent>(eventArgs.Target.Value))) { var validStorables = new List <EntityUid>(); foreach (var entity in _entityLookupSystem.GetEntitiesInRange(eventArgs.ClickLocation, storageComp.AreaInsertRadius, LookupFlags.None)) { if (entity == eventArgs.User || !HasComp <ItemComponent>(entity) || !_interactionSystem.InRangeUnobstructed(eventArgs.User, entity)) { continue; } validStorables.Add(entity); } //If there's only one then let's be generous if (validStorables.Count > 1) { storageComp.CancelToken = new CancellationTokenSource(); var doAfterArgs = new DoAfterEventArgs(eventArgs.User, 0.2f * validStorables.Count, storageComp.CancelToken.Token, uid) { BreakOnStun = true, BreakOnDamage = true, BreakOnUserMove = true, NeedHand = true, }; await _doAfterSystem.WaitDoAfter(doAfterArgs); } // TODO: Make it use the event DoAfter var successfullyInserted = new List <EntityUid>(); var successfullyInsertedPositions = new List <EntityCoordinates>(); foreach (var entity in validStorables) { // Check again, situation may have changed for some entities, but we'll still pick up any that are valid if (_containerSystem.IsEntityInContainer(entity) || entity == eventArgs.User || !HasComp <ItemComponent>(entity)) { continue; } if (TryComp <TransformComponent>(uid, out var transformOwner) && TryComp <TransformComponent>(entity, out var transformEnt)) { var position = EntityCoordinates.FromMap(transformOwner.Parent?.Owner ?? uid, transformEnt.MapPosition); if (PlayerInsertEntityInWorld(uid, eventArgs.User, entity, storageComp)) { successfullyInserted.Add(entity); successfullyInsertedPositions.Add(position); } } } // If we picked up atleast one thing, play a sound and do a cool animation! if (successfullyInserted.Count > 0) { if (storageComp.StorageInsertSound is not null) { SoundSystem.Play(storageComp.StorageInsertSound.GetSound(), Filter.Pvs(uid, entityManager: EntityManager), uid, AudioParams.Default); } RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(uid, successfullyInserted, successfullyInsertedPositions)); } return; } // Pick up the clicked entity else if (storageComp.QuickInsert) { if (eventArgs.Target is not { Valid : true } target) { return; } if (_containerSystem.IsEntityInContainer(target) || target == eventArgs.User || !HasComp <ItemComponent>(target)) { return; } if (TryComp <TransformComponent>(uid, out var transformOwner) && TryComp <TransformComponent>(target, out var transformEnt)) { var parent = transformOwner.ParentUid; var position = EntityCoordinates.FromMap( parent.IsValid() ? parent : uid, transformEnt.MapPosition); if (PlayerInsertEntityInWorld(uid, eventArgs.User, target, storageComp)) { RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(uid, new List <EntityUid> { target }, new List <EntityCoordinates> { position })); } } } return; }
private void OnStorageItemRemoved(EntityUid uid, ServerStorageComponent storageComp, EntRemovedFromContainerMessage args) { RecalculateStorageUsed(storageComp); UpdateStorageUI(uid, storageComp); }
private void StartDoAfter(EntityUid storageUid, EntityUid?targetUid, EntityUid userUid, DumpableComponent dumpable, ServerStorageComponent storage, float multiplier = 1) { if (dumpable.CancelToken != null) { dumpable.CancelToken.Cancel(); dumpable.CancelToken = null; return; } if (storage.StoredEntities == null) { return; } float delay = storage.StoredEntities.Count * (float)dumpable.DelayPerItem.TotalSeconds * multiplier; dumpable.CancelToken = new CancellationTokenSource(); _doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, delay, dumpable.CancelToken.Token, target: targetUid) { BroadcastFinishedEvent = new DumpCompletedEvent(userUid, targetUid, storage.StoredEntities), BroadcastCancelledEvent = new DumpCancelledEvent(dumpable.Owner), BreakOnTargetMove = true, BreakOnUserMove = true, BreakOnStun = true, NeedHand = true }); }