Skip to content

ItemExchange: support multiple inputs and outputs per exchange - #45

Open
ProgrammerGodMC wants to merge 1 commit into
EdenMinecraft:mainfrom
ProgrammerGodMC:main
Open

ItemExchange: support multiple inputs and outputs per exchange#45
ProgrammerGodMC wants to merge 1 commit into
EdenMinecraft:mainfrom
ProgrammerGodMC:main

Conversation

@ProgrammerGodMC

Copy link
Copy Markdown

Summary

An exchange could only ever pair one input rule with one output rule. A single exchange can now require several different items and pay out several — e.g. 2 iron + 1 diamond for a sword + a shield.

Rules are grouped by their order in the shop inventory: an unbroken run of inputs followed by an unbroken run of outputs is one exchange, and the next input after an output starts the next. Trades stay all-or-nothing — the buyer must have every input and the shop every output, or nothing moves. Every input and output is always listed when browsing, so a buyer always sees the full price before paying it.

Behaviour change

input,output,input,output — the documented and common layout — parses identically to before, so ordinary shops are unaffected.

Consecutive inputs now merge instead of splitting. input,input,output,output was previously a donation of the first input plus an exchange of the second input for the first output, with the second output ignored; it is now one exchange taking both inputs for both outputs.

This matters most for donation shops. A chest of 12 input rules with no outputs used to be 12 separate donations; it is now a single exchange demanding all 12 items at once — and past maxInputs it is disabled entirely.

Why the new stock allocator

Utilities.getStock / calculateStock are load-bearing, not cosmetic. The old per-rule scan searched the inventory independently for each rule, so two rules matching the same items would both claim the same stack and the trade would silently under-charge. The new allocator reserves across all rules at once with no double-claiming.

Conformance is precomputed once per call because ExchangeRule.conforms() builds its debug strings unconditionally, and the stock search would otherwise multiply its call count on the browse path — which runs on every punch.

Exchange size limits

A bulk rule block holds any number of rules in one item, so a very large exchange is cheap to build. New config.yml section, live-reloadable with /iereload:

tradeLimits:
  maxInputs: 8
  maxOutputs: 8

An over-limit exchange is rejected outright, never trimmed — dropping an input would let a buyer underpay, and dropping an output would shortchange them. Enforcement is in TradeRule.isValid(), the one chokepoint both the grouping and the listener already gate on, and it sits after bulk flattening so loose and bulk rules are measured identically. The limit applies per exchange, not per bulk item: one bulk block can still hold any number of normal exchanges.

Because rule items look normal in a container and a bulk block hides its contents, a disabled exchange is announced on punch

0 means no limit configs without a tradeLimits section fall back to the jar defaults

Notes

  • TradeRule now holds lists. getInput(), getOutput() and hasOutput() are retained
  • NameLayerGlue now checks every input. It would have compiled unchanged, but a group lock on any non-first input would have been silently bypassed.
  • Bulk rules are flattened in order before grouping, so they behave exactly like loose rules, including runs spanning two bulk blocks. Grouping never spans separate containers.
  • No changes to the item transfer layer — InventoryUtils already accepted item arrays and committed atomically.

Testing

Tested on a local Paper 1.21.8 server running the full plugin set, and it works:

  • existing single-input → single-output shops behave exactly as before
  • multi-input / multi-output exchanges take every input and pay out every output
  • the exchange is refused when the buyer is short any input, or the shop is short any output
  • donations (inputs with no outputs) work
  • bulk rules behave the same as loose rules, including a run spanning a bulk block and a loose rule
  • browsing lists every input and output with the correct stock count
  • over-limit exchanges are disabled and reported to the player

LLM use

Implementation and write-up assisted by Claude Opus 5.

@ProgrammerGodMC

Copy link
Copy Markdown
Author
image image image

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.

1 participant