2017-11-10 4 views
0

나는 게임이 시작될 때 모든 플레이어가 자신의 스코어 보드에서 볼 수있는 Bukkit 실행 가능 타이머를 만들었지 만, 타이머에 참여하는 모든 플레이어가 2만큼 올라간다는 것을 알았습니다. 이 문제를 해결하는 방법에 대한 단서가 없습니다. 나는 이것에 대한 해결책을 찾지 않고 어디에서나 찾고 있었다.부킷 타이머는 플레이어가 합류 할 때 속도가 향상됩니다.

게임 내 클래스 :

public class InGame extends BukkitRunnable implements Listener{ 

    private Main main; 

    public InGame(Main main) { 
     this.main = main; 

    } 

    public static int time; 

    public void run() { 
     if (time == 300) { 
      if (GameState.getCurrentGamestate() == GameState.INGAME) { 
       Bukkit.broadcastMessage(Main.prefix + "§b5 " + "§6minutes has passed!"); 
       for(Player all : main.players) { 
        all.playSound(all.getLocation(), Sound.NOTE_PLING, 1, 1); 
       } 

       return; 
      } 
     } 

     if(time == 6000) { 
      Bukkit.broadcastMessage(Main.prefix + "§b10 " + "§6minutes has passed!"); 
      for(Player all : main.players) { 
       all.playSound(all.getLocation(), Sound.NOTE_PLING, 1, 1); 

      } 

     } 
     if(time == 12000) { 
      Bukkit.broadcastMessage(Main.prefix + "§b20 " + "§6minutes has passed!"); 
      for(Player all : main.players) { 
       all.playSound(all.getLocation(), Sound.NOTE_PLING, 1, 1); 

      } 

     } 
     if(time == 18000) { 
      Bukkit.broadcastMessage(Main.prefix + "§b30 " + "§6minutes has passed!"); 
      for(Player all : main.players) { 
       all.playSound(all.getLocation(), Sound.NOTE_PLING, 1, 1); 

      } 

     } 

     time += 1; 
    } 
} 

메인 클래스 코드 :

public class Main extends JavaPlugin implements Listener{ 

//int minutes = Waiting.timeUntilStart/60; 
//int seconds = Waiting.timeUntilStart % 60; 
//String t = String.format("%02d:%02d", minutes, seconds); 

public static Plugin plugin; 
public static Main main; 

ArrayList<UUID> player = new ArrayList(); 

public File file; 
public FileConfiguration locationConfig; 



public static int startCountdownId; 
public static int startCounterId; 

private int waitingtask; 
private int count = 120; 
private int number = 15; 



public ArrayList<Player> players = new ArrayList(); 
public ArrayList<Player> spectators = new ArrayList(); 
public ArrayList<Player> innocent = new ArrayList(); 
public ArrayList<Player> traitor = new ArrayList(); 



public static Map<Location, Inventory> chests = new HashMap<Location, Inventory>(); 

public static String prefix = "§8§l┃ §6TIMV §8┃ §6"; 

Inventory spec; 




public void onEnable() { 



    Bukkit.getServer().getWorld("world").setTime(300); 

    startCountdown(); 
    saveDefaultConfig(); 
    registerFile(); 

    GameState.setGamestate(GameState.WAITING); 
    plugin = this; 
    registerEvents(); 

    Bukkit.getConsoleSender().sendMessage("§cPlugin developed by InfernoArtz & Kodepus"); 

    this.getCommand("timv").setExecutor(new TimvCommand(this)); 
    //this.getCommand("role").setExecutor(new RoleCommand(this)); 
} 

public void loc1() { 
    Location loc = (Location) main.locationConfig.get("main.spawns.Lobby"); 
} 



public void onDisable() { 
    plugin = null; 

} 

/* SCOREBOARD KODER */ 
@EventHandler 
public void onJoin(PlayerJoinEvent e) { 
    final Player p = e.getPlayer(); 

    new BukkitRunnable() { 


     @Override 
     public void run() { 
      final org.bukkit.scoreboard.Scoreboard s = Bukkit.getScoreboardManager().getNewScoreboard(); 
      p.setScoreboard(s); 
      final Objective o = s.registerNewObjective("sidebar", "dummy"); 
      if (p == null || !p.isOnline() || GameState.getCurrentGamestate() != GameState.WAITING) { 
       cancel(); 

       return; 
      } else { 

      } 



      o.setDisplayName("§bTIMV §3" + Waiting.timeUntilStart); 
      o.setDisplaySlot(DisplaySlot.SIDEBAR); 
      o.getScore(" ").setScore(12); 
      o.getScore("§6§lRole").setScore(11); 
      o.getScore("§fUnknown").setScore(10); 
      o.getScore(" ").setScore(9); 
      o.getScore("§a§lPlayers Left").setScore(8); 
      o.getScore("§f" + Bukkit.getOnlinePlayers().size()).setScore(7); 
      o.getScore(" ").setScore(6); 
      o.getScore("§b§lRound Stats").setScore(5); 
      o.getScore("§7Karma: §f0").setScore(4); 
      o.getScore("   ").setScore(3); 
      o.getScore("§8§m--------").setScore(2); 
      o.getScore("§6play.§eserver§6.com").setScore(1); 

     } 
    }.runTaskTimer(this, 1, 20); 
} 



public void registerFile() { 
    file = new File(getDataFolder(), "locations.yml"); 
    locationConfig = YamlConfiguration.loadConfiguration(file); 
    saveFile(); 
} 

public void saveFile() { 
    try { 
     locationConfig.save(file); 

    } catch(IOException e) { 


    } 
} 




public void registerEvents() 
{ 


    Bukkit.getPluginManager().registerEvents((this), this); 
    Bukkit.getPluginManager().registerEvents(new JoinEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new QuitEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new PlayerInteractEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new PvpEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new FallEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new InventoryEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new LobbyEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new BlockPlace(this), this); 
    Bukkit.getPluginManager().registerEvents(new BreakEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new DeathEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new LoginEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new HungerEvent(this), this); 
    Bukkit.getPluginManager().registerEvents(new NoMobSpawn(this), this); 


} 

@SuppressWarnings("deprecation") 
public void startCountdown() { 
    Waiting.timeUntilStart = 300; 
    startCountdownId = getServer().getScheduler().scheduleSyncRepeatingTask(this, new Waiting(this), 20l, 20l); 



    } 
@SuppressWarnings("deprecation") 
public void startCounter() { 
    InGame.time = 0; 
    startCounterId = getServer().getScheduler().scheduleSyncRepeatingTask(this, new InGame(this), 20l, 20l); 


} 

public void stopCountdown() { 
    getServer().getScheduler().cancelTask(startCountdownId); 
} 

public void restartCountdown() { 
    startCountdown(); 
    stopCountdown(); 
} 

public static Main getPlugin() { 
    return main; 
} 










    } 
+2

'public static int time;'모든 플레이어에 대해 타이머를 공유하고 있습니다. – Draco18s

+0

여기에 문제가 있다고 생각하지 마십시오 – InfernoArtz

+1

예, 그렇습니다. '정적'이 무엇을하는지보십시오. – Draco18s

답변

1

그래서 당신이 조인 모든 플레이어 용의 Runnable을하고 있습니다, 그리고 당신은 모든의 Runnable에 타이머에 +1을 추가합니다. 따라서 12 명의 플레이어가 합류하면 매초마다 12 개의 Runnable이 실행되므로 초당 12 회 +1 초가 추가됩니다.

이 문제를 해결하려면 게임 스레드를 제어하지 못하게하십시오. 이벤트를 사용하지 않고 견고한 방식으로 제어하십시오. 이벤트를 사용하여 플레이어로 ArrayLists를 제어하고 스레드의 ArrayList를 확인하십시오.

스레드 중 하나에서 무언가를 액세스하는 여러 스레드를 사용하는 경우 synchronized 키워드를 사용해야합니다. 나는 당신이 그것에 뛰어들 것을 제안합니다.

