简体   繁体   中英

Task not being cancelled when HashMap value is true

I'm currently learning about scheduled tasks.

Basically, I'm making a Bukkit plugin where you can enable or disable PVP. When the player types /pvp on or /pvp off, they mustn't move for 5 seconds, however, the task cancelation just doesn't seem to execute.

Main class:

package me.mortadelle2.pvptoggle;

import java.util.ArrayList;
import java.util.HashMap;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.Vector;

public class PVPToggle extends JavaPlugin {

    ArrayList<String> noPVP = new ArrayList<String>();

    HashMap<String, Boolean> hasMoved = new HashMap<String, Boolean>();

    Player p;

    public void onEnable() {

        new PlayerDamage(this);
        getLogger().info("PVPToggle toggled!");

    }

    public void onDisable() {

        getLogger().info("PVPToggle disabled!");

    }

    public boolean onCommand(CommandSender sender, Command cmd, String label,
            String[] args) {

        p = (Player) sender;

        if (cmd.getName().equalsIgnoreCase("pvp")) {

            if (args.length == 0) {

                p.sendMessage(ChatColor.RED + "Invalid usage! /pvp [on or off]");
                return true;

            }

            if (args.length == 1) {

                if (args[0].equalsIgnoreCase("on")) {

                    p.sendMessage(ChatColor.YELLOW
                            + "PVP will be turned on in 5 seconds! Don't move!");
                    hasMoved.remove(p.getName());
                    hasMoved.put(p.getName(), false);

                    int turnOn = this.getServer().getScheduler()
                            .scheduleSyncDelayedTask(this, new Runnable() {

                                @Override
                                public void run() {

                                    if (hasMoved.get(p.getName()) == false) {
                                        noPVP.remove(p.getName());
                                        p.sendMessage(ChatColor.YELLOW
                                                + "You have turned PVP on!");
                                    }

                                }
                            }, 100L);

                    if (hasMoved.get(p.getName()) == true) {
                        p.sendMessage(ChatColor.RED
                                + "You moved so the action was cancelled.");
                        this.getServer().getScheduler().cancelTask(turnOn);
                    }

                    return true;

                }

                if (args[0].equalsIgnoreCase("off")) {

                    p.sendMessage(ChatColor.YELLOW
                            + "PVP will be turned off in 5 seconds. Don't move!");

                    hasMoved.remove(p.getName());
                    hasMoved.put(p.getName(), false);

                    int turnOff = this.getServer().getScheduler()
                            .scheduleSyncDelayedTask(this, new Runnable() {

                                @Override
                                public void run() {

                                    if (hasMoved.get(p.getName()) == false) {
                                        noPVP.add(p.getName());
                                        p.sendMessage(ChatColor.YELLOW
                                                + "You have turned PVP off!");
                                    }

                                }

                            }, 100L);

                    if (hasMoved.get(p.getName()) == true) {
                        p.sendMessage(ChatColor.RED
                                + "You moved so the action was cancelled.");
                        this.getServer().getScheduler().cancelTask(turnOff);
                    }

                    return true;
                }

            }

        }

        return false;
    }

}

Listener class:

    package me.mortadelle2.pvptoggle;

import org.bukkit.Bukkit;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;

public class PlayerDamage implements Listener{

    PVPToggle getter;

    public PlayerDamage(PVPToggle plugin) {

        plugin.getServer().getPluginManager().registerEvents(this, plugin);

        this.getter = plugin;

    }

    @EventHandler
    public void playerJoins(PlayerJoinEvent e){

        Player p = e.getPlayer();
        getter.hasMoved.put(p.getName(), false);

    }

    @EventHandler
    public void playerDamages(EntityDamageByEntityEvent e){

        Player victim = (Player) e.getEntity();
        Player killer = (Player) e.getDamager();

        victim.sendMessage("hey");

        if (getter.noPVP.contains(victim.getName()) || getter.noPVP.contains(killer.getName())){
            e.setCancelled(true);
        }

    }

    @EventHandler
    public void playerShootsPlayer(EntityShootBowEvent e){

        Arrow a = (Arrow) e.getEntity();

        Player shooter = (Player) a.getShooter();

        if (getter.noPVP.contains(a.getName()) || getter.noPVP.contains(shooter.getName())){
            e.setCancelled(true);
        }



    }

    @EventHandler
    public void playerMoves(PlayerMoveEvent e) {

        final Player p = e.getPlayer();

        final Vector pVel = p.getVelocity();

        getter.getServer().getScheduler()
                .scheduleSyncDelayedTask(getter, new Runnable() {

                    @Override
                    public void run() {


                        if (pVel.getX() != 0 || pVel.getBlockY() != 0
                                || pVel.getBlockZ() != 0) {
                            getter.hasMoved.remove(p.getName());
                            getter.hasMoved.put(p.getName(), true);
                        } else {
                            getter.hasMoved.remove(p.getName());
                            getter.hasMoved.put(p.getName(), false);
                        }

                    }
                }, 5L);

    }

}

There's no need to cancel the task because it's already over. There are also a few issues i see with your code. The first and probably most serious is that your scheduling a task in a PlayerMoveEvent, and not only that but its also unnecessary. You should always be extremely careful when using that event. It is called every time a player moves anything, including their head. So that event could be called hundreds or event thousands of times a second. If not absolutely necessary you should always have a check that makes sure the player moved to a new block to lower the amount of times your code is run. A much easier way would be to just do something like this:

@EventHandler
public void playerMoves(PlayerMoveEvent e) {
    Player p = e.getPlayer();

    //Check if the player moved to a new block
    if (e.getTo().getBlockX() != e.getFrom().getBlockX() || e.getTo().getBlockY() != e.getFrom().getBlockY() || e.getTo().getBlockZ() != e.getFrom().getBlockZ()) {
        //If they have, set their value in the hashmap to true
        getter.hasMoved.put(p.getName(), true);
    }
}

Also know that your scheduler is only called once when the ticks have passed, and the rest of your program continues. You can check if the player has moved in the scheduler

Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {

    @Override
    public void run() {

        if (hasMoved.get(p.getName()) == false) {
            noPVP.remove(p.getName());
            p.sendMessage(ChatColor.YELLOW + "You have turned PVP on!");
        } else {
            p.sendMessage(ChatColor.RED + "You moved so the action was cancelled.");
        }
    }
}, 100L);

Also a quick note: You do not need to remove the player from the HashMap every time you change its value. HashMap.put() will overwrite the existing value.

EDIT (Another suggestion): Probably the best way of doing this and if you wanted to achieve the effect of sending the cancellation message to the player as soon they moved, you could cancel the scheduler from instead from inside the playerMoves method instead of adding the player to the HashMap. That way the HashMap would not even be needed and it would just improve the overall code quality. You really should try and avoid using HashMaps as much as possible, there's usually a better way of doing things.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM