• Filename
  • Uploaded by
  • Uploaded
    May 17, 2018
  • Size
    350.21 KB
  • Downloads
  • MD5

Supported Bukkit Versions

  • 1.12
  • 1.11
  • 1.10
  • 1.9
  • 1.8.1
  • 1.8
  • 1.8.3


v1.87 for MC 1.12, 1.11, 1.10, 1.9, 1.8

Major rewrite of the processing of trades:

Shopkeepers is now implementing the inventory actions that might trigger trades itself.

Previously, trading with player shopkeepers only allowed simple left clicks of the result slot. We predicted the trading outcome (rather simple when only allowing left clicking..) and then let minecraft handle the click like normal. Any other inventory actions (ex. shift-clicks) were prevented, because so far we weren't able to predict the outcome of those.
I finally took the time to dive into minecraft's and craftbukkit's internals to figure out, how it processes the various clicking types and resulting inventory actions, how those can trigger trades, and how minecraft processes those trades.

Supporting more advanced inventory actions for trading requires at minimum being able to reliably predict the outcome of those inventory actions, and by that already requires re-implementing of large parts of the vanilla logic (which is one of the reasons why this wasn't done so far). The step to also apply those predicted inventory changes ourselves then isn't that much of an additional effort on top, but has a few advantages:
For one, we can be quite sure that the predicted outcome of a trade actually matches what gets applied in the end. This should reduce the risk of inconsistencies between minecraft's behaviour and our predictions resulting in bugs (also with future minecraft updates in mind).
Secondly, when relying on minecraft's implementation we are only able to allow or cancel the inventory action as a whole. The shift-clicking inventory action however is able to trigger multiple successive trades (possibly even using different trading recipes). By implementing this ourselves, we are able to apply as many trades as are possible with regards to available stock and chest capacity.

Implementing the trading ourselves has a few advantages, but also comes with caveats:


  • Increased risk for bugs which we need to fix ourselves. Increased maintenance and testing effort.
  • Increased possibility for inconsistencies between vanilla inventory/trading behaviour and our own implementation.
  • Minecraft performs some map initialization when certain map items are created by crafting or via trades: This seems to be responsible for updating the scaling (after crafting a larger map) and enabling tracking (this doesn't seem to be used anywhere inside minecraft though). Since this is only the case if the map item has some special internal nbt data (which shouldn't be obtainable in vanilla minecraft), we currently simply ignore this inside Shopkeepers.


  • The usage count of the used trading recipes doesn't get increased anymore. But since these are only temporarily existing and aren't used for anything so far anyways, this shouldn't be an issue.
  • The player's item crafting statistic doesn't get increased anymore for items received via shopkeeper trades.
  • The player's traded-with-villager statistic doesn't get increased anymore for shopkeeper trades.

I could manually replicate some of these, but since these are custom trades anyways I don't see the need for it right now. But if there is a justified interest in this, let me know and I might add a config option for it.


  • Support for more advanced inventory actions when trading with shopkeepers:
    • Currently supported are: Shift-clicking, and moving traded items to a hotbar slot. (Fixes #437)
    • Not (yet) supported are:
      • Dropping the traded item: Exactly reproducing the vanilla behaviour for dropping the traded item is actually rather tricky / impossible with pure bukkit API so far. 
      • Trading by double-clicking an item in the player inventory: The behaviour of this inventory action is rather arbitrary in vanilla already (trades zero, one, or two times depending on the other items in the inventory), and it is currently affected by a bug (https://bugs.mojang.com/browse/MC-129515)
  • Simpler API: A single ShopkeeperTradeEvent is called for each trade (might be multiple per click depending on the used inventory action, ex. shift-clicking). The ShopkeeperTradeCompletedEvent was removed. (API breakage, sorry.)
  • Fixed: The logging of purchases should now actually be accurate for shift-clicks. It logs each trade individually. (Fixes #360)
  • Eventually this might allow for more options for customization of the trading behaviour in the future.

Potential issue (that has existed before already):

  • If minecraft adds new inventory actions, those are initially not supported by shopkeepers: If those inventory actions involve clicking on the result slot, they will simply be prevented. If they however allow players to trigger trades by clicking on items inside the player's inventory (similar to the existing collect-to-cursor action by double-clicking), they might introduce bugs which players might be able to exploit.


Other changes in this update:

  • Fix: Player inventory changed even though hiring was not successful. (Fixes #493)
  • Fix: All inventory operations are now limited to storage contents. This might fix issues with hiring cost items being removed from armor or extra slots.
  • Fix: No longer applying color conversion to a few settings. This mostly affects the 'name-regex' setting: Previously, depending on where the '&' was added inside the regex, the regex would become invalid due to color conversion.
  • Fix/Improvement: Added config validation for 'tax-rate' (it has to be between 0 and 100).
  • Improvement: The collect-to-cursor inventory action is now allowed inside the trading window, as long as the result slot doesn't match the item on the cursor.
  • Improvement: Normal player shopkeepers are now slightly smarter when figuring out whether the chest has enough space for the traded currency items, by allowing a variable ratio between high and low currency items.
  • Improvement: Buying shopkeepers are now slightly smarter when removing currency items from the chest: It prioritizes low currency items over high currency items, partial stacks over full stacks, and is able to split more than one large currency item and return the excess change to the chest (previously it only converted at most 1 high currency item). This should help keeping the chest more compact.
  • Improvement: The logged purchases contain the trading players' uuids now, in parentheses inside the 'PLAYER' column. The overall format of the columns should still be the same.
  • Improvement: Decreased delay of inventory updates from 3 to 1 tick (used when canceling inventory clicks inside the trading window).
  • Debugging: Minor improvements to debug messages for click events, closing of unexpected inventories and trading recipe information.
  • Debugging: Added an experimental way to accurately detect individual non-shopkeeper trades for all types of inventory clicks (by listening for corresponding statistic changes). This can be useful when comparing vanilla trading behaviour with Shopkeeper's new trading behaviour.
  • API: The ShopkeeperTradeEvent now directly provides access to the items offered by the player and the order in which they were matched to the used trading recipe.
  • API: Providing access to the resulting player inventory contents to the PlayerShopkeeperHiredEvent.
  • API: Various javadoc improvements.
  • API/Internal: Added new immutable class for representing trading recipes. This also affects users of the ShopkeeperTradeEvent.
  • API/Internal: The shopkeeper offers are now immutable. Changing prices requires replacing the offer now.
  • API/Internal: Changed how the AdminShopkeeper is handling its offers/recipes. The saving and loading of offers was slightly refactored, but shouldn't impact the current saving format.
  • Internal/Fix: Minor refactoring during updating to the new trade handling. This might even fix a few small potential bugs/inconsistencies related to handling of high-currency items.
  • Internal/Fix: All general inventory operations now work on content arrays (inventory snapshots) instead of the inventories directly. This might even fix a few severe issues, which went unnoticed so far.
  • Internal: Removed 'forHire' boolean value from shopkeepers. Instead a shopkeeper's hiring state is now solely determined by whether or not a non-empty hire cost item has been specified.
  • Internal: Added Settings#isHighCurrencyEnabled() and using that now everywhere.
  • Internal: Settings#isHighCurrencyItem() now returns false if high currency isn't enabled.
  • Internal: Added a debug message for every trade processed by Shopkeepers.
  • Internal: Moved trade logging into a separate class and package. It now reacts to ShopkeeperTradeEvents.
  • Internal: Some refactoring related to setting up the editor window and handling of editor clicks.
  • Internal: Various other small refactorings. Moved logging into util package, and moved item and inventory related utilities into a separate class.
  • Internal: Updated the internal TODO list and added a few more ideas.


Since the impact of these changes is rather high, I marked this update as 'beta' for now. Please try it out and report back any issues and inconsistencies you encounter.


Known potential issues: See here.


If you like this plugin, consider making a donation.