Solved Removing specified players from Bukkit.getOnlinePlayers()

Discussion in 'Plugin Development' started by TerraVale, Jan 16, 2013.

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

    TerraVale

    Hi there!

    I've been devoting a lot of time towards implementing an extremely seamless 'tool' for my minecraft server. Seamless, to me, means the player will not need to delve into a large pool of commands to perform tasks. Even something as simple as /spawn, for example, will be handled through my methods. Alas, I have run into a problem!

    I have created an Enchanted Book (ID 403) with it's own custom MetaData: A display name and lore. When you crowch and left click, the item will place you into a hashmap. When repeated, it will take you out. The purpose of this feature is to disable global chatting for the player - i.e. disable their ability to globally chat (which I've already finished with a simple statement) and their ability to receive global chats.

    Because I've modified the default minecraft chatting, I introduce the following:

    Code:JAVA
    1.  
    2. for (Player oPlayer : Bukkit.getOnlinePlayers())
    3. {
    4. }
    5.  


    I send the message that the player types to "oPlayer". Every player receives the message.
    I'd like to have the people that are inside of my hashmap opt out of this "getOnlinePlayers()", so they will not receive global chats. Just for the purpose of explanation, there is global chatting and local chatting. This is all in an effort to reduce server-wide spam, and provide a comfortable playing environment which, coincidentally, does not include a large scrawl of text being propelled at your face every second.

    In extremely deprecated sudo-code, this is what I wish to achieve:

    Code:JAVA
    1.  
    2. Player aPlayer = Bukkit.getOnlinePlayers();
    3. Player bPlayer = plugin.gchat.get(p.getName());
    4. Player cPlayer = aPlayer - bPlayer (where bPlayers are "subtracted" from the online players)
    5.  
    6. //EDIT: Whoops. I meant for it to iterate through the hashmap and return all keys.
    7. //Where plugin.gchat is the reference to my initialized hashmap.
    8.  


    With such, I could simply send the message to cPlayer.

    Note* The hashmap is NOT saved on restart/reload, and the player is removed from the hashmap when they log out. This prevents confusion on the player's side, and makes it easier overall.
     
  2. Offline

    Cjreek

    Just check if oPlayer is contained in your HashMap. If he is than don't send a message to him.
     
  3. Offline

    Frazz86

    Use ASyncChatEvent.
    Cancel it.
    Use For Loop.
    Check player against your hashmap, if it doesn't contain player then send the message.
    Code:
    Player bPlayer = plugin.gchat.get(p.getName());
    
    Just send a message to players that aren't within the hashmap
     
  4. You could create your own instance of this map as an arraylist and just update it on the player join and quit events. Then you can sort it and filter it however you like.
     
  5. Offline

    fireblast709

    to elaborate on that:
    • use a java.util.concurrent.CopyOnWriteArrayList for that matter (for thread-safety and to prevent ConcurrentModificationExceptions
    • put people in that list if they join
    • remove them on leave
    • when they use that book the first time, remove them. Add them again on the second use, etc.
    • when someone chats:
      • cancel the AsyncPlayerChatEvent
      • check if the player is in the list. If not, return
      • loop through all players, and send them the message
    (not sure if noted before, but use playernames instead of Player objects)
     
  6. Offline

    TerraVale


    Hm. I'm confused by the CopyOnWriteArrayList part - I've never worked with one, and examples on the web seem daunting.

    However, what you described is exactly what I hoped to do!

    I've already had everything set up to do with chatting for a while, I simply need to introduce this new feature.
    Would you mind briefly explaining how to implement a java.util.concurrent.CopyOnWriteArrayList?
    I'm assuming "ConcurrentModificationExceptions" refers to when multiple changes to the map are happening all at once? All help is appreciated :)

    (also, not looking for very in-depth & functional pieces of code. I love to learn this stuff!)
     
  7. Offline

    fireblast709

    A CopyOnWriteArrayList is the same as an ArrayList in usage. You call .add(element), .remove(element), contains(element), etc like on a normal ArrayList. The difference is that this ArrayList is thread-safe. Whenever you write (in other words: change) the ArrayList it will make a copy and write it back when the other threads stopped using it. The implementing is the same as the ArrayList (except for the actual type)
    Code:java
    1. List<String> safeList = new CopyOnWriteArrayList<String>();


    About the ConcurrentModificationException, yes that is true. Though another cause I am familiar with is when you iterate over a list and edit it
    Code:java
    1. for(String a : list)
    2. {
    3. if(a.equals("Something"))
    4. {
    5. // This throws a CME, as you use the list while modifying it
    6. list.remove(a);
    7. }
    8. }
    This counts for all Collections and Maps afaik. If everyone has a remark, please let me know =3
     
  8. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı

    Wait. Why are we cancelling the event when you could just modify the recipients list.
     
  9. Offline

    TerraVale

    I've formatted the aesthetics of the chat to my liking; as opposed to "<player> message", I now use:
    Player: message, where if the player is OP, the playername is red, and if they have a bukkitperm for moderator, their name is blue, else just white. If the chat is local, their message colour is gray, and if global, white! I'm also writing an alliance system where a player may create an alliance. The alliance name will display as a prefix.
    I explained the above extremely roughly, but you should get the idea ;)

    Thank you for the explanation, I really appreciate it; will get back to you with whether or not I was able to get it functioning :D
     
  10. Offline

    fireblast709

     
  11. Offline

    TerraVale

    fireblast709

    Everything is in working order, aside from iterating through the list and sending each player within this list the originally sent message. It's pretty late, and I can't (for the life of me) figure out how to iterate through the list and send each "string", in this case, a message.

    The only way I can imagine it being accomplished is by it iterating through each string, assigning that string to a variable, and using that variable as the player to send the message to. Unfortunately, I don't know how to have it go through each string in the list one by one, 'nor do I know how to get that string from the list.

    It must involve plugin.gchat.get() in some way, but alas, it wishes for me to define an index number. I suppose that would need to be a function that continues to add 1 to itself? I have no idea.
     
  12. Offline

    fireblast709

    TerraVale what are you trying to iterate over. Don't you just want to iterate over the recipients, check if they have global chat enabled, and if they have send the message?
     
  13. Offline

    TerraVale

    Simply just sending the message would not work, as everyone would receive it regardless :eek:
    Is there an event for on receive of a chat event? If not, then I'd need to only send the original message to people that are in the list, or in an alternative scenario, all people that are not contained within the list - if possible!

    I can PM you what I've been working on so far, if it helps :3
     
  14. Offline

    fireblast709

    just iterate over the players in the list and send them the message
     
  15. Offline

    TerraVale

    This is what I don't exactly know how to do yet :O

    Code:JAVA
    1.  
    2. if ((p.getItemInHand().getTypeId() == 403) && (p.getItemInHand().getItemMeta().getLore() != null) && plugin.gchat.contains(p.getName()))
    3. {
    4. //Iterates through the list, but I need to have it able to send a message to all players in the list?
    5. for (Object oPlayer: plugin.gchat)
    6. {
    7. if (p.isOp() == true)
    8. {
    9. //Where oPlayer should be all players in the list,
    10. //prefix is my custom prefix-esque alliance plugin,
    11. //and globalC is my chat formatting and the message itself!
    12. oPlayer.sendMessage((prefix + ChatColor.RED + globalC));
    13. return;
    14. }
    15. else if (p.hasPermission("chat.mod"))
    16. {
    17. oPlayer.sendMessage((prefix + ChatColor.AQUA + globalC));
    18. return;
    19. }
    20. else
    21. {
    22. oPlayer.sendMessage((prefix + ChatColor.WHITE + globalC));
    23. return;
    24. }
    25. }
    26. }
    27.  
     
  16. Offline

    fireblast709

    Code:
    for(String pn : thatSafeListWithPlayerNames)
    {
        Player p = Bukkit.getPlayer(pn);
        if(p != null)
        {
            p.sendMessage(theMessage);
        }
    }
     
  17. Offline

    TerraVale

    Hm, this works, but the second (or third, fourth, etc.) player that's in the list cannot see their own message :O

    For example, I logged in first, and could see my own global message.
    My friend logged in second, and could see my global messages.
    If my friend sent a global message, I could see it, but he could not.
    I logged out and logged back in, to place me second in the list - I could not see my own messages, but he was able to.

    I'll see if I can get it fixed myself, but here's what I currently have:
    http://pastebin.com/56PGZTV2

    I really appreciate your help :)
     
  18. Offline

    fireblast709

    Just after looking 10 seconds in your code... maybe you should not check the item in hand when you chat :3
     
  19. Offline

    TerraVale

    Oh, hm.... You see, that's part of the roleplaying aspect of what I wish to have :O
    This is getting tricky, every way I think of accomplishing what I'd like to accomplish, something always gets in the way :(
     
  20. Offline

    fireblast709

    TerraVale remove the 'return;' after sending the message
     
    TerraVale likes this.
  21. Offline

    TerraVale

    Ah, thanks a ton!
    I'd give you a cookie if I could ;)
     
Thread Status:
Not open for further replies.

Share This Page