Solved Making a resettable action

Discussion in 'Plugin Development' started by SlimeyDerp, Mar 27, 2020.

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

    SlimeyDerp

    I am trying to make a sword that, on playerhit, turns into the item the opponent is holding. The concept seems buggy, but I'll fix the conditions on the trigger. Also, whenever it turns into that, it should only turn for 5 seconds before going back into sword form

    Now, here's the hard part: If it does ANOTHER playerhit, it should refresh the 5 seconds. So if I am hit once, then 2 seconds pass, and I'm hit again, it should take 5 seconds for it to turn back to sword form. I tried to do some timers that activate and deactivate but I couldn't get it to work. I also heard that maps could be useful for that, but I couldn't understand how they could help

    I can show you the code I have right now:

    Player damaged_player = (Player) event.getEntity();
    damaged_player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 100, 1));
    ItemMeta DamagedPlayerMeta = damaged_player.getItemInHand().getItemMeta();
    DamagedPlayerMeta.addEnchant(Enchantment.ARROW_INFINITE, 10, true);
    ItemStack clone = damaged_player.getItemInHand().clone();
    clone.setItemMeta(DamagedPlayerMeta);
    attacker.setItemInHand(clone);
    if (Bukkit.getScheduler().isCurrentlyRunning(id)) {
    Bukkit.getScheduler().cancelTask(id);
    }

    // Appears to work until this part, in which it blows up after it

    id = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() {
    @Override
    public void run() {
    int counter = 0;
    for (ItemStack item : attacker.getInventory().getContents()) {
    counter++;
    if (item.getEnchantmentLevel(Enchantment.ARROW_INFINITE) == 10) {
    attacker.getInventory().setItem(counter, CustomItemStack.ETHERIAL_PHANTOM_SWORD_STACK);
    }
    }
    }
    }, 100).getTaskId();

    Some variables that were declared before:

    attacker = Player entity
    CustomItemStack = Sword item ItemStack
    id = integer that equals zero at first declaration on class

    I have tried a bunch of options to no avail. So please, help me. You don't need to spoon-feed me code, but also, don't just put wiki links and just say "Read this". Thank you for your help
     
  2. Offline

    CraftCreeper6

    @SlimeyDerp
    A nice way to do this would be System#currentTimeMillis()

    When you first start the timer, store the current time millis + 5000 (5 seconds in milliseconds) in a variable (likely a map as I imagine you'll want to store multiple players). Then, if System#currentTimeMillis() returns a value greater than the value stored in the map, the timer is up. However, if you want to reset the timer to 5 seconds, simply overwrite the value in the map with System#currentTimeMillis() + 5000 again.

    The only caveat is that you'd need some form of repeated task checking the timer.
     
  3. Offline

    SlimeyDerp

    @CraftCreeper6 I am sorry to be like this, but I am new to this whole plugin spectrum. Actually, Java in general. But I couldn't understand how maps could work in this scenario. Could you give me an example? Because I'm confused
    ( In pseudo-code as to understand what's going on )
     
  4. Offline

    CraftCreeper6

    @SlimeyDerp
    So a map (HashMap in your case) uses a key and a value, the key would be the UUID of the player, you can use player#getUniqueId() to get it.

    The value would be of type long, as that's what currentTimeMillis returns.

    So you'd end up with something like:
    Code:
    HashMap<UUID, Long> map = new HashMap…
    
    To start the process you'd add the user to the map.

    Code:
    map#put(key, value)
    Then, create a repeating task using BukkitRunnables or a Scheduler, that's up to you. The task should repeat as many times a second as you like, it's totally your choice, but remember, performance > functionality.

    Each time it runs, it should check each value in the HashMap, do this by getting it from the map, and checking it against System#currentTimeMillis()

    Code:
    bool reached = map#get(key) >= System#currentTimeMillis
    if reached is true, then the timer has been reached.

    If you want to reset the timer, just check that the map contains the UUID of the player, then replace the value
    Code:
    map#replace(key,val)
     
  5. Offline

    SlimeyDerp

    I am going to try it! Ill mark the post as solved if it works.

    I thank you a lot for simplifying it and explaining it in a clear way. That's mostly what I needed.

    Again, thank chu.
     
  6. Offline

    CraftCreeper6

    Good luck, let me know how it goes.
     
Thread Status:
Not open for further replies.

Share This Page