Solved How would you scan through a config to find a match?

Discussion in 'Plugin Development' started by supersonicsauce, Jul 3, 2014.

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

    supersonicsauce

    Hello guys, it's me again, still trying to make that regioning plugin. I've managed to save a players name, and 6 different values to define a region. Here's what it looks like in a config.yml:
    Code:
    Regions:
      players:
        SupersonicSauce:
          bounds:
            minX: 335.0
            miny: 71.0
            minZ: -289.0
            maxX: 342.0
            maxY: 77.0
            maxZ: -280.0
        Bob:
          bounds:
            minX: 999
            miny: 0
            minZ: -12
            maxX: 1000
            maxY: 256
            maxZ: -3
     
     
     
    
    Here is the code that saves it:
    Code:java
    1. public void saveRegion(Player player, double minX, double minY, double minZ, double maxX, double maxY, double maxZ){
    2. config.addDefault("Regions.players."+player.getName()+".bounds.minX", minX);
    3. config.addDefault("Regions.players."+player.getName()+".bounds.miny", minY);
    4. config.addDefault("Regions.players."+player.getName()+".bounds.minZ", minZ);
    5. config.addDefault("Regions.players."+player.getName()+".bounds.maxX", maxX);
    6. config.addDefault("Regions.players."+player.getName()+".bounds.maxY", maxY);
    7. config.addDefault("Regions.players."+player.getName()+".bounds.maxZ", maxZ);
    8. this.saveConfig();
    9.  
    10.  
    11. }
    12.  


    Now, here's the part that I'm totally clueless on. On a server with potentially hundreds of players, how would I be able to iterate quickly through the entire config to check if a player is building inside of an existing region?
     
  2. Offline

    unrealdesign

    supersonicsauce I can help you, but I really need to know what you're trying to do.
    • Can players only edit in their regions
    • Can only certain players edit in certain regions
    • Can players edit in any region
     
  3. Offline

    supersonicsauce

    unrealdesign
    Well, players will not be able to edit other players regions, but they can edit their own regions and any unclaimed land. But the important thing I need to know how to do is finding if a player is inside of a region. I think once I know how to do that, it should be relatively straightforward to restrict players from building in certain areas.
     
  4. Offline

    unrealdesign

    Have a player region class. Have an set of all instances of player regions class. In the class, have the start location, end location, and an set of all inbetween. Also have a method to calculate all the locations and put then into an array separate from getting the array, because this will save calculations. Just update it every time you change the start and/or end point. Then every time a player builds, check if he is in his region, and if he isnt, then check if he is in someone elses, then if he isnt, he isn't in a region. To iterate between one location to the next and get all blocks, use this code (not tested):
    Code:java
    1. for(it x=xMin; x<=xMax; x++)
    2. for(y=yMin; y <= yMax; y++)
    3. for(z=zMin; z <= zMax; z++)
    4. set.add (new Location(world, x, y, z))
     
  5. Offline

    supersonicsauce

    unrealdesign
    But...how? What do you mean by this?
     
  6. Offline

    Necrodoom

    unrealdesign *cringe* instead of checking if player location is in the region set, why not check if the player coords are between the region low and high points? 6 math checks would be cheaper than hundreds of equals.
     
    Phasesaber likes this.
  7. Offline

    unrealdesign

    Oh my bad I'm at work and replied fast haha
     
  8. Offline

    supersonicsauce

    Necrodoom unrealdesign
    Ok, well, how would I check? That's the main problem here. I'm at some point going to have a config with dozens of sets of 6-point region data, and have no idea how to scan through them to find if a player is inside them. How would I do this?

    Edit: I should say that I can probably figure out how to check if a player is inside of a region. My problem is mainly with getting the 6 location points from each individual player's region, and repeating that for as many players are in the list. I have no idea how to accomplish this.
     
  9. Offline

    Flamedek

    supersonicsauce Why would you want to loop through all players in the list? At most you'd want to loop through all online players which can be done with a for-each loop, and looping through getServer().getOnlinePlayers().

    Then just use the getInt(path + p.getName() + restOfPath) method of the config object.

    And add a check to see if it returns null, if it does that player does not have a region and you can return
     
  10. Offline

    supersonicsauce

    Flamedek If I looped only through online players, then players could break the blocks in the regions of other players who have logged off. All someone would have to do to grief is to wait until their target logged off.

    But just out of curiosity and for the sake of getting closer to finishing this, how exactly would I do a for loop with getOnlinePlayers()? Could you give me an example of the syntax?
     
  11. Offline

    unrealdesign

    supersonicsauce
    1. Create a instance variable Map<String, Location[]>. The string will be for the players name, and the array of locations will be for the the 2 corners of the region.
    2. On plugin enable, read from the config and write to your new Map with the correct information.
    3. On creation/deletion of a region, add/remove it to your config like normal, but also add/remove it to your new Map.
    4. Create a method canBuild(Player p) method. In this method loop through the new Map and see if the player is in one of the regions between the two locations, if he isn't then he is outside of that region. If he is, check if he is the owner, or check the config and see if he is a member of the region. If then cancel it
    5. Check your canBuild(Player p) method for every event you want
    OR
    1. Create a Region class *PREFERRED*
    2. Create instance variables: Player owner, Set<String> members, Location corner1, Location corner2.
    3. Create getters, setters, and other methods: boolean hasPermission(Player p), boolean inRegion(Location loc).
    4. In your main class or manager class, create a Set<Region>.
    5. Create a new Region instance for every part in your config and add it to the Set<Region> on plugin enable.
    6. When a region is removed/added also update your Set<Region> appropriately.
    7. In your events, loop through your Set<Region> instance variable and see if the player is inRegion(Location loc). If he isn't any any then you're fine. If he is in one, check if he is the hasPermission(). If he does, you're fine, if not, cancel the event.
     
  12. Offline

    supersonicsauce

    unrealdesign
    How do I get a Map from a config?

    Ok. I fixed it.
    For anyone who is having the same issue, here's what I did:

    Make an ArrayList that you will keep your players in.
    Code:java
    1. ArrayList<String> playerlist;
    2. public void onEnable(){
    3. playerlist=newArrayList<String>();
    4. //then, after you've declared it, make it read the list from the config.
    5. playerlist=(ArrayList<String>)getConfig().getStringList("PlayerList");
    6. // don't forget to save your config.
    7. saveConfig();
    8. }
    9.  


    Save your region with this method.
    Code:java
    1. public void saveRegion(Player player, double minX, double minY, double minZ, double maxX, double maxY, double maxZ){
    2. config.addDefault("Regions.players."+player.getName()+".bounds.minX", minX);
    3. config.addDefault("Regions.players."+player.getName()+".bounds.miny", minY);
    4. config.addDefault("Regions.players."+player.getName()+".bounds.minZ", minZ);
    5. config.addDefault("Regions.players."+player.getName()+".bounds.maxX", maxX);
    6. config.addDefault("Regions.players."+player.getName()+".bounds.maxY", maxY);
    7. config.addDefault("Regions.players."+player.getName()+".bounds.maxZ", maxZ);
    8. this.saveConfig();
    9.  
    10.  
    11. }
    12.  
    13.  

    When a player joins, you must add them to the PlayerList that we made earlier. Since there is no way a player can be on the server without joining, it's impossible that any player will not be added to the list.

    Code:java
    1. @EventHandler
    2. public void onJoin(PlayerJoinEvent event){
    3. Player player = event.getPlayer();
    4. //if our array DOES NOT contain the player who is joining
    5. if(!playerlist.contains(player)){
    6. playerlist.add(player.getName());
    7. getConfig().set("PlayerList", playerlist);
    8.  
    9. }
    10. this.saveConfig();
    11. }


    We have everything we need now. So, as an example, here's how we would detect if a player is breaking blocks inside of a region:

    Code:java
    1.  
    2. @EventHandler
    3. public void onMove(BlockBreakEvent event){
    4. //get the list from the config
    5. config.getList("Playerlist");
    6. Player player = event.getPlayer();
    7. Block block = event.getBlock();
    8. //run through our playerlist
    9. for(String p : playerlist){
    10. //basically we are getting the 6 location points from our config, but substituting in the player name for each repetition.
    11. double minX = config.getDouble("Regions.players."+p+".bounds.minX");
    12. double minY = config.getDouble("Regions.players."+p+".bounds.minY");
    13. double minZ = config.getDouble("Regions.players."+p+".bounds.minZ");
    14. double maxX = config.getDouble("Regions.players."+p+".bounds.maxX");
    15. double maxY = config.getDouble("Regions.players."+p+".bounds.maxY");
    16. double maxZ = config.getDouble("Regions.players."+p+".bounds.maxZ");
    17.  
    18. double X = block.getLocation().getX();
    19. double Y = block.getLocation().getY();
    20. double Z = block.getLocation().getZ();
    21.  
    22. if(X <= maxX && X >= minX && Y <= maxY && Y >= minY && Z <= maxZ && Z >= minZ){
    23. System.out.println(player.getName()+" IS BREAKING BLOCKS INSIDE OF "+p+"'s region!");
    24.  
    25. }
    26. }
    27.  
    28. }


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

    xTigerRebornx

    supersonicsauce Could just use ConfigurationSection#getKeys(), where the ConfigurationSection is "Regions.players"
     
  14. Offline

    supersonicsauce

  15. Offline

    xTigerRebornx

    supersonicsauce Something like
    Code:
    config.getConfigurationSection("path").getKeys(false);
    Would return a List<String>, which contains the keys.
    If you have a config like this:
    Code:
    path:
      node:
      value1: 1
      node2:
      value1: 2
      node3:
      value1: 2124142
    Calling getKeys(false) on the section 'path' would return a List<String> containing node, node2, and node3
     
  16. Offline

    supersonicsauce

    xTigerRebornx
    So something along the lines of this?
    Code:java
    1. playerlist = (ArrayList<String>) config.getConfigurationSection("PlayerList").getKeys(false);
    2.  

    Also, what if getKeys(true)? Would it retrieve value1 as 1, then 2, then 2124142?

    Edit: Also, when I don't cast, I get the error Type mismatch: cannot convert from Set<String> to ArrayList<String>
     
  17. Offline

    unrealdesign

    supersonicsauce No, it would just return the paths. You would then have to do config.get(path)

    What do you mean? You create the map, then you iterate through your code and would getKeys(false) for the path to the names, then inside that, you would getKeys(false) to get your locations, then you save to the map with your name, and then create/add the locations from the second getKeys(false) loop. But anyways you found a workingish way, so it doesn't matter until you maybe run into problems. Goodluck

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

    xTigerRebornx

    supersonicsauce No, you don't need the PlayerList. The Path "Regions.players"'s keys are the Player Names. You call getKeys(), passing in false to only get the keys and not its children, and it will return a Set (I believe)with all of those names. tldr, getKeys() replaces the PlayerList.
    Also, you should be storing with UUIDs to prepare for name changes.
     
  19. Offline

    supersonicsauce

    xTigerRebornx unrealdesign
    Ok, I did what both of you suggested and got rid of the playerlist after realizing how pointless it was when I could just get keys. So thank you both very much for your help!
    Now, how would I store a UUID in a config? And how can I get the last known username?
     
  20. Offline

    unrealdesign

    Save UUID: uuid.toString() and save it to the config
    Last name: save all uuids along with the players name to the config. Once a player joins with a uuid the same as one in your config, replace the name with their current name in the config with the corresponding uuid.
     
  21. Offline

    supersonicsauce

    unrealdesign
    How do I replace their name with the one in my config?
    Edit: Ah I see, you mean to replace what I have in my config with the more recent one.
     
Thread Status:
Not open for further replies.

Share This Page