public async Task GrantsAndRevokesItemActions() { var serverOptions = new ServerIntegrationOptions { ExtraPrototypes = PROTOTYPES }; var clientOptions = new ClientIntegrationOptions { ExtraPrototypes = PROTOTYPES }; var(client, server) = await StartConnectedServerClientPair(serverOptions : serverOptions, clientOptions : clientOptions); await server.WaitIdleAsync(); await client.WaitIdleAsync(); var serverPlayerManager = server.ResolveDependency <Robust.Server.Interfaces.Player.IPlayerManager>(); var serverEntManager = server.ResolveDependency <IEntityManager>(); var serverGameTiming = server.ResolveDependency <IGameTiming>(); var cooldown = Cooldowns.SecondsFromNow(30, serverGameTiming); ServerActionsComponent serverActionsComponent = null; ClientActionsComponent clientActionsComponent = null; IEntity serverPlayerEnt = null; IEntity serverFlashlight = null; await server.WaitAssertion(() => { serverPlayerEnt = serverPlayerManager.GetAllPlayers().Single().AttachedEntity; serverActionsComponent = serverPlayerEnt.GetComponent <ServerActionsComponent>(); // spawn and give them an item that has actions serverFlashlight = serverEntManager.SpawnEntity("TestFlashlight", new EntityCoordinates(new EntityUid(1), (0, 0))); Assert.That(serverFlashlight.TryGetComponent <ItemActionsComponent>(out var itemActions)); // we expect this only to have a toggle light action initially var actionConfigs = itemActions.ActionConfigs.ToList(); Assert.That(actionConfigs.Count == 1); Assert.That(actionConfigs[0].ActionType == ItemActionType.ToggleLight); Assert.That(actionConfigs[0].Enabled); // grant an extra item action, before pickup, initially disabled itemActions.GrantOrUpdate(ItemActionType.DebugToggle, false); serverPlayerEnt.GetComponent <HandsComponent>().PutInHand(serverFlashlight.GetComponent <ItemComponent>(), false); // grant an extra item action, after pickup, with a cooldown itemActions.GrantOrUpdate(ItemActionType.DebugInstant, cooldown: cooldown); Assert.That(serverActionsComponent.TryGetItemActionStates(serverFlashlight.Uid, out var state)); // they should have been granted all 3 actions Assert.That(state.Count == 3); Assert.That(state.TryGetValue(ItemActionType.ToggleLight, out var toggleLightState)); Assert.That(toggleLightState.Equals(new ActionState(true))); Assert.That(state.TryGetValue(ItemActionType.DebugInstant, out var debugInstantState)); Assert.That(debugInstantState.Equals(new ActionState(true, cooldown: cooldown))); Assert.That(state.TryGetValue(ItemActionType.DebugToggle, out var debugToggleState)); Assert.That(debugToggleState.Equals(new ActionState(false))); }); await server.WaitRunTicks(5); await client.WaitRunTicks(5); // check that client has the actions, and toggle the light on via the action slot it was auto-assigned to var clientPlayerMgr = client.ResolveDependency <IPlayerManager>(); var clientUIMgr = client.ResolveDependency <IUserInterfaceManager>(); var clientEntMgr = client.ResolveDependency <IEntityManager>(); EntityUid clientFlashlight = default; await client.WaitAssertion(() => { var local = clientPlayerMgr.LocalPlayer; var controlled = local.ControlledEntity; clientActionsComponent = controlled.GetComponent <ClientActionsComponent>(); var lightEntry = clientActionsComponent.ItemActionStates() .Where(entry => entry.Value.ContainsKey(ItemActionType.ToggleLight)) .FirstOrNull(); clientFlashlight = lightEntry.Value.Key; Assert.That(lightEntry, Is.Not.Null); Assert.That(lightEntry.Value.Value.TryGetValue(ItemActionType.ToggleLight, out var lightState)); Assert.That(lightState.Equals(new ActionState(true))); Assert.That(lightEntry.Value.Value.TryGetValue(ItemActionType.DebugInstant, out var debugInstantState)); Assert.That(debugInstantState.Equals(new ActionState(true, cooldown: cooldown))); Assert.That(lightEntry.Value.Value.TryGetValue(ItemActionType.DebugToggle, out var debugToggleState)); Assert.That(debugToggleState.Equals(new ActionState(false))); var actionsUI = clientUIMgr.StateRoot.Children.FirstOrDefault(c => c is ActionsUI) as ActionsUI; Assert.That(actionsUI, Is.Not.Null); var toggleLightSlot = actionsUI.Slots.FirstOrDefault(slot => slot.Action is ItemActionPrototype { ActionType: ItemActionType.ToggleLight }); Assert.That(toggleLightSlot, Is.Not.Null); clientActionsComponent.AttemptAction(toggleLightSlot); });
public ActionMenu(ClientActionsComponent actionsComponent, ActionsUI actionsUI) { _actionsComponent = actionsComponent; _actionsUI = actionsUI; _actionManager = IoCManager.Resolve <ActionManager>(); _gameHud = IoCManager.Resolve <IGameHud>(); Title = Loc.GetString("Actions"); CustomMinimumSize = (300, 300); Contents.AddChild(new VBoxContainer { Children = { new HBoxContainer { Children = { (_searchBar = new LineEdit { StyleClasses ={ StyleNano.StyleClassActionSearchBox }, SizeFlagsHorizontal = SizeFlags.FillExpand, PlaceHolder = Loc.GetString("Search") }), (_filterButton = new MultiselectOptionButton <string>() { Label = Loc.GetString("Filter") }), } }, (_clearButton = new Button { Text = Loc.GetString("Clear"), }), (_filterLabel = new Label()), new ScrollContainer { //TODO: needed? CustomMinimumSize = new Vector2(200.0f, 0.0f), SizeFlagsVertical = SizeFlags.FillExpand, SizeFlagsHorizontal = SizeFlags.FillExpand, Children = { (_resultsGrid = new GridContainer { MaxWidth = 300 }) } } } }); // populate filters from search tags var filterTags = new List <string>(); foreach (var action in _actionManager.EnumerateActions()) { filterTags.AddRange(action.Filters); } // special one to filter to only include item actions filterTags.Add(ItemTag); filterTags.Add(NotItemTag); filterTags.Add(InstantActionTag); filterTags.Add(ToggleActionTag); filterTags.Add(TargetActionTag); filterTags.Add(AllActionsTag); filterTags.Add(GrantedActionsTag); foreach (var tag in filterTags.Distinct().OrderBy(tag => tag)) { _filterButton.AddItem(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(tag), tag); } UpdateFilterLabel(); _dragShadow = new TextureRect { CustomMinimumSize = (64, 64), Stretch = TextureRect.StretchMode.Scale, Visible = false }; UserInterfaceManager.PopupRoot.AddChild(_dragShadow); LayoutContainer.SetSize(_dragShadow, (64, 64)); _dragDropHelper = new DragDropHelper <ActionMenuItem>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag); }
public ActionsUI(ClientActionsComponent actionsComponent) { _actionsComponent = actionsComponent; _actionManager = IoCManager.Resolve <ActionManager>(); _entityManager = IoCManager.Resolve <IEntityManager>(); _gameTiming = IoCManager.Resolve <IGameTiming>(); _gameHud = IoCManager.Resolve <IGameHud>(); _menu = new ActionMenu(_actionsComponent, this); LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.End); LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End); LayoutContainer.SetAnchorTop(this, 0f); LayoutContainer.SetAnchorBottom(this, 0.8f); LayoutContainer.SetMarginLeft(this, 13); LayoutContainer.SetMarginTop(this, 110); SizeFlagsHorizontal = SizeFlags.None; SizeFlagsVertical = SizeFlags.FillExpand; var resourceCache = IoCManager.Resolve <IResourceCache>(); // everything needs to go within an inner panel container so the panel resizes to fit the elements. // Because ActionsUI is being anchored by layoutcontainer, the hotbar backing would appear too tall // if ActionsUI was the panel container var panelContainer = new PanelContainer() { StyleClasses = { StyleNano.StyleClassHotbarPanel }, SizeFlagsHorizontal = SizeFlags.None, SizeFlagsVertical = SizeFlags.None }; AddChild(panelContainer); var hotbarContainer = new VBoxContainer { SeparationOverride = 3, SizeFlagsHorizontal = SizeFlags.None }; panelContainer.AddChild(hotbarContainer); var settingsContainer = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.FillExpand }; hotbarContainer.AddChild(settingsContainer); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); _lockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock.svg.192dpi.png"); _unlockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock_open.svg.192dpi.png"); _lockButton = new TextureButton { TextureNormal = _unlockTexture, SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, SizeFlagsStretchRatio = 1, Scale = (0.5f, 0.5f) }; settingsContainer.AddChild(_lockButton); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); _settingsButton = new TextureButton { TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/gear.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, SizeFlagsStretchRatio = 1, Scale = (0.5f, 0.5f) }; settingsContainer.AddChild(_settingsButton); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); // this allows a 2 column layout if window gets too small _slotContainer = new GridContainer { MaxHeight = CalcMaxHeight() }; hotbarContainer.AddChild(_slotContainer); _loadoutContainer = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.FillExpand, MouseFilter = MouseFilterMode.Stop }; hotbarContainer.AddChild(_loadoutContainer); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); var previousHotbarIcon = new TextureRect() { Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, SizeFlagsStretchRatio = 1, TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(previousHotbarIcon); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); _loadoutNumber = new Label { Text = "1", SizeFlagsStretchRatio = 1 }; _loadoutContainer.AddChild(_loadoutNumber); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); var nextHotbarIcon = new TextureRect { Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, SizeFlagsStretchRatio = 1, TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(nextHotbarIcon); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); _slots = new ActionSlot[ClientActionsComponent.Slots]; _dragShadow = new TextureRect { CustomMinimumSize = (64, 64), Stretch = TextureRect.StretchMode.Scale, Visible = false }; UserInterfaceManager.PopupRoot.AddChild(_dragShadow); LayoutContainer.SetSize(_dragShadow, (64, 64)); for (byte i = 0; i < ClientActionsComponent.Slots; i++) { var slot = new ActionSlot(this, _menu, actionsComponent, i); _slotContainer.AddChild(slot); _slots[i] = slot; } DragDropHelper = new DragDropHelper <ActionSlot>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag); }
public ActionsUI(ClientActionsComponent actionsComponent) { SetValue(LayoutContainer.DebugProperty, true); _actionsComponent = actionsComponent; _actionManager = IoCManager.Resolve <ActionManager>(); _entityManager = IoCManager.Resolve <IEntityManager>(); _gameTiming = IoCManager.Resolve <IGameTiming>(); _gameHud = IoCManager.Resolve <IGameHud>(); _menu = new ActionMenu(_actionsComponent, this); LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.End); LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Constrain); LayoutContainer.SetAnchorTop(this, 0f); LayoutContainer.SetAnchorBottom(this, 0.8f); LayoutContainer.SetMarginLeft(this, 13); LayoutContainer.SetMarginTop(this, 110); HorizontalAlignment = HAlignment.Left; VerticalExpand = true; var resourceCache = IoCManager.Resolve <IResourceCache>(); // everything needs to go within an inner panel container so the panel resizes to fit the elements. // Because ActionsUI is being anchored by layoutcontainer, the hotbar backing would appear too tall // if ActionsUI was the panel container var panelContainer = new PanelContainer() { StyleClasses = { StyleNano.StyleClassHotbarPanel }, HorizontalAlignment = HAlignment.Left, VerticalAlignment = VAlignment.Top }; AddChild(panelContainer); var hotbarContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, SeparationOverride = 3, HorizontalAlignment = HAlignment.Left }; panelContainer.AddChild(hotbarContainer); var settingsContainer = new BoxContainer { Orientation = LayoutOrientation.Horizontal, HorizontalExpand = true }; hotbarContainer.AddChild(settingsContainer); settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 }); _lockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock.svg.192dpi.png"); _unlockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock_open.svg.192dpi.png"); _lockButton = new TextureButton { TextureNormal = _unlockTexture, HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center, SizeFlagsStretchRatio = 1, Scale = (0.5f, 0.5f), ToolTip = Loc.GetString("ui-actionsui-function-lock-action-slots"), TooltipDelay = CustomTooltipDelay }; settingsContainer.AddChild(_lockButton); settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 }); _settingsButton = new TextureButton { TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/gear.svg.192dpi.png"), HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center, SizeFlagsStretchRatio = 1, Scale = (0.5f, 0.5f), ToolTip = Loc.GetString("ui-actionsui-function-open-abilities-menu"), TooltipDelay = CustomTooltipDelay }; settingsContainer.AddChild(_settingsButton); settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 }); // this allows a 2 column layout if window gets too small _slotContainer = new GridContainer { MaxGridHeight = CalcMaxHeight() }; hotbarContainer.AddChild(_slotContainer); _loadoutContainer = new BoxContainer { Orientation = LayoutOrientation.Horizontal, HorizontalExpand = true, MouseFilter = MouseFilterMode.Stop }; hotbarContainer.AddChild(_loadoutContainer); _loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 }); var previousHotbarIcon = new TextureRect() { Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.192dpi.png"), HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center, SizeFlagsStretchRatio = 1, TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(previousHotbarIcon); _loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 }); _loadoutNumber = new Label { Text = "1", SizeFlagsStretchRatio = 1 }; _loadoutContainer.AddChild(_loadoutNumber); _loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 }); var nextHotbarIcon = new TextureRect { Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.192dpi.png"), HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center, SizeFlagsStretchRatio = 1, TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(nextHotbarIcon); _loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 }); _slots = new ActionSlot[ClientActionsComponent.Slots]; _dragShadow = new TextureRect { MinSize = (64, 64), Stretch = TextureRect.StretchMode.Scale, Visible = false, SetSize = (64, 64) }; UserInterfaceManager.PopupRoot.AddChild(_dragShadow); for (byte i = 0; i < ClientActionsComponent.Slots; i++) { var slot = new ActionSlot(this, _menu, actionsComponent, i); _slotContainer.AddChild(slot); _slots[i] = slot; } DragDropHelper = new DragDropHelper <ActionSlot>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag); MinSize = (10, 400); }