[lib] VillagerTradingLib Custom Villager Trades ; Quick, Easy and Clean

Discussion in 'Resources' started by jtjj222, Nov 18, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    jtjj222

    I have fixed all of the bugs, and this currently works in all game modes, on 1.6.2. In the next update, I will use reflection to allow future compatibility.
    About:
    I couldn't find an easy way to make custom villager trading screens, so I dug into the minecraft server source and made a library to handle the dirty work for you :D
    https://forums.bukkit.org/attachments/villagertrading-java-zip.14689/
    Drop this class into your project (I would prefer if you kept the package the same, but it really doesn't matter), and follow below.
    How to use:
    When you want to launch a new trade, all you have to do is create an array of the VillagerTradeOffer's available:
    Code:java
    1. VillagerTradeOffer[] offers = {
    2. new VillagerTradeOffer(new ItemStack(Material.EMERALD,1),new ItemStack(Material.MUSHROOM_SOUP,1))
    3. };

    (More on this below)
    Then lastly, open the trade with the player:
    Code:java
    1. VillagerTrading.openTrade(player, offers);

    And that's it!
    2012-11-18_15.37.53.png
    Other things to note:
    • The VillagerTradeOffer constructor can take 2, or 3 ItemStack's as arguments. If given 2, the first is the leftmost cost (with the other being left blank) and the second is the item being offered. If given 3 arguments, the first 2 are the costs, and the third is the item being offered. The picture above used this:
      Code:java
      1. new VillagerTradeOffer(new ItemStack(Material.GLASS,1),new ItemStack(Material.STONE,2),new ItemStack(Material.THIN_GLASS,3));
    I hope that a few people can find this useful. If you do, I would love it if you could reply telling me so, that way I have some sort of incentive to keep doing things like this. Reply below if you find bugs, or have any suggestions also. Happy coding :D
     

    Attached Files:

  2. Offline

    KeybordPiano459

  3. Offline

    ienze

    Good job, if you will update it to next version I will use it i one my project..
     
  4. Offline

    jtjj222

    It supports 1.4.5 :D
     
  5. Offline

    lucasdidur

    Where I can download?
     
  6. Offline

    jtjj222

  7. Offline

    Allov

    Is it possible to inject trades into existing villagers?
     
  8. Offline

    jtjj222

  9. Offline

    Allov

    Is anyone else having this bug. I do the trade, then I close the trade window. If I take an item from my inventory, it goes back to the previous state, as if the trade never happened.

    Do I need to save the inventory after a trade?

    Edit: I tried assigning different ID, creating only one instance of the library, assigning an ID by player, etc.

    The inventory (or the server) doesn't seem to recognize the transaction and seem to put my inventory back to the state it was.
     
    jtjj222 likes this.
  10. Offline

    jtjj222

    hmm... That sounds like a bug. I'll try to fix it :D
     
  11. Offline

    Allov

    Maybe the inventory needs to be saved when the trade is done? How did you know which packet to use? I could help you this way!

    Thanks a lot for the help by the way!
     
  12. Offline

    Allov

    I did a bit more research on this, and it seems that bukkit doesn't listen for InventoryClickEvent for window created using the method above. Odd.
     
  13. Offline

    jtjj222

    That's what I thought too. The only thing I can think of is using reflection to register the window id somehow...
     
  14. Offline

    Allov

    In fact, this code should be useful : https://github.com/Bukkit/CraftBukk...n/java/net/minecraft/server/EntityPlayer.java

    Check out line 520. This is the exact way to open a trade window. In fact, what I did with CraftBukkit was to spawn a villager using getWorld().spawnEntity(...). Then, I using getHandle() to get the EntityVillager, I can use the getOffers() method to ADD trades. This work fine to customize villager.

    So, what I'm going to do is to spawn villagers, and give them custom trades this way. It's going to be way more intuitive and Minecraft-like :D

    I'll get back to you with some code if you like.
     
    jtjj222 likes this.
  15. Offline

    Shiny Quagsire

    Now is it possible to just open a window without the villager? I'd imagine you could spawn one, open the window, and then kill it, but is there a way to avoid that?
     
  16. Offline

    Allov


    Well, as seen in the openTrade() function in EntityVillager, you have to pass an IMerchant parameter. So, my guess is if you implement that interface, you could, at some extent, simulate a virtual merchant. However, the merchant seem to return a EntityHuman too. So, it has to be something that exist. Maybe a custom block implementing those interface would work?

    I tried to create one on the fly, but I wasn't able to make it work and I didn't spawn it using the Server.spawnEntity() function. It would require some more testing.
     
  17. Offline

    jtjj222

    I tried that, but gave up. That's why I just sent the packet... But I can't register the window id cb doesn't allow plugins to modify packets or parts of itself without messy reflection :-{
     
  18. Offline

    Allov

    Alright, so, I didn't check about spawning a window out of a right click (i.e.: from a block, sign, or something other than a villager). What I did, and it suits my needs plenty, and is Minecraft friendly in my opinion, was to change what a villager would sell for my list.

    So, I used your MerchantRecipe wrapper class to make this easier, and to be frank, this was the code I needed.

    Here's the flow of what I was thinking when I wanted my user to use my mod:
    1. Have a way for them to create a custom shop (the list of item is currently server side only);
    2. Have them interact with an Entity, living if possible (that, I have done throught spawning a villager);
    3. Have custom trades with presets prices.
    That said, here's the code I used to modify a villagers offers:
    Code:
    VillagerTradeOffer[] offers = new VillagerTradeOffer[] {
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 24), new ItemStack(Material.DIAMOND_SWORD, 1)),
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 64), new ItemStack(Material.DIAMOND_LEGGINGS, 1)),
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 64), new ItemStack(Material.DIAMOND_CHESTPLATE, 1)),
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 32), new ItemStack(Material.DIAMOND_HELMET, 1)),                   
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 32), new ItemStack(Material.DIAMOND_BOOTS, 1)),                   
            new VillagerTradeOffer(new ItemStack(Material.EMERALD, 24), new ItemStack(Material.DIAMOND_PICKAXE, 1))
    };
     
    // HERE IS MISSING THE "GET A VILLAGER FUNCTION", IT ACTUALLY DEPENDS ON WHAT YOU NEED.
    Villager villager = *TODO*;
     
    EntityVillager entityVillager = ((CraftVillager)villager).getHandle();
    MerchantRecipeList recipes = entityVillager.getOffers(((CraftPlayer)evt.getPlayer()).getHandle());
    recipes.clear();
     
    for(VillagerTradeOffer offer : offers) {
        recipes.add(offer.getMerchantRecipie());
    }
    
    The way I used to spawn villager (the *TODO* part) what to create a "recipe" much like the way you can spawn an Iron Golem or a Snowman. My recipe was listen for BlockPlaceEvent and check for an Emerald block. If it was the case, I tested the two blocks below to see if they were Obsidian blocks. If such was the case, I just spawn a villager using Bukkit's spawn function:

    Code:
    // block variable comes from the BlockPlaceEvent.getBlock();
    Block block = event.getBlock();
     
    // Here's the todo part
    Villager villager = world.spawn(block.getLocation(), Villager.class);
    
     
    Wruczek and jtjj222 like this.
  19. Offline

    jtjj222

    Thanks, looks like that would work, although I have been busy working on a plugin, so I can't test it out just yet :={
     
  20. Offline

    Jumla

    Please update this to 1.4.6
     
  21. Offline

    Allov

    In 1.4.6 (and late 1.4.5), they changed package name to include versions. So, the quick fix is to add version name into the imports:

    Code:
    import net.minecraft.server.v1_4_6.MerchantRecipe;
    import net.minecraft.server.v1_4_6.EntityVillager;
     
    import org.bukkit.craftbukkit.v1_4_6.entity.CraftPlayer;
    import org.bukkit.craftbukkit.v1_4_6.entity.CraftVillager;
    
    I'll look deeper if there is a better way, but this works for now.
     
  22. Offline

    Jumla

    That's not the only issue:

    p.netServerHandler.sendPacket is now broken
    .getHandle() -- Doesn't exist anymore
     
  23. Offline

    Allov

    Oh, you're talking about the original code. In fact, this never worked. The window will show up, and it will let you do the trade, but as soon as you close the window, reopen your inventory and change something in there, it will resets.

    That's why I came up with the latter. It doesn't require any packets, but you'll have to get a villager instead of a sign post / block / chest. You can even set the villager to be invulnerable and stuck him inside fences if you're afraid of him moving around too much.

    Anyway, otherwise, I don't know how to make it works.
     
  24. Offline

    jtjj222

    I had only tested it in creative mode :\. Anyway, The mods should probably delete the thread, because untill bukkit provides an api for villager trading, there will never be a way to do trading in survival mode (where the inventories are checked). I would make a pr, but I honestly don't have a clue about the coding style and whatnot craftbukkit requires. Thanks for your help, and sorry it didn't work.
     
  25. Offline

    Cybermaxke

    I can try to make a new API for the villagers trading.
    Changing the title is forced by the client but the rest would be changable.
    :)
     
  26. Offline

    jtjj222

    It won't work until bukkit provides an way (without messy reflection) to register new inventory windows :(
     
  27. Offline

    Cybermaxke

    I have made a witch merchant for my server project and its working good. ;)
     
  28. Offline

    Allov

    Care to tell us your approach :D
     
  29. Offline

    Cybermaxke

    I made a other thread. ;)
     
  30. Offline

    lucasdidur

    How I can automatically register the trade window on bukkit using reflections?
     
Thread Status:
Not open for further replies.

Share This Page