[Solved] Farming Help

Discussion in 'CommandHelper' started by Chloe Sanders, Nov 20, 2017.

  1. Chloe Sanders

    Chloe Sanders New Member

    Hi. I am new to command helper but I have used things like it in the past, I am trying to allow players to harvest crops by right clicking them and so far I have done this:

    Code (Text):
    bind(player_interact, null, null, @event,
      if(equals(@event['action'], 'right_click_block'),
        if(equals(@event['block'], '59:7'),
          break_block(@event['location'])
          set_block_at(@event['location'], '59:0')
        )
      )
    )
    I am unsure how powerful the plugin is but it seems very simple to use and I am curious on how to do two things~
    1: Make it so when you right click the crop you will have a fist attack animation to look like you harvested it
    2: Remove 1 seed from the items that are dropped

    Thanks for any help :)
  2. PseudoKnight

    PseudoKnight Well-Known Member

    There's no Bukkit method to send an attack animation for a player. I'm not even sure that packet would work for the client doing the attacking anyway. You can trick the client into temporarily moving the hand down by swapping out the item in that hand, though.

    If you want more control of the drops, I suggest using drop_item() instead of break_block(). break_block() simply sets the block to air and spawns the default drops for the block you replaced. So you're already half-way there already by setting the wheat to '59:0'.
  3. PseudoKnight

    PseudoKnight Well-Known Member

    So I tested manually sending an animation packet and it does work. However, it requires bypassing the API to do so, so I can only put the function in my extension for those types of functions.
  4. PseudoKnight

    PseudoKnight Well-Known Member

    I added the hand swing animation to my CHNaughty extension for the hell of it, just in case you really really wanted this. But fair warning before you use this extension. It's extremely version dependent and will need to be updated before you update to a new version of Minecraft. That said, I have been updating it regularly since 1.8.0 and you can use the extension_exists('CHNaughty') check for fallback code.

    https://github.com/PseudoKnight/CHNaughty/releases
    Chloe Sanders likes this.
  5. Chloe Sanders

    Chloe Sanders New Member

    I just wanted something easy to start out with so I was working on remaking this plugin just to see if I could do it. It is where I got the fake attack animation idea from as that plugin has that same effect. The reason I used break_block instead of drop_item is because I wanted the drops to be just like vanilla with the exception of removing 1 seed (to make up for the free auto seed replant) and the problem with that is the drops vary so like you could get 2 seeds or you could get one in vanilla minecraft and break_block just keeps to that vanilla randomness. How would I check what is normally dropped in vanilla? Is there a method to do that in Command Helper or will I have to manually set that I want a number between 1 and 3 seeds to drop? Thanks for the help so far
  6. PseudoKnight

    PseudoKnight Well-Known Member

    Ya, it turns out that plugin uses the same method I implemented in my function, except I also send the packet to nearby players too.

    That plugin also recreates the drops like I suggested with drop_item() and rand(). However, there is Bukkit method that gets expected drops for a block. We just don't have a function to get that information yet. Do you want me to add that to CommandHelper?
    Chloe Sanders likes this.
  7. Chloe Sanders

    Chloe Sanders New Member

    I feel that could be very useful for in the future if mojang ever decided to change the vanilla drops, would make things a little safer. I really appreciate this :D
  8. Chloe Sanders

    Chloe Sanders New Member

    hey just to add to that I tested out the
    pswing_hand([playerName], [hand])
    and it worked! When you put the description as "The hand parameter can be either main_hand (default) or off_hand" did you mean you can use pswing_hand(@event['player']) to default to the main_hand? because I tested that and it returned this error when right clicking:
    [​IMG]
    This is not at all a problem for me I'm just mentioning it for if it happens to be a bug, I am using pswing_hand(@event['player'], 'main_hand') and it is working perfectly
  9. PseudoKnight

    PseudoKnight Well-Known Member

    I've explored this method and its accuracy is really spotty. For example, for full grown wheat it never returns seeds. This appears to be because it only supports one drop type. They nicely add a method for getting the drops for a specific tool, but then it only checks if the tool actually causes drops, then it returns the generic drops. (which means SIlk Touch and Fortune aren't supported) Blocks with meta are mostly unsupported too, so banner data is lost for example. All-in-all it seems poorly supported and I hesitate to add it. It's no wonder it doesn't exist in CommandHelper yet.

    For what it's worth, break_block() does seem to use the vanilla drop system, so that should be accurate. What you could do is bind() item_spawn before break_block() and then unbind() it after.
    Chloe Sanders likes this.
  10. PseudoKnight

    PseudoKnight Well-Known Member

    You can just use pswing_hand() and it'll default to the player running the script and main_hand. [edit] That's not a bug. I intended pswing_hand('main_hand') to be a usage. The docs are not clear on that, though. Maybe I should change it.
    Last edited: Nov 21, 2017
  11. Chloe Sanders

    Chloe Sanders New Member

    Oh okay, thanks for trying anyway.

    I'll try get that to work then :) otherwise I'll just research the exact vanilla drops
  12. Chloe Sanders

    Chloe Sanders New Member

    Is this what you mean?
    Code (Text):
    bind(player_interact, null, null, @crop_harvest,
      if(equals(@crop_harvest['action'], 'right_click_block'),
        if(equals(@crop_harvest['block'], '59:7'),
          pswing_hand()
          bind(item_spawn, null, null, @crop_seeds,
            if (@crop_seeds['item']['type'] == 295) {
              @seedcount += 1;
              if (@seedcount == 1) {
                cancel()
              }
            }
          )
          break_block(@crop_harvest['location'])
          unbind(item_spawn)
          set_block_at(@crop_harvest['location'], '59:0')
        )
      )
    )
    I'm not very familiar with the variables I have it so @seedcount += 1 in the hopes that every time it goes through the drops and the drop is a seed it will equal the total amount of seeds dropped and the first seed will be removed. It seems to just remove all seeds though :/
    Last edited: Nov 21, 2017
  13. PseudoKnight

    PseudoKnight Well-Known Member

    Sorry that you seemed to have stumbled upon a not-simple project for your first script.

    bind() returns the bind id that you can use in unbind().

    PHP:
    @id = bind(item_spawn, null, null, @event, /* do stuff */ )
    break_block(@event['location'])
    unbind(@id)
    Your @seedcount logic doesn't make sense, though. In the item_spawn event docs you can see that "item" is in the "Mutable Fields" column. This means you can change the item being dropped in the event. So what you could do is...
    PHP:
    bind(item_spawn, null, array('item': 295), @event) { // can prefilter here for just this item type
         @event['item']['qty'] -= 1;  // change the array first
         modify_event('item', @event['item']); // then modify the item in the event using your modified array
    }
    I'd have to test if a zero quantity item would work here, but it usually does, which makes our lives easier.
  14. Chloe Sanders

    Chloe Sanders New Member

    The @seedcount thing was as the event seems to trigger per item dropped so it was meant to count the total number of seeds however the variables dont seem consistant they just delete themself on the next spawned item, I tried your code:
    PHP:
    bind(player_interact, null, null, @crop_harvest) {
      if(equals(@crop_harvest['action'], 'right_click_block'),
        if(equals(@crop_harvest['block'], '59:7'),
          pswing_hand()
          @item_spawn_id = bind(item_spawn, null, array('item': 295), @crop_seeds) {
            @crop_seeds['item']['qty'] -= 1;
            modify_event('item', @crop_seeds['item']);
          }
          break_block(@crop_harvest['location'])
          unbind(@item_spawn_id)
          set_block_at(@crop_harvest['location'], '59:0')
        )
        if(equals(@crop_harvest['block'], '142:7'),
          pswing_hand()
          break_block(@crop_harvest['location'])
          set_block_at(@crop_harvest['location'], '142:0')
        )
        if(equals(@crop_harvest['block'], '207:3'),
          pswing_hand()
          break_block(@crop_harvest['location'])
          set_block_at(@crop_harvest['location'], '207:0')
        )
        if(equals(@crop_harvest['block'], '141:7'),
          pswing_hand()
          break_block(@crop_harvest['location'])
          set_block_at(@crop_harvest['location'], '141:0')
        )
      )
    }
    but it seems to be working the exact same way as now no seeds are being dropped :(
  15. PseudoKnight

    PseudoKnight Well-Known Member

    Oh, I was wondering if it spawned them in one group or multiple groups. Guess that answers that. Each seed spawns as its own item. So to fix that we just unbind after the first event.

    PHP:
    @item_spawn_id = bind(item_spawn, null, array('item': 295), @crop_seeds) {
       cancel();
       unbind();
    }
    break_block(@crop_harvest['location'])
    unbind(@item_spawn_id) // just in case no seeds were dropped
    Chloe Sanders likes this.
  16. PseudoKnight

    PseudoKnight Well-Known Member

    Each time a script is run, it uses a new variable list. Aliases, binds, procs, and closures are separate scripts. If the same one is run multiple times, it'll start "fresh", meaning it'll only know the variables it was given at the time of its creation unless you pass variables in. You can pass changed variables in various ways, like with import()/export() and/or array references (where the array values can be changed and any script that has access to that array variable will see the changes). This is covered in more detail on the Learning Trail on the wiki, and it's really handy to learn.
    Chloe Sanders likes this.
  17. Chloe Sanders

    Chloe Sanders New Member

    Sorry for all the questions but I really want to learn how to use this plugin to help customise a server I plan to make in the future and I really want to use the best coding practices. Thanks to your help I have managed to completly remake that plugin in command helper however to continue my training I thought the code was unnecessarily large (creating a new if statement and bind for each individual crop) so I attempted to minimalize my code, there are two things I didnt fully understand how to do though. I've looked through the api and I cant find the information that I'm looking for - the code I provide below is just an example as I've used php alot in the past and I cant seem to find the equivilant of isset() in the api
    PHP:
    bind(player_interact, null, null, @crop_harvest) {
      array @crops = array('59:7': 295, '142:7': 392, '207:3': 434, '141:7': 391);
      if(equals(@crop_harvest['action'], 'right_click_block')) {
        if(isset(@crops[@crop_harvest['block']])) {
          pswing_hand()
          @item_spawn_id = bind(item_spawn, null, array('item': @crops[@crop_harvest['block']]), @crop_seeds) {
           cancel();
           unbind();
          }
          break_block(@crop_harvest['location'])
          unbind(@item_spawn_id)
          set_block_at(@crop_harvest['location'], '59:0')
        }
      }
    }
    I also need to learn how to set only the data value of the block to 0 instead of 59:0 as I have made it work for more than just wheat now
    Last edited: Nov 22, 2017
  18. PseudoKnight

    PseudoKnight Well-Known Member

    For isset() you can use array_index_exists(@crops, @crop_harvest['block']);

    To work for multiple blocks, you could use split(':', @crop_harvest['block']). This returns an array where the first value is the block id and the second is data.
  19. Chloe Sanders

    Chloe Sanders New Member

    Sorry for the delay on replying been going through some personal stuff, I've now finished this!! I dont think its bad for my first attempt although I required a load of help (thanks ;)) here is the finished code for if anyone ever needs it:
    PHP:
    bind(player_interact, null, null, @crop_harvest) {
      array @crops = array('59:7': 295, '142:7': 392, '207:3': 434, '141:7': 391);
      if(equals(@crop_harvest['action'], 'right_click_block')) {
        if(array_index_exists(@crops, @crop_harvest['block'])) {
          pswing_hand()
          @item_spawn_id = bind(item_spawn, null, array('item': @crops[@crop_harvest['block']]), @crop_seeds) {
           cancel();
           unbind();
          }
          break_block(@crop_harvest['location'])
          unbind(@item_spawn_id)
          array @id_data = split(':', @crop_harvest['block'], 1)
          set_block_at(@crop_harvest['location'], @id_data[0] . ':0')
        }
      }
    }
    I'll be needing help in the future I imagine with future projects thanks for all the amazing support :p
  20. PseudoKnight

    PseudoKnight Well-Known Member

    You're welcome.

    I also suggest adding a prefilter to player_interact. eg. array('button': 'right')
  21. Chloe Sanders

    Chloe Sanders New Member

    okay cool so I removed if(equals(@crop_harvest['action'], 'right_click_block')) and replaced it with the prefilter I understand how those work now I also made it so pswing_hand() checks for CHNaughty just to be safe
    PHP:
    bind(player_interact, null, array('button': 'right'), @crop_harvest) {
      array @crops = array('59:7': 295, '142:7': 392, '207:3': 434, '141:7': 391);
      if(array_index_exists(@crops, @crop_harvest['block'])) {
        if (extension_exists('CHNaughty') == true) {
          pswing_hand()
        }
        @item_spawn_id = bind(item_spawn, null, array('item': @crops[@crop_harvest['block']]), @crop_seeds) {
         cancel();
         unbind();
        }
        break_block(@crop_harvest['location'])
        unbind(@item_spawn_id)
        array @id_data = split(':', @crop_harvest['block'], 1)
        set_block_at(@crop_harvest['location'], @id_data[0] . ':0')
      }
    }
    Question just for organization is there any way to have this in its own script for example 'farming.ms' rather than main.ms? Maybe it goes into the includes folder? I've tested just putting farming.ms next to main.ms and it just wouldnt load the code the reason I ask is because I plan on doing many other things in the future and it will be really confusing if they are all in the same file
  22. PseudoKnight

    PseudoKnight Well-Known Member

    Absolutely. You can organize scripts however you want within LocalPackages (or its subdirectories). Any *.ms script will be run on start/recompile, unless it is within a directory ending with *.library or *.disabled. You can put any number of auto_include.ms files too. (up to one per directory, of course) Likewise, any *.msa file in LocalPackages will be compiled for aliases.

    I put almost all my scripts in LocalPackages. (except for some test/debug ones) I even use *.library directories to keep scripts I rarely use or don't need loaded immediately. You can load them (and compile them if they haven't already) later with include(). I do this to keep recompile time low because I have just a ton of scripts.
    Last edited: Nov 30, 2017
    Chloe Sanders likes this.
  23. Chloe Sanders

    Chloe Sanders New Member

    ah great, thanks again :)