나는 이것을 위해 작은 예제를 만들었으며, 이것이 더 명확 해지기를 바랍니다.

메인 클래스 :

public class Main extends JavaPlugin implements Listener { 

    public ArrayList<Player> players = new ArrayList<>(); 

    // My HashMap with the threads 
    private HashMap<BukkitTask, Integer> game = new HashMap<>(); 

    public void onEnable() { 
     this.getServer().getPluginManager().registerEvents(this, this); 

     // Create a thread here and let it run the whole game 
     BukkitTask task = new Game(this).runTaskTimer(this,1,20); 
     game.put(task, task.getTaskId()); 
    } 

    public void onDisable() { 
    } 

    // Eventhandlers that control the ArrayList with players 
    @EventHandler 
    public void onJoin(PlayerJoinEvent e) { 
     Player player = e.getPlayer(); 
     this.players.add(player); 
     if (!this.players.contains(player)) { 
     this.players.add(player); 
     } 
    } 

    @EventHandler 
    public void onQuit(PlayerQuitEvent e) { 
     Player player = e.getPlayer(); 
     if (!this.players.contains(player)) { 
     this.players.remove(player); 
     } 
    } 
} 

내 게임() BukkitRunnable 클래스 확장 :

public class Game extends BukkitRunnable { 

    private Main main; 

    private int time; 

    public Game(Main main) { 
     this.main = main; 
    } 

    public void run() { 
     for(Player player : main.players) { 
     final org.bukkit.scoreboard.Scoreboard s = Bukkit.getScoreboardManager().getNewScoreboard(); 
     player.setScoreboard(s); 
     final Objective o = s.registerNewObjective("sidebar", "dummy"); 

     o.setDisplayName("Sidebar"); 
     o.setDisplaySlot(DisplaySlot.SIDEBAR); 
     o.getScore("Time: " + this.time).setScore(12); 
     } 

     // Don't count if there are no players 
     if (!main.players.isEmpty()) { 
     this.time++; 
     } 
    } 
} 

당신은 게임() 클래스처럼 더 BukkitRunnables을 만들 수 있지만 필요할 때 synchronized를 사용해야 할 수 있습니다 , 이것에 의해 thread-safe가됩니다.

나에게 올바른 방법을 제공하기 위해 큰소리로 hnefatl을 보내주십시오. 더 나은 옵션이 있다면 의견에서 듣고 싶습니다.

+1

이것은 더 나은 디자인이지만 이상적인 것은 아닙니다. 클라이언트가 연결하고 연결을 끊었다가 다시 연결하면 2 개의 Runnable이 실행됩니다.모든 플레이어에게 상태 정보를 보내는 Runnable을 항상 가지고있는 것이 더 좋을 것입니다. 플레이어가 없다면 아무 것도 할 필요가 없습니다. 일부 동기화 로직을 추가해야 할 수도 있습니다.이 코드는 스레드로부터 안전하지 않습니다. 'onJoin' 이벤트가 동 기적으로 만 실행될 수 있는지 여부는 중요하지 않습니다. 그렇지 않으면 확실히 수행됩니다. – hnefatl

+0

@hnefatl 그래서 ArrayList에서 플레이어를 제거하고 마지막 플레이어를 확인하고 Runnable을 종료하는 OnPlayerQuitEvent가 있어야합니까? 제가 틀렸다면 언제나 저를 교정하십시오, 나는 여전히 학습자입니다. 댓글을 주셔서 감사합니다. 정말 도움이됩니다. – Scriptblade

+0

"ArrayList"에 연결된 플레이어를 추적하려면 "player quit"이벤트를 처리해야합니다.하지만 주된 포인트는 다음과 같은 조건에서 스레드를 스폰하는 것이 아닙니다. 여러 번 만나야한다. 언제나 * 항상 (타이머에서) 계속 실행하고 모든 플레이어에 대해 반복하고 스코어 보드를 보냅니다. 연결되어있는 플레이어가 없다면 "no players"와 그 벌금을 반복 할 것입니다. – hnefatl