concurrent modification exception

Discussion in 'Plugin Development' started by moose517, Sep 7, 2011.

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

    moose517

    could use some help. i know what the problem is i'm just not sure how to go about fixing it. my plugin loads a list of users with a command that was enabled when they last logged in/out.

    Here is the server log
    Code:
    20:34:28 [SEVERE] Could not pass event PLAYER_LOGIN to RuneLayer
    java.util.ConcurrentModificationException
            at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
            at java.util.ArrayList$Itr.next(Unknown Source)
            at com.moosemanstudios.Runelayer.RLPlayerListener.onPlayerLogin(RLPlayer
    Listener.java:28)
            at org.bukkit.plugin.java.JavaPluginLoader$13.execute(JavaPluginLoader.j
    ava:328)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:58)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:338)
            at net.minecraft.server.ServerConfigurationManager.a(ServerConfiguration
    Manager.java:184)
            at net.minecraft.server.NetLoginHandler.b(NetLoginHandler.java:82)
            at net.minecraft.server.NetLoginHandler.a(NetLoginHandler.java:33)
            at net.minecraft.server.NetworkListenThread.a(SourceFile:91)
            at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:454)
            at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:363)
            at net.minecraft.server.ThreadServerApplication.run(SourceFile:422)
    20:34:28 [INFO] moose517 [/127.0.0.1:44653] logged in with entity id 32 at ([wor
    ld] 3.34375, 55.0, 6.71875)
    and RLPlayerListener relevant code
    Code:java
    1.  
    2. public class RLPlayerListener extends PlayerListener{
    3. private RuneLayer plugin;
    4. RLPlayerListener(RuneLayer instance) {
    5. plugin = instance;
    6. }
    7. public void onPlayerLogin(PlayerLoginEvent event) {
    8. Player player = event.getPlayer();
    9. // see if the player is in the offline list, if so query server for them and add to the rune users list
    10. for (String offlinePlayer : plugin.offlinePlayers) {
    11. plugin.log.info("[RuneLayer] " + offlinePlayer + ", " + player.getName());
    12. if (player.getName().equalsIgnoreCase(offlinePlayer)) {
    13. // add this user to the online players list and remove from current one
    14. plugin.offlinePlayers.remove(offlinePlayer);
    15. plugin.runePlayers.add(player);
    16. plugin.log.info("[RuneLayer] Adding online user: " + player.getName());
    17. }
    18. }
    19. }
    20. public void onPlayerQuit(PlayerQuitEvent event) {
    21. // remove the player from the rune users list and add to the offline users list
    22. plugin.runePlayers.remove(event.getPlayer());
    23. plugin.offlinePlayers.add(event.getPlayer().getName());
    24. plugin.log.info("[RuneLayer] removing online user: " + event.getPlayer().getName());
    25. }
    26.  


    As well as the main class's relevant bits
    Code:java
    1.  
    2. public class RuneLayer extends JavaPlugin{
    3. Logger log = Logger.getLogger("minecraft");
    4. public ArrayList<Player> runePlayers = new ArrayList<Player>();
    5. public ArrayList<String> offlinePlayers = new ArrayList<String>();
    6. private final RLPlayerListener playerlistener = new RLPlayerListener(this);
    7. static String mainDirectory = "plugins/RuneLayer";
    8. public void onEnable() {
    9. // register the event
    10. PluginManager pm = this.getServer().getPluginManager();
    11. pm.registerEvent(Event.Type.PLAYER_INTERACT, playerlistener, Priority.Normal, this);
    12. pm.registerEvent(Event.Type.PLAYER_LOGIN, playerlistener, Priority.Normal, this);
    13. pm.registerEvent(Event.Type.PLAYER_QUIT, playerlistener, Priority.Normal, this);
    14. // load list of players with rune layer enabled
    15. new File(mainDirectory).mkdir();
    16. load_players();
    17. PluginDescriptionFile pdfFile = this.getDescription();
    18. log.info("[" + pdfFile.getName() + "] version " + pdfFile.getVersion() + " is enabled");
    19. }
    20. public void onDisable() {
    21. // save list of players with rune layer enabled
    22. save_players();
    23. log.info("[RuneLayer] is disabled");
    24. }
    25. private void load_players() {
    26. try {
    27. // see if hte file even exists
    28. if ((new File(mainDirectory+"/players.txt").exists())) {
    29. BufferedReader in = new BufferedReader(new FileReader(mainDirectory + "/players.txt"));
    30. runePlayers.clear();
    31. // loop through the file to get all the players
    32. String line = null;
    33. while ((line = in.readLine()) != null) {
    34. Player player = this.getServer().getPlayer(line);
    35. if (player == null) {
    36. this.offlinePlayers.add(line);
    37. log.info("[RuneLayer] offline player added: " + line);
    38. } else {
    39. this.runePlayers.add(player);
    40. log.info("[Runelayer] online player added: " + player.getName());
    41. }
    42. }
    43. in.close();
    44. log.info("[RuneLayer] Loaded successfully!");
    45. }
    46. } catch (IOException ex) {
    47. ex.printStackTrace();
    48. }
    49. }
    50. private void save_players() {
    51. try {
    52. BufferedWriter out = new BufferedWriter(new FileWriter(mainDirectory + "/players.txt"));
    53. // save the online users first
    54. for (Player player: runePlayers) {
    55. out.write(player.getName());
    56. out.newLine();
    57. log.info("[RuneLayer] online player saved: " + player.getName());
    58. }
    59. // now save the offline users
    60. for (String offlinePlayer : offlinePlayers) {
    61. out.write(offlinePlayer);
    62. out.newLine();
    63. log.info("[RuneLayer] offline player saved: " + offlinePlayer);
    64. }
    65. out.close();
    66. log.info("[RuneLayer] Saved successfully!");
    67. } catch (IOException ex) {
    68. ex.printStackTrace();
    69. }
    70. }
    71. }
    72.  
     
  2. Well, as you're pasted code is cutted I can't figure out the line which causes the error for sure but I think it's in RLPlayerListener at line 10 and 14: Get an Iterator (offlinePlayers.iterator() and work witht that instead of the ArrayList (because you read and write in the loop, which can cause that. Don't ask me why but I ran into the same error not so long ago and somebody told that to me).
     
  3. Offline

    moose517

    LOL i knew i was forgetting something, i was gonna point out the line that errors in that, i'll try the iterator.

    I replaced the for loop with this, but the error still persists.

    Code:java
    1.  
    2. Iterator<String> itor = plugin.offlinePlayers.iterator();
    3. while(itor.hasNext()) {
    4. String next = itor.next().toString();
    5. if (next.equals(player.getName())) {
    6. plugin.offlinePlayers.remove(next);
    7. plugin.runePlayers.add(player);
    8. }
    9. }
    10.  


    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 19, 2016
  4. Offline

    daemitus

    You cant remove items from an array while iterating through it. clone it and remove from that.
    Alternatively,
    "Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress."
    http://download.oracle.com/javase/tutorial/collections/interfaces/collection.html
     
  5. Try this:
    Code:java
    1.  
    2. Iterator<String> itor = plugin.offlinePlayers.iterator();
    3. while(itor.hasNext()) {
    4. String next = itor.next().toString();
    5. if (next.equals(player.getName())) {
    6. itor.remove(next); // That should fix it. :)
    7. plugin.runePlayers.add(player);
    8. }
    9. }
    10.  

    And if that shouldn't help, show the full class and the errog again. :)

    //EDIT:
    Totally wrong. That's what an Itorator is for ;)
     
  6. Offline

    daemitus

    Iterator.remove() doesnt take an argument. It removes the last item called from Iterator.next().
     
  7. Right, thanks for correcting. :) It was written quick and with less attention.
     
  8. Offline

    moose517

    haha that worked V10later, minus the next as claemitus pointed out. i should have known that and after you posted that i did a facepalm. Thanks guys LOL.

    alright, another problem, and i'm not understading why either.

    here is the function onPlayerLogin again
    Code:java
    1.  
    2. public void onPlayerLogin(PlayerLoginEvent event) {
    3. Player player = event.getPlayer();
    4. // see if the player is in the offline list, if so query server for them and add to the rune users list
    5. Iterator<String> itor = plugin.offlinePlayers.iterator();
    6. while(itor.hasNext()) {
    7. String next = itor.next().toString();
    8. if (next.equals(player.getName())) {
    9. itor.remove();
    10.  
    11. // make sure the player actually has permissions to use this, so no file editing can fool it
    12. if (player.hasPermission("runelayer.rune")) {
    13. plugin.runePlayers.add(player);
    14. plugin.log.info("[Runelayer] adding online users: " + player.getName());
    15. } else {
    16. player.sendMessage("I call hax!"); <---- errors out on this line
    17. plugin.log.info("[Runelayer] user not authorized to use rune: " + player.getName());
    18. }
    19. }
    20. }
    21. }
    22.  


    and my error log
    Code:
    18:53:03 [SEVERE] Could not pass event PLAYER_LOGIN to RuneLayer
    java.lang.NullPointerException
            at org.bukkit.craftbukkit.entity.CraftPlayer.sendRawMessage(CraftPlayer.
    java:96)
            at org.bukkit.craftbukkit.entity.CraftPlayer.sendMessage(CraftPlayer.jav
    a:100)
            at com.moosemanstudios.Runelayer.RLPlayerListener.onPlayerLogin(RLPlayer
    Listener.java:42)
            at org.bukkit.plugin.java.JavaPluginLoader$13.execute(JavaPluginLoader.j
    ava:328)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:58)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:338)
            at net.minecraft.server.ServerConfigurationManager.a(ServerConfiguration
    Manager.java:184)
            at net.minecraft.server.NetLoginHandler.b(NetLoginHandler.java:82)
            at net.minecraft.server.NetLoginHandler.a(NetLoginHandler.java:33)
            at net.minecraft.server.NetworkListenThread.a(SourceFile:91)
            at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:454)
            at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:363)
            at net.minecraft.server.ThreadServerApplication.run(SourceFile:422)
    18:53:03 [INFO] moose517 [/127.0.0.1:13415] logged in with entity id 32 at ([wor
    ld] 54.26853346541987, 51.0, 53.56104092605317)
    
    if i replace that inner if statement checking for player permissions and just add the player object its fine and works great, but when i put that has permissions it fubars

    EDIT: weird, if i just have:
    Code:java
    1.  
    2. plugin.runePlayers.add(player);
    3. player.sendMessage("I call hax!");
    4.  

    it also fails, its like the player object isn't valid but isn't it safe to assume it is otherwise its all wrong? LOL

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 19, 2016
  9. Offline

    nisovin

    You can't send a message in onPlayerLogin, since they aren't all the way logged in yet. If you want to send a message when a player joins, use onPlayerJoin.
     
  10. Offline

    moose517

    aaah, that makes sense, well what i'm doing will work either on login or join, i guess i'll switch that now
     
Thread Status:
Not open for further replies.

Share This Page