1. The forums will be archived and moved to a read only mode in about 2 weeks (mid march).

Proper way to remove a level from a running server

Discussion in 'Development' started by SteveDev386, Sep 25, 2017.

  1. SteveDev386

    SteveDev386 Silverfish

    Messages:
    17
    GitHub:
    dschwartz783
    I'm curious as to what the best way is to unload a level from a running server, and cleaning up its directory. I'm calling unload() on the level, but shortly after, the server crashes. This is being called from a PluginTask, if that helps. The crash seems "deferred". A few ticks later, it crashes...

    To limit questions, I'll fully explain what I'm working on. I've implemented "Player Vaults" by using a template Vault world, and making a copy for each player. While this isn't the most efficient from a disk usage standpoint (although I'm archiving them when not in use), it's very efficient for performance. The alternative would be to parse the contents of each chest, and save that, which would be horrible on performance or track the changes to the chests as they're modified... For now, I'm storing a copy of the vault for each player, including their changes. When the player leaves the Vault, the Vault is uploaded to a database, and completely erased from the server. This is where the error occurs, although before any cleanup is attempted (shortly after unload).

    If there's a better way to implement this entire thing, I'm all ears. Right now, the crash I'm getting looks like this:

    Code:
    [23:59:49] [Server thread/CRITICAL]: Error: "Call to a member function getName() on null" (EXCEPTION) in "src/pocketmine/level/Level" at line 2681
    [23:59:49] [Server thread/DEBUG]: #0 src/pocketmine/Server(2365): pocketmine\level\Level->getName()
    [23:59:49] [Server thread/DEBUG]: #1 src/pocketmine/Server(2497): pocketmine\Server->checkTickUpdates(integer 358, double 1506311989.3806)
    [23:59:49] [Server thread/DEBUG]: #2 src/pocketmine/Server(2238): pocketmine\Server->tick()
    [23:59:49] [Server thread/DEBUG]: #3 src/pocketmine/Server(2117): pocketmine\Server->tickProcessor()
    [23:59:49] [Server thread/DEBUG]: #4 src/pocketmine/Server(1699): pocketmine\Server->start()
    [23:59:49] [Server thread/DEBUG]: #5 src/pocketmine/PocketMine(553): pocketmine\Server->__construct(BaseClassLoader object, pocketmine\utils\MainLogger object, string phar:///Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/PocketMine-MP.phar/, string /Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/, string /Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/plugins/)
    [23:59:49] [Server thread/DEBUG]: #6 /Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/PocketMine-MP.phar(1): require_once(string phar:///Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/PocketMine-MP.phar/src/pocketmine/PocketMine.php)
    [23:59:49] [Server thread/EMERGENCY]: An unrecoverable error has occurred and the server has crashed. Creating a crash dump
    [23:59:49] [Server thread/EMERGENCY]: Please upload the "/Volumes/APFS_HACK_DRIVE/MCPE_Stuff/MCPEPlanetFiles/crashdumps/Sun_Sep_24-23.59.49-EDT_2017.log" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can.
     

    Attached Files:

    Last edited: Sep 25, 2017
  2. dktapps

    dktapps Administrator Staff Member PMMP Team

    Messages:
    774
    GitHub:
    dktapps
    do you have example code to reproduce this crash? I've had a few reports of this recently.
     
  3. SteveDev386

    SteveDev386 Silverfish

    Messages:
    17
    GitHub:
    dschwartz783
    Sure. The code that I believe is behind this crash isn't really sensitive.

    PHP:
    class UnloadTask extends PluginTask {

       
    /**
        * @var string
        */
       
    private $levelName;

       
    /**
        * UnloadTask constructor.
        * @param string $levelName
        * @param Plugin $owner
        */
       
    public function __construct(string $levelNamePlugin $owner) {
          
    $this->levelName $levelName;

          
    parent::__construct($owner);
       }

       
    /**
        * @param int $currentTick
        */
       
    public function onRun(int $currentTick) {
          
    $plugin $this->getOwner();
          if (
    $plugin instanceof Vault) {
             
    $level $plugin->getServer()->getLevelByName($this->levelName);
             
    $level->unload();
          }
       }
    }
    If this doesn't do anything for you, I can send you my full code in a private message. You'll have to configure a MySQL database as specified in the code if you want to run it, though.

    Although, it could always be indirectly related to any one of the many plugins I run. I'll try disabling them all, and report back. Probably should have done that first. :3

    EDIT: Nah, crashes even with just one plugin loaded.

    Also note that this task is being set up as a delayed task after 20 ticks.
     
    Last edited: Sep 25, 2017
  4. dktapps

    dktapps Administrator Staff Member PMMP Team

    Messages:
    774
    GitHub:
    dktapps
    your problem is that you're using `Level->unload()`... that's an internal method, it doesn't remove the level from the Server. Use `Server->unloadLevel()` instead.

    (This is also a documentation problem... it'll be corrected.)
     
    sharletsings123 and jasonwynn10 like this.
  5. SteveDev386

    SteveDev386 Silverfish

    Messages:
    17
    GitHub:
    dschwartz783
    ...and like that, the error's gone. Wow. I could have sworn I tried that method too, but I guess I tried it somewhere else, in some other context. Thanks.

    EDIT: Ah, I see.
    PHP:
    unset($this->levels[$level->getId()]);
    isn't run if you use the internal method. Gotcha. :p
     
    Last edited: Sep 25, 2017
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.