1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Optimization.

Discussion in 'Resources' started by Muqsit, Jan 1, 2017.

  1. Muqsit

    Muqsit Zombie Pigman Verified

    Messages:
    649
    GitHub:
    muqsit
    Everyone wants their server to be unique, feature-rich, lag free, etc. If that's the case, you may have come across statements such as "More plugins = more memory consumption".
    And it is true in most of the cases, depending on how the plugin listens to events and handles them.

    But you definitely don't want to remove a feature-rich plugin just for the sake of performance, do you?
    For this, let's talk OPTIMIZATION!

    1. PlayerMoveEvent

    This is by far the most aggressively called event. It's called during movements such as sneaking, minor coordinate movements, yaw/pitch changes (rotating face) etc. To optimize this event, let's add a simple line right after the event.
    PHP:
    public function onMove(PlayerMoveEvent $event) {
        if (!
    $event->getFrom()->equals($event->getTo())) {
            
    //Your code here.
        
    }
    }
    (Source: HereAuth, by PEMapModder)
    This will reduce call to your code in PlayerMoveEvent by a lot. This still doesn't mean that you can use this event endlessly. Try not to call too many things and not declare too many vars in PlayerMoveEvent.

    If you want check if player has walked, but not rotated...
    PHP:
    public function onMove(PlayerMoveEvent $event) {
        if (
    $event->getTo()->distance($event->getFrom()) > 0.1) {
            
    //player has moved. Head rotation isn't being listened.
        
    }
    }
    (Source: Bukkit Forums)

    2. Item
    Items too can be optimized for performance. Here are a list of things that can be optimized for items. (Please keep in mind: Only optimize when NEEDED).

    > Counting the number of enchants on an item.
    It's better to count via the namedtag (NBT) rather than using count($item->getEnchantments()).
    PHP:
    /** @var Item $item */
    $enchants count($item->getNamedTag()->ench);
    //is faster than...
    $enchants count($item->getEnchantments());
    //Because this^ one actually uses $item->getNamedTag()->ench, then converts it into an array and instantiates it with Enchantment (Enchantment::getEnchantment(...$args)) which is basically double counting.
    > Finding if item has enchantments having level greater than 5 (useful for anti hacks).
    PHP:
    $found false;
    foreach (
    $item->getNamedTag()->ench as $en) {
        if (
    $en["lvl"] > 5) {
            
    $found true;
            break; 
    //break the foreach loop.
        
    }
    }
    If (
    $found) {
        
    //if item has enchantment with level > 5...
    }

    //is faster than...
    $found false
    foreach ($item->getEnchantments() as $en) {
        if (
    $en->getLevel() > 5) {
            
    $found true;
            break;
        }
    }
    /**
    Because, again...This is how getEnchantments() works...

    $enchants = [];
    foreach ($item->getNamedTag()->ench as $en) {
        $enchants[] = Enchantment::getEnchantment($en["id"])->setLevel($en["lvl"]);
    }
    return $enchants;

    So using the slower method is basically like double counting the enchants.
    */
    More coming soon..
     
    Last edited: Jan 1, 2017
    applqpak likes this.
  2. Thunder33345

    Thunder33345 Wither Skeleton Verified

    Messages:
    1,139
    GitHub:
    Thunder33345
    It also helps to do basic check before doing the advance memory consuming task

    Like for example,
    you have a plugin that do certain stuff in lobby when player stand on a specified position
    you should check if (order is important)
    event is cancelled
    player had movement
    player is in lobby world
    player in on the specified position
    also This is the original HereAuth full source code for these who wonders
     
  3. robske_110 (Tim)

    robske_110 (Tim) Zombie Pigman Verified

    Messages:
    762
    GitHub:
    robske_110
    the second one is not guranteed to work all the time, because you can move 0.5blocks and then in the next tick another 0.5block->plugin broken.
    For the first one you should note that you only want to add that if you do not want to do stuff with head/body yaw/pitch
     
    applqpak likes this.
  4. Muqsit

    Muqsit Zombie Pigman Verified

    Messages:
    649
    GitHub:
    muqsit
    Right, thanks for the feedbacks. Edited.
     
    Sandertv and applqpak like this.
  5. Junkdude

    Junkdude Zombie

    Messages:
    325
    GitHub:
    JunkDaCoder
    *custom enchant example pls*
     
  6. Junkdude

    Junkdude Zombie

    Messages:
    325
    GitHub:
    JunkDaCoder
    Lemme restate myself, can you do a tutorial on customnbt tags?
     
  7. xZeroMCPE

    xZeroMCPE Spider Jockey

    Messages:
    34
    It's not that hard, not even hard at all
    Anybody can do it, if they know what they're
    doing....
     
    applqpak and XShockinFireX like this.
  8. SOFe

    SOFe A-Team Staff Member PMMP Team

    Messages:
    961
    GitHub:
    sof3
    Not true. There are DataPacketSendEvent and DataPacketReceiveEvent.
    Wrong use of terms. You don't call some code. You call a function, and whether there is the if-statement or not your event handler function is still called.
    And for most plugins, such check does not improve performance to a meaningful extent. Keep in mind that the PocketMine event handling system is not very fast itself, and triggering the event already has some impact on performance. It would be quite negligible, but if your PlayerMoveEvent code is just something as simple as portals, both of them load comparably.
    You should never call any unnecessary functions anywhere. More precisely, you can try to do things before and after - If you need to fetch some data and data fetching takes a long time, what about storing the data somewhere quickly accessible (e.g. class properties), and update them periodically and upon observable local change? If you have to do something every PlayerMoveEvent call, what about queuing them locally and clear the queue periodically, if doing them together would be faster than splitting into many times? For example, if you call one MySQL UPDATE query every time the player moves (don't ask me; I have perfectly no idea why you want to do that), do you really need them to update so frequently? Maybe you can update them every second or every minute instead?
    Since this thread is full of premature optimization, please note that you can optimize even more if you use distanceSquared instead of distance(). Because d/dx(x^2) is always positive for x>0, and distance is always non-negative, the comparison of the distane can be done through comparing squares instead of the actual distance. Calling sqrt() unnecessary is probably a bit more performance-consuming than declaring one less variable ;) [citation needed]
    And then in the next update PocketMine changes the way it stores enchantments and your method no longer works.
    NBT is an unreliable part of the PocketMine API, and is actually not officially supported. Plugins do not have promised backwards compatibility if they depend on NBT tags. If you can avoid using them, avoid.
    It is probably bad implementation of the getEnchantments() method that PocketMine converts the array every time.
     
  9. Muqsit

    Muqsit Zombie Pigman Verified

    Messages:
    649
    GitHub:
    muqsit
    So items having enchantments and tags will, in the future not be having those? The tags will just vanish away?
     
    applqpak likes this.
  10. SOFe

    SOFe A-Team Staff Member PMMP Team

    Messages:
    961
    GitHub:
    sof3
    The tags will normally not vanish, but they may be deprecated. They are primarily based on Minecraft's saving format, which is subject to change depending on the Minecraft developers' decision. For example, they may be renamed, or changed to another data type, etc.
    After all they are not recommended at all. It's probably a bad idea to count enchantments using the getEnchantments() method, but I believe this is an API implementation method.
    Actually PM is implemented so poorly. NBT is a data saving format, not a native data model. I don't see why it would be a good idea to base on NBT tags so heavily in the API. At least, you should read the NBT tags into PM's own data models (classes) instead of manipulating the tags directly in the implementation code when the data are loaded, e.g. during chunk loading, and written as NBT tags during chunk unloading.
    Optimization? @shoghicp, if you are so concerned about those tiny premature optimization, preprocess all functions inline!
     
    Muqsit, dktapps and HimbeersaftLP like this.

Share This Page