java.lang.IndexOutOfBoundsException -- Need Help

Discussion in 'Plugin Development' started by vasil7112, Jul 17, 2013.

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

    vasil7112

    Dear Bukkit Readers,
    Here is the error i get:
    Code:
    Task #3 for DS v1.0 generated an exception
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
        at java.util.ArrayList.rangeCheck(Unknown Source)
        at java.util.ArrayList.remove(Unknown Source)
        at me.vasil7112.DeathSwap.Main.roll(Main.java:113)
        at me.vasil7112.DeathSwap.Main.roll(Main.java:104)
        at me.vasil7112.DeathSwap.Main.roll(Main.java:104)
        at me.vasil7112.DeathSwap.Main$1.run(Main.java:65)
        at org.bukkit.craftbukkit.scheduler.CraftTask.run(CraftTask.java:58)
        at org.bukkit.craftbukkit.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:344)
        at net.minecraft.server.MinecraftServer.r(MinecraftServer.java:516)
        at net.minecraft.server.DedicatedServer.r(DedicatedServer.java:234)
        at net.minecraft.server.MinecraftServer.q(MinecraftServer.java:477)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:409)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:573)
    Yes, i know how to read the errors, and i checked line 113, 104, and 65. I couldn't find something that would crash my code, and i did lots of testing on it. It works fine for 10-20 seconds, but then it crashes!
    Here is my full plugin code, take a look:
    Code:java
    1. package me.vasil7112.DeathSwap;
    2.  
    3. import java.util.ArrayList;
    4. import java.util.Random;
    5.  
    6. import org.bukkit.Bukkit;
    7. import org.bukkit.Location;
    8. import org.bukkit.entity.Player;
    9. import org.bukkit.event.EventHandler;
    10. import org.bukkit.event.EventPriority;
    11. import org.bukkit.event.Listener;
    12. import org.bukkit.event.entity.PlayerDeathEvent;
    13. import org.bukkit.event.player.PlayerJoinEvent;
    14. import org.bukkit.event.player.PlayerQuitEvent;
    15. import org.bukkit.plugin.PluginManager;
    16. import org.bukkit.plugin.java.JavaPlugin;
    17.  
    18. public class Main extends JavaPlugin implements Listener{
    19. public static Main Instance;
    20. public GhostFactory ghostFactory;
    21. final Random random = new Random();
    22. ArrayList<String> alive_players = new ArrayList<String>();
    23. ArrayList<String> dead_players = new ArrayList<String>();
    24. ArrayList<String> teleported = new ArrayList<String>();
    25. public Main()
    26. {
    27. Instance = this;
    28. }
    29.  
    30. public void onEnable(){
    31. PluginManager pm = getServer().getPluginManager();
    32. pm.registerEvents(this, this);
    33. this.ghostFactory = new GhostFactory(this, true);
    34. ghostFactory.create();
    35. for(Player player : getServer().getOnlinePlayers()){
    36. alive_players.add(player.getName());
    37. }
    38.  
    39. Instance.getServer().getScheduler().scheduleSyncRepeatingTask(Instance, new Runnable() {
    40. public void run() {
    41. getLogger().info(alive_players.size() + " " + dead_players.size() + " " + teleported.size());
    42. int a = alive_players.size();
    43. if(getServer().getOnlinePlayers().length >= 2){
    44. if(alive_players.isEmpty() == true){
    45. for(Player player : getServer().getOnlinePlayers()){
    46. player.sendMessage("All Players Died! Round Restarting");
    47. restart();
    48. }
    49. }else if(a == 1){
    50. for(Player player : getServer().getOnlinePlayers()){
    51. player.sendMessage(alive_players.get(0) + " won this round! Restarting");
    52. restart();
    53. }
    54. }else{
    55. for(Player player : getServer().getOnlinePlayers()){
    56. if(alive_players.contains(player.getName())){
    57. teleported.add(player.getName());
    58. }
    59. }
    60. for(Player player : getServer().getOnlinePlayers()){
    61. if(alive_players.contains(player.getName()) && teleported.contains(player.getName())){
    62. if(teleported.size() == 1){
    63. teleported.clear();
    64. }else{
    65. roll();
    66. }
    67. }
    68. }
    69. }
    70. }else{
    71. for(Player player : getServer().getOnlinePlayers()){
    72. player.sendMessage("There must be atleast 2 players online to play this MiniGame!");
    73. }
    74. }
    75. }
    76. }, 0L, 5 * 20L);
    77. }
    78.  
    79. @EventHandler(priority=EventPriority.HIGHEST)
    80. public void onJoin(final PlayerJoinEvent e){
    81. if(!(dead_players.contains(e.getPlayer().getName()))){
    82. alive_players.add(e.getPlayer().getName());
    83. }else{
    84. e.getPlayer().sendMessage("You either died or left this round. As result you won't participate in this round!");
    85. }
    86. }
    87. @EventHandler(priority=EventPriority.HIGHEST)
    88. public void onLeave(final PlayerQuitEvent e) {
    89. alive_players.remove(e.getPlayer().getName());
    90. dead_players.add(e.getPlayer().getName());
    91. ghostFactory.addGhost(e.getPlayer());
    92. }
    93. @EventHandler(priority=EventPriority.HIGHEST)
    94. public void onDeath(final PlayerDeathEvent e){
    95. alive_players.remove(e.getEntity().getPlayer().getName());
    96. dead_players.add(e.getEntity().getPlayer().getName());
    97. ghostFactory.addGhost(e.getEntity().getPlayer());
    98. e.getEntity().getPlayer().sendMessage("You died! You are now a Ghost! You can't attack or be attacked, but you can spectate others :)");
    99. }
    100. public void roll(){
    101. int i1 = random.nextInt(teleported.size());
    102. int i2 = random.nextInt(teleported.size());
    103. if(i1 == i2){
    104. roll();
    105. }else{
    106. String p1 = teleported.get(i1);
    107. String p2 = teleported.get(i2);
    108. Location p1loc = Bukkit.getPlayerExact(p1).getLocation();
    109. Location p2loc = Bukkit.getPlayerExact(p2).getLocation();
    110. Bukkit.getPlayerExact(p1).teleport(p2loc);
    111. Bukkit.getPlayerExact(p2).teleport(p1loc);
    112. teleported.remove(i1);
    113. teleported.remove(i2);
    114. }
    115. }
    116. public void restart(){
    117. alive_players.clear();
    118. dead_players.clear();
    119. teleported.clear();
    120. for(Player player : getServer().getOnlinePlayers()){
    121. ghostFactory.removeGhost(player);
    122. }
    123. for(Player player : getServer().getOnlinePlayers()){
    124. alive_players.add(player.getName());
    125. }
    126. }
    127.  
    128. }
     
  2. Offline

    Cooliojazz

    Think about this: is it possible for i1 or i1 (in the roll() method) the be the index of the last item? Sure it is! So what happens if i2 is the last index and then you remove an item from the list? Well now it's pointing to an index one past the end of the list. Although it only throws an error in that one specific case, that actually exposes a much deeper problem with that piece of code (line 112 & 113). Whenever i2 > i1, the item you remove with i2 will actually be one past the intended index, as all the indices after a removed item in an ArrayList get shifted down one. Luckily, there is a solution, because the remove() method actually takes a couple different parameters. One could be an index, as you are trying to do, but we've already seen how that will get you into trouble. The other is an actual reference to the object you want to remove. So instead of removing it using the indices, obtain references to the Strings using the indices, then use those as the actual parameters to remove the item from the list. I will give you one small example of what I'm talking about, then hopefully you can figure it out from there, because I'm all about the learning!
    Code:
    ArrayList<String> strings = new ArrayList<>();
    strings.add("Hi!");
    String histring = strings.get(0);
    strings.remove(histring);
    Hope that helps you with your problem! :)
     
  3. Offline

    vasil7112

    Srry for the late response...
    So what you are suggesting is the following:
    teleported.remove(teleported.get(i1));
     
  4. Offline

    Cooliojazz

    vasil7112 No, not exactly. More like
    Code:java
    1. String i1s = teleported.get(i1);
    2. String i2s = teleported.get(i2);
    3. teleported.remove(i1s);
    4. teleported.remove(i2s);


    I know that may seem roundabout and not exactly intuitive, but it's what you have to do to avoid the problems mentioned above. If you don't understand why that's necessary, maybe try reading what I said through a couple more times, or ask and I can try to explain better :p
     
Thread Status:
Not open for further replies.

Share This Page