Sophisticated Tab

A simple mod which integrates Sophisticated Backpacks and Legendary Tabs for convenience; access your backpack from the inventory with the simple click of a tab, returning to your inventory the same way.

File Details

Sophisticated Tab 0.5.1 (Forge 1.20.1)

  • R
  • May 15, 2026
  • 62.52 KB
  • 76
  • 1.20.1
  • Forge

File Name

sophisticatedtab-0.5.1.jar

Supported Versions

  • 1.20.1

Curse Maven Snippet

Forge

implementation fg.deobf("curse.maven:sophisticated-tab-1540042:8090684")
Curse Maven does not yet support mods that have disabled 3rd party sharing

Learn more about Curse Maven

[1.20.1-0.5.1] - 2026-05-14

Fixed

  • Settings panel and right-click context menu no longer leak the parent inventory through their backgrounds. The v0.5.0 implementations of BackpackSettingsScreen.java and BackpackTabContextMenu.java rendered the parent screen first (correct, intentional — we want the parent dimmed behind us) and then drew the panel via GuiGraphics.fill(...) at the pose's default Z=0. Because ItemRenderer.renderGuiItem in 1.20.1 translates Z forward (slot quad +100, item model +50), every item the parent rendered lived at Z ≈ 100–150 and won the depth test against our Z=0 panel fragments. Result: backpack tabs, inventory slots, hotbar items, and any HUD-adjacent widgets (e.g. JEI's search box) stayed crisply visible inside the panel rectangle while the panel outline survived only in the gaps between items. Fix is to pose().pushPose() + translate(0, 0, 400) before drawing the dim, panel BG, widgets, and list content, then popPose() once they're all in. Z=400 also matches vanilla Screen.renderTooltipInternal's tooltip Z so our content can never sit under stale tooltip residue from the parent.

[1.20.1-0.5.0] - 2026-05-14

Added — User-configurable tab order, hiding, and settings

  • Drag-and-drop tab ordering. Left-click-hold and drag a backpack tab horizontally. The dragged backpack renders as a faded ghost at the cursor and a vertical drop indicator marks the target slot. Release commits the reorder; release without horizontal movement is treated as a normal click and opens the backpack. Threshold: 4 px / 350 ms (constants in TabInteractionHandler.java).
  • Right-click context menu on any backpack tab. Four entries: Open Backpack, Move Left, Move Right, Hide This Backpack. Move entries grey out at the row boundaries; hide greys out for UUID-less backpacks (see Design notes). Menu position auto-clamps when the anchor tab is at the right edge of the row.
  • Hide individual backpacks so they vanish from the LT row. Hidden backpacks remain in the inventory and are still openable via SB's default B keybind; only the tab is suppressed.
  • Settings screen (BackpackSettingsScreen) listing every currently carried backpack plus every saved-but-not-carried UUID. Click a carried row to toggle visibility; the screen is the escape hatch that prevents hiding every tab from trapping the user. Footer buttons: Reset Order, Reset Hidden (both two-step confirm), Clean Unused (one-shot prune of stale UUIDs), Done.
  • Gear tab on the LT row (priority 100) opens the settings screen. Reuses backpack_tab.png chrome and overlays a Items.COMPARATOR glyph so the iconography stays in line with the rest of the row.
  • Open Tab Settings keybind (default unbound — assign via Options > Controls > Sophisticated Tab). Opens the settings screen during gameplay without needing the inventory.
  • Per-profile client preferences persisted to config/sophisticatedtab/tab_preferences.json. Profile key is singleplayer:<level> for both non-LAN and LAN-hosted single-player; server:<ip> for multiplayer connections. Schema is v1, includes orderedBackpacks and hiddenBackpacks per profile. Atomic writes via temp+rename; corrupt files are renamed to tab_preferences.json.broken.<ISO-timestamp> on the next launch rather than overwritten in place.

Changed

  • BackpackTab.java now resolves its descriptor through BackpackTabResolver.java instead of calling SophisticatedBackpacksLocator.findAllBackpacks(player) directly. The resolver applies the user's hide-filter and order-sort once and produces the canonical visible list that BackpackTab(i) indexes into.
  • BackpackDescriptor.java gains a uuid() accessor delegating to wrapper.getContentsUuid(). Centralizes identity reads so the resolver, preferences model, and active-tab highlight no longer each re-derive it.
  • SophisticatedBackpacksSizing.java now sizes against the first visible backpack from the resolver instead of the first discovered. Matches what the user sees: the leftmost tab is the screen-sizing anchor even after reordering.
  • LegendaryTabsCompat.java exposes the registered BackpackTab instances via backpackTabs() so TabInteractionHandler.java can identify which TabButton on the active screen represents which logical index.

Design notes for future contributors

  • Why UUID, not slot/tier/name, as the identity anchor? Slot breaks on inventory rearrange. Tier breaks on multiple backpacks of the same tier (the common heavy-player case). Name breaks on rename and collides on identical names. IStorageWrapper.getContentsUuid() is stable across all three and was already the anchor for v0.3.0's active-tab highlight — v0.5.0 just extends it to ordering and hiding.
  • Why no item NBT mutation for hide state? Hiding is a local UI preference. Writing it to item NBT would: (a) travel with the backpack if traded, (b) require a server packet, (c) break shared worlds where multiple players see different "carrying" sets. Storing only in the client JSON keeps the contract clean.
  • Why no dynamic LegendaryTabs tab re-registration? TabsMenu.register is a one-shot at FMLClientSetupEvent. The static-pool-of-eight BackpackTab instances each resolve their descriptor at render/click time, so the perceived reorder happens entirely inside the resolver — LT priorities 20..27 never mutate.
  • UUID-less backpacks (rare; happens on freshly crafted stacks before SB writes the contents UUID) render normally but are excluded from drag-ordering and from hide persistence. The context menu greys those entries out, and the settings screen marks them with a * and a tooltip explaining the limitation. If the UUID is assigned later (e.g., on first open), the backpack rejoins the configurable pool automatically.
  • Right-click capture vs. LT's Button.onPress. LT's TabButton extends Button and treats all mouse buttons identically — onPress fires for left, right, and middle clicks the same way. To distinguish right-click without forking LT, TabInteractionHandler.java subscribes to ScreenEvent.MouseButtonPressed.Pre at EventPriority.HIGH and cancels the event before LT's widget dispatch runs. Left-clicks on our tabs are also captured so we can decide click-vs-drag on MouseButtonReleased.Pre.
  • TabButton.tabBase field access. LegendaryTabs 1.20.1 exposes the field as public TabBase tabBase. The hit-test reads it directly; if a future LT release flips it to private, the read is wrapped in try/catch and degrades to a logged warning rather than crashing.
  • Drag visual via ScreenEvent.Render.Post. We don't move the live TabButton widgets — they stay rendered at their priority-determined positions. The drag is purely a top-level overlay: faded ghost ItemStack at the cursor plus a 2 px white drop indicator between the nearest tab boundaries.
  • Preferences scope. Per-world for singleplayer (including LAN-hosted, which uses the same singleplayer:<level> key as non-LAN) and per-server for multiplayer. Cross-instance share isn't supported — each launcher profile has its own config/sophisticatedtab/.