Skip to content
This repository was archived by the owner on Sep 20, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/BazaarPlusPlus/Game/CollectionPanel/CollectionPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ internal sealed class CollectionPanel : MonoBehaviour
// instance and re-renders once, so the startup window self-heals.
private bool _viewMissedNativeTypography;
private bool _sourceCatalogWarmed;
private bool _stagingItemIdCopyEnabled;

public void Initialize(
IBppServices services,
Expand All @@ -91,6 +92,7 @@ IGameDataDayTierResolver dayTierResolver
_instance = this;
_services = services;
_config = services.Config;
_stagingItemIdCopyEnabled = CollectionStagingTools.IsEnabled(services.GameBuild.RawVersion);
_nativeCardPreviewHost = nativeCardPreviewHost;
_dayTierResolver = dayTierResolver;
_catalog = new CollectionCatalog(cardMapProvider);
Expand Down Expand Up @@ -458,10 +460,33 @@ out _
{
var pos = mouse.position.ReadValue();
_virtualizer.PollHover(pos, _viewportBoundsPx);
TryCopyHoveredCardId();
}
}
}

private void TryCopyHoveredCardId()
{
if (
!_stagingItemIdCopyEnabled
|| IsTextInputFocused()
|| _virtualizer == null
|| !_virtualizer.TryGetHoveredCard(out var card)
)
return;

var keyboard = Keyboard.current;
if (
keyboard?.cKey.wasPressedThisFrame != true
|| (keyboard.leftCtrlKey.isPressed || keyboard.rightCtrlKey.isPressed) != true
)
return;
Comment on lines +478 to +483

var templateId = card.Id.ToString("D");
GUIUtility.systemCopyBuffer = templateId;
_view?.ShowStagingTemplateIdCopied(card.DisplayName, templateId);
}

private void HideNativeCardLayerImmediately()
{
_virtualizer?.Dispose();
Expand Down Expand Up @@ -603,7 +628,11 @@ private void EnsureView()
return;
}

_view = new CollectionPanelView(transform, new PanelCommands(this));
_view = new CollectionPanelView(
transform,
new PanelCommands(this),
_stagingItemIdCopyEnabled
);

_view.GridViewportBoundsChanged += bounds =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#nullable enable

namespace BazaarPlusPlus.Game.CollectionPanel;

internal static class CollectionStagingTools
{
internal static bool IsEnabled(string? rawGameVersion) =>
rawGameVersion?.IndexOf("-staging", StringComparison.OrdinalIgnoreCase) >= 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,22 @@ public void PollHover(Vector2 mousePixels, Rect viewportBoundsPx)
}
}

internal bool TryGetHoveredCard(out CollectionCardVm card)
{
if (
_hoverDispatched
&& _hoverPollIndex >= 0
&& _realized.TryGetValue(_hoverPollIndex, out var cell)
)
{
card = cell.Vm;
return true;
}

card = null!;
return false;
}

private void DispatchHoverOut()
{
// Hide the display-case highlight on every hover-out path (outside the viewport, in a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ private void BuildOperationRail(VisualElement parent)
_subtitle = BPPSupporterAttributionRow.Create();
rail.Add(_subtitle);

if (_stagingItemIdCopyEnabled)
{
_stagingIdCopyLabel = CreateLabel(
Sizes.FontCorner,
FontStyle.Normal,
Colors.HistoryStatusText
);
_stagingIdCopyLabel.text = StagingIdCopyHint;
_stagingIdCopyLabel.style.marginTop = UiSpacing.Xs;
_stagingIdCopyLabel.style.whiteSpace = WhiteSpace.NoWrap;
_stagingIdCopyLabel.style.overflow = Overflow.Hidden;
rail.Add(_stagingIdCopyLabel);
}

var primaryControlsRow = CreateOperationRow(UiSpacing.Md);
rail.Add(primaryControlsRow);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ namespace BazaarPlusPlus.Game.CollectionPanel.Ui;

internal sealed partial class CollectionPanelView : IDisposable
{
private const string StagingIdCopyHint = "STAGING · 悬停卡牌后按 Ctrl+C 复制 template ID";
private const string SourceChipInitialsName = "bpp-source-chip-initials";
private const string TagChipIconName = "bpp-tag-chip-icon";
private const string TagChipLabelName = "bpp-tag-chip-label";

private readonly Transform _parent;
private readonly ICollectionPanelCommands _commands;
private readonly bool _stagingItemIdCopyEnabled;

private GameObject? _rootObject;
private UIDocument? _document;
Expand All @@ -29,6 +31,7 @@ internal sealed partial class CollectionPanelView : IDisposable
private VisualElement? _root;
private Label? _title;
private VisualElement? _subtitle;
private Label? _stagingIdCopyLabel;
private Label? _countLabel;
private Label? _statusLabel;
private Label? _disclaimerLabel;
Expand Down Expand Up @@ -85,6 +88,7 @@ internal sealed partial class CollectionPanelView : IDisposable
private bool _searchToggleHovered;
private bool _searchTogglePressed;
private bool _searchToggleFocused;
private int _stagingIdCopyFeedbackGeneration;

private readonly Dictionary<EHero, Button> _heroChips = new();
private readonly Dictionary<EHero, VisualElement> _heroChipIcons = new();
Expand Down Expand Up @@ -114,10 +118,31 @@ internal sealed partial class CollectionPanelView : IDisposable

public event Action<Rect>? GridViewportBoundsChanged;

public CollectionPanelView(Transform parent, ICollectionPanelCommands commands)
public CollectionPanelView(
Transform parent,
ICollectionPanelCommands commands,
bool stagingItemIdCopyEnabled = false
)
{
_parent = parent ?? throw new ArgumentNullException(nameof(parent));
_commands = commands ?? throw new ArgumentNullException(nameof(commands));
_stagingItemIdCopyEnabled = stagingItemIdCopyEnabled;
}

internal void ShowStagingTemplateIdCopied(string displayName, string templateId)
{
if (_stagingIdCopyLabel == null)
return;

var generation = ++_stagingIdCopyFeedbackGeneration;
_stagingIdCopyLabel.text = $"已复制 {displayName}: {templateId}";
_stagingIdCopyLabel
.schedule.Execute(() =>
{
if (generation == _stagingIdCopyFeedbackGeneration && _stagingIdCopyLabel != null)
_stagingIdCopyLabel.text = StagingIdCopyHint;
})
.StartingIn(2500);
}

public void EnsureCreated()
Expand Down Expand Up @@ -598,6 +623,7 @@ public float ReadScrollYPixels()

public void Dispose()
{
_stagingIdCopyFeedbackGeneration++;
_controlsDragScroller?.Dispose();
_gridDragScroller?.Dispose();
if (_rootObject != null)
Expand All @@ -612,6 +638,7 @@ public void Dispose()
_typography = null;
_titleOverlay = null;
_root = null;
_stagingIdCopyLabel = null;
_controlsScrollView = null;
_controlsDragScroller = null;
_gridDragScroller = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
</PropertyGroup>

<ItemGroup>
<Compile
Include="..\..\src\BazaarPlusPlus\Game\CollectionPanel\CollectionStagingTools.cs"
Link="CollectionStagingTools.cs"
/>
<Compile
Include="..\..\src\BazaarPlusPlus\Game\CollectionPanel\Data\CollectionCardVm.cs"
Link="CollectionCardVm.cs"
Expand Down
17 changes: 17 additions & 0 deletions tests/CollectionGridLayout.Tests/Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
using BazaarGameShared.Domain.Core.Types;
using BazaarPlusPlus.Game.CollectionPanel;
using BazaarPlusPlus.Game.CollectionPanel.Data;
using BazaarPlusPlus.Game.CollectionPanel.Grid;
using BazaarPlusPlus.Game.CollectionPanel.Tooltips;

AssertEqual(
true,
CollectionStagingTools.IsEnabled("1.0.11884-staging-windows-x64-0fff95cf"),
"Staging builds should expose the collection template-ID copy tool."
);
AssertEqual(
false,
CollectionStagingTools.IsEnabled("1.0.11884-windows-x64-0fff95cf"),
"Online builds must not expose the collection template-ID copy tool."
);
AssertEqual(
false,
CollectionStagingTools.IsEnabled("1.0.11884-ptr-windows-x64-0fff95cf"),
"PTR builds must not expose the collection template-ID copy tool."
);

var mergedTierText = CollectionTierTooltipTextMerger.Merge(
new[]
{
Expand Down