2015-08-28 14 views
0

我目前正在瞭解計劃任務。當HashMap值爲真時,任務未被取消

基本上,我製作了一個Bukkit插件,您可以在其中啓用或禁用PVP。 當玩家輸入/ pvp on或/ pvp off時,他們不能移動5秒,然而,任務取消似乎並未執行。

主要類:

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類:

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); 

    } 

} 

回答

2

有沒有必要取消任務,因爲它已經結束了。我的代碼中還有一些問題。首先也可能是最嚴重的是你在PlayerMoveEvent中安排了一個任務,不僅如此,而且它也是不必要的。使用該事件時應始終非常小心。每次玩家移動任何物體時都會調用它,包括頭部。所以這個事件可以被稱爲數百次或每秒數千次的事件。如果不是絕對必要,您應該始終進行檢查,確保玩家移動到新的區塊以減少代碼運行的次數。更簡單的方法是隻做這樣的事情:

@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); 
    } 
} 

也知道,當蜱已通過您的調度只叫一次,你的程序的其他部分仍在繼續。您可以檢查,如果玩家在調度

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); 

而且快速說明已移至:你並不需要從HashMap的每次改變其值時刪除播放器。 HashMap.put()將覆蓋現有的值。

EDIT(另一個建議): 也許這樣做的最好的方式,如果你想達到儘快他們搬到發送取消消息給玩家的效果,你可以從不是從playerMoves內取消調度方法而不是將玩家添加到HashMap中。這種方式甚至不需要HashMap,它只會提高整體代碼質量。你真的應該儘量避免使用HashMaps,通常有更好的做事方式。