Skip to content

Feature/player trading via player list button - #918

Open
absol89 wants to merge 22 commits into
tiltedphoques:devfrom
absol89:codex/player-trading
Open

absol89 wants to merge 22 commits into
tiltedphoques:devfrom
absol89:codex/player-trading

Conversation

@absol89

@absol89 absol89 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

First draft, it adds a scrollable list of traded item offers, with unable to trade equipped items, and category sorting.

Some of these can probably be removed, or the window can be set to be a certain size, or to filter out weird IDs...

image

Credits to Codex and Jacobwasbeast for pioneering the trade view. This beats skse trading by having these things:

  1. Consent, players can't just barter with other players with skse mods and steal their stuff for money
  2. no skse need.
  3. The UI is in CEF so it can be modified to any maintainer's liking probably.
  4. remote trading, you dont have to physically find a player or be in a party with them to find them to trade. Just ui.

Tested on 1.7.104 on a laptop. Known issues which needs review comment. I fixed how the original canceled on F2.

Logs from the final test on 1.6.1170 build
STServerOut.log
tp_client_instance_2.log
cef_debug.log
tp_client.log

absol89 and others added 2 commits October 6, 2026 19:24
Add trading invitations, inventory offers, confirmation countdowns, and cancellation through the existing client overlay and server inventory services. Validate offers against canonical server inventories and prepare both sides atomically before sending ownership-checked inventory changes. Integrate native events with the existing UI lifecycle, fonts, notifications, and view store; add C++ and UI regression tests. Correct the TiltedCore v0.2.9 ref required by the existing build.

Adapted from Jacobwasbeast/TiltedEvolution trading implementation; isolated on upstream master without validation-only runtime, quest, animation, or item-drop changes.

Co-authored-by: Jacobwasbeast <jacobwasbeast@outlook.com>
Classify native forms into weapons, armor, ammo, potions, poisons, scrolls, food, ingredients, books, keys, soul gems, and misc. Add accessible category buttons with All as the default and keep broad Skyrim grouping for ammo, poison, and soul-gem subcategories. Filtering preserves offers and native inventory indices, survives state updates, and resets between trades. No server protocol changes.

Validation: production UI build and full release client/launcher link passed; nine UI tests passed, including category filtering and hidden-offer preservation. Native category behavior still needs in-game validation.
@absol89
absol89 marked this pull request as draft October 6, 2026 19:36
absol89 added 11 commits October 6, 2026 21:37
Merge ammo into Weapons and soul gems into Misc/Gems, shorten Apparel, enlarge the viewport layout, and follow the global STR text setting. Place Ready/Cancel Ready and Cancel Trade between full-height offer panes using the inventory scrollbar width. Remove redundant Close and Escape cancellation. Keep active sessions and the trade view when F2 hides the overlay; native state updates no longer force navigation, and the Trade menu restores an exchange after visiting other screens.

Validation: production Angular build and ten UI tests passed. Browser preview verified single-line category buttons at 1366x768 and 1920x1080, normal and XL STR text, matching offer/inventory scrollbar widths, centered controls, viewport fit, and trade persistence across F2 toggles. Downgrade changes remain in a separate local stash.
Add a search input beside Your inventory, combining category selection with case- and accent-insensitive Unicode partial-word matching. Reset search between sessions while preserving offers and native indices. Arrange each row as minus, actual quantity, plus, Clear, Max, and remove the duplicate gold-only maximum action.

Validation: twelve UI behavior tests and production Angular build passed. Browser preview verified search placement and single-line quantity controls at 1366x768 normal text and 1920x1080 XL text, plus accented partial-name filtering. Runtime downgrade changes remain stashed and excluded.
Use fixed, font-scaled grid columns for minus, quantity, plus, Clear and Max. Share the step-column width, gap and cell padding with the Offered heading so its left edge matches the quantity input at every STR text size.

Validation: production Angular build passed. Rendered alignment measured at 1366 and 1920 viewport widths for 10, 12, 16, 20 and 26px STR text; every row aligned within 0.02px.
Initialize Ready to false in an explicit noexcept constructor instead of a nested default member initializer. This avoids the GCC 13 type-trait error reported while instantiating the server trade-session map, without changing default readiness or the session layout.

Validation: Windows release server build passed; C++ tests passed 69 assertions in eight cases. A full Linux build remains to be rerun in CI; no Linux/GCC environment is installed locally.
Dock the trade panel to the right of the existing F2 controls/chat, remove the trade popup's full-screen input blocker, and keep chat/menu undimmed. Constrain the popup wrapper to the dock and wrap the left menu to avoid overlap. Left-align Available amounts with their heading and add spacing before Offered.

Validation: production Angular build and twelve UI tests passed. Browser preview confirmed chat remained clickable and a message could be sent with trading open at 1280x720, 1920x1080, and XL text. Available alignment measured across XS through XL and small/large quantities. UI and build commits are separate from the pre-existing runtime downgrade.
Hide quest-flagged inventory entries and Skyrim's internal unarmed form 000001F4 without renumbering native inventory indices. Reject these entries in shared server-side offer validation and omit hidden entries from outgoing UI selections. Preserve other unnamed entries pending identification.

Validation: production UI and Windows server builds passed; thirteen UI tests passed; C++ tests passed 77 assertions. Regression cases cover hiding protected items, preserving native indices and other offers, rejecting the unarmed form, and denying an outgoing offer with a falsified quest flag against a quest-flagged canonical entry.
Render trading directly in a fixed right-hand dock instead of the generic popup frame. Bound the panel and its flex/grid children, use fixed inventory columns, and wrap long item and offer names so intrinsic content cannot enlarge the window beyond the viewport. Preserve left-side chat hit testing and font-scaled quantity controls.

Validation: production Angular build and thirteen UI tests passed. Browser tests exercised 1366 and 1920 widths at all five STR text sizes with long unbroken names and maximum integer quantities. Panel and Max buttons remained inside the screen, and chat stayed clickable.
Use five evenly spaced menu columns so Settings and other actions keep their positions at every STR text size. Center labels within their own buttons and take ornament arrows out of normal text flow. Share the right/bottom dock gap and set explicit viewport-based panel dimensions independent of content width.

Validation: production Angular build and thirteen UI tests passed. Browser checks at 1366 and 1920 widths across XS through XL confirmed a single row of equal-width menu buttons, matching right/bottom trade margins, and clickable chat. Multi-word labels may wrap inside their fixed column.
@absol89
absol89 marked this pull request as ready for review October 6, 2026 22:49
absol89 and others added 9 commits October 7, 2026 10:15
…emp IDs

Poisons are recreated through the engine's AddPoison call instead of
AddPotion, effects keep the sender's order (recipe comparison is now
order-insensitive), and the trade UI lists each crafted potion's
temporary ID alongside its effects.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit 2129565)
Each client hides partner items whose plugin forms or crafted effects it
cannot load, and its Ready request lists the partner items it accepts.
The server transfers only accepted items; the rest stay with their owner,
and senders see which of their offered items the partner cannot receive.
Crafted enchanted gear trades when its enchantment effects resolve.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit 8343e6f)
Applied crafted poisons now carry their recipe in the inventory entry and
compare by recipe instead of temporary ID. The recipient recreates the
coating with AddPoison when every effect resolves locally; otherwise the
weapon stays hidden and remains with its owner.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit 9900e11)
Enchanting, renaming and brewing change items without the incremental
inventory events the server copy relies on, so those items were missing
from the trade picker and the client's Ready check cancelled trades
whose offer no longer matched the live inventory.

The client now sends its live inventory when a trade starts and before
each Ready, and the server replaces its copy and drops offered items the
snapshot no longer covers. Outdated offers unready instead of cancelling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit 8063177)
Inventory removals passed a freshly built extra data list to RemoveItem.
It matches none of the inventory's stored lists, so trading away an
enchanted, renamed or poisoned item could leave it with the sender and
take a plain copy (or nothing) instead. Removals now find the stored
extra data list that describes the entry and remove that one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit f87a288)
A sender crashed in a dynamic cast while its game applied the traded
items to the partner's remote character. Remove the paths that could
leave the engine pointing at freed or foreign data there:

- Keep created-potion references instead of releasing them after the
  item is added; the inventory may not hold its own reference.
- Stop creating potion forms just to name partner offers in the UI.
- Never pass RemoveItem an extra data list the inventory does not own;
  fall back to removing without extra data.
- Refuse to create an enchantment whose effect setting is missing, and
  skip attaching a missing enchantment instead of attaching null.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit 92d45d4)
AddPotion/AddPoison can return an existing created potion, including one
the player already holds. Releasing it on a recipe mismatch could free a
form an inventory still points at. Refuse it without releasing, ignore
effect cost (gold value only) in the check, and log both recipes so a
refused potion can be diagnosed from the client log.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit e120b7e)
The trade picker drops its separate Poisons filter; poisons already show
under Potions. The Misc/Gems filter is now labelled Misc (soul gems still
appear there).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSW5HGXzi9kAVm4zdsSaid
(cherry picked from commit d2b06f7)
@absol89

absol89 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants