Very annoying *Bug*

Discussion in 'Spigot Plugin Development' started by v_M_v, May 30, 2016.

  1. Hey,

    So I've been spending the past few days creating a plugin, however I knew it wouldn't be simple and I've come across a possible bug. I'm looking for someone with a brain, unlike me to come across a fix for this.

    Here's my problem:

    I'm using WGRegionEvents to execute this code as someone enters a region, which works 100%.

    Code (Text):
     
        @EventHandler
        public void PlayerenterRegion(RegionEnterEvent e) throws IOException {

            File file = new File(plugin.getDataFolder(), File.separator  + "Playerdata" + File.separator + "" + e.getPlayer().getUniqueId() + ".yml");
            YamlConfiguration data = YamlConfiguration.loadConfiguration(file); /* Gets the playerdata folder */

            String splitter = e.getRegion().getId() + "_parkour";
            String[] parts = splitter.split("_");
            String name = parts[0].substring(0, 1).toUpperCase() + parts[0].substring(1);; /*Splits name and capitalises first letter of map name*/

            e.getPlayer().sendMessage(ChatColor.YELLOW + "You joined map: " + name);

            data.set("PixelParkour.Current_map", name);
            data.save(file); /*Sets the Playerdata folder "Current_map" for that user*/
        }
     
    Now, all we need to know about this code is that when a player enters a region it sends them this message:
    http://prntscr.com/bad40r
    The point of this plugin is so that when they reach a destination, in this case when they're on top of a barrier block, they will get teleported OUT of the region which triggers the RegionLeaveEvent, however it seems that when the player gets teleported out of the arena it's triggering the RegionEnterEvent once again (maybe as a safety check?) and displays the join message again.

    Player move event check for teleporting out

    Code (Text):
        @EventHandler
        public void onPlayerMove(PlayerMoveEvent e) throws IOException {

    //I KNOW THIS IS NOT EFFICIENT IT WILL BE FIXED

            File file = new File(plugin.getDataFolder(), File.separator  + "Playerdata" + File.separator + "" + e.getPlayer().getUniqueId() + ".yml");
            YamlConfiguration data = YamlConfiguration.loadConfiguration(file); /* Gets the playerdata folder */
            String name = data.getString("PixelParkour.Current_map");

            if (e.getTo().getBlock().getRelative(BlockFace.DOWN).getType() == Material.BARRIER && !name.equals("None")) {
                Player player = e.getPlayer();
                int mapsCompleted = data.getInt("PixelParkour.Maps_completed") + 1;
                player.sendMessage(ChatColor.GREEN + "Teleported");
                Location tp = new Location(e.getPlayer().getServer().getWorld("Test"), 0, 5, 0);
                player.teleport(tp);
                Location loc = player.getLocation();
                player.playSound(loc, Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f);
                player.playSound(loc, Sound.ENTITY_ITEM_PICKUP, 1f, 1f);
                data.set("PixelParkour.Maps_completed", mapsCompleted);
                player.sendMessage("Finished " + mapsCompleted + " maps!");
                player.sendMessage("That maps name was " + name);
                data.save(file);
            }
        }

    Notes:
    - Teleporting out of the arena with /tp 0 0 0 does NOT trigger the join message
    - I've tried everything I can think of and i'm dying inside

    Please help me :)
     
    #1 v_M_v, May 30, 2016
    Last edited: May 30, 2016
  2. Choco

    Moderator

    Nothing to do with your bug, but any other developer noticing this too?
    You're listening for an event that calls probably hundreds/thousands of times a second, and loading a file every single time? So you're loading a file object and a YamlConfiguration file about 1000x a second? Yeaaaa... that won't be efficient in the slightest.

    Cache some files in a Map<Player, YamlConfiguration> so you don't have to load it so often and overload the server
     
  3. Yes i know this, it's a plugin for personal use. I'm fully aware this is not efficient and i will be fixing it after i resolve this issue
     
  4. Another easier solution, I believe, is to just have a bukkit runnable task timer. Every interval, loop through all players online, check if their position is in a vector (or if the block below them is a barrier block) and act accordingly. This also avoids unnecessary re-triggering as a listener does.
     
  5. Create a new Java class that contains a Bukkit runnable.

    Each time that regionChangeEvent fires, try to add that
    player to a list. Inside that new class, send the message
    to the player.

    However when adding that object to a list, you can
    check if that list already contains that object and thus
    avoid adding the object to the list twice.

    Once the object that contains the Bukkit Runnable
    send the message, with a 1 tick delay, then
    you can have reference back to the class
    that added that object to a list and call a method
    that stops that object's runnable and removes that object
    from the list.