Working Threaded Generation

This commit is contained in:
Shoghi Cervantes 2014-06-10 20:45:09 +02:00
parent 392eb74901
commit fa50cbf4b3
56 changed files with 1631 additions and 1733 deletions

View File

@ -519,16 +519,16 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
unset($this->chunksLoaded[$index]); unset($this->chunksLoaded[$index]);
} }
}else{*/ }else{*/
foreach($this->getLevel()->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){ foreach($this->getLevel()->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){
if($entity !== $this){ if($entity !== $this){
$entity->spawnTo($this); $entity->spawnTo($this);
}
} }
foreach($this->getLevel()->getChunkTiles($this->lastChunk[0], $this->lastChunk[1]) as $tile){ }
if($tile instanceof Spawnable){ foreach($this->getLevel()->getChunkTiles($this->lastChunk[0], $this->lastChunk[1]) as $tile){
$tile->spawnTo($this); if($tile instanceof Spawnable){
} $tile->spawnTo($this);
} }
}
//} //}
$this->lastChunk = false; $this->lastChunk = false;
} }
@ -696,6 +696,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
if($needACK and $identifier !== null){ if($needACK and $identifier !== null){
$this->needACK[$identifier] = false; $this->needACK[$identifier] = false;
return $identifier; return $identifier;
} }
@ -721,6 +722,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
if($needACK and $identifier !== null){ if($needACK and $identifier !== null){
$this->needACK[$identifier] = false; $this->needACK[$identifier] = false;
return $identifier; return $identifier;
} }
@ -970,6 +972,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
return $i; return $i;
} }
} }
return -1; return -1;
} }
@ -1157,6 +1160,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason")); $this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
if($ev->isCancelled()){ if($ev->isCancelled()){
$this->close($ev->getKickMessage(), "Plugin reason"); $this->close($ev->getKickMessage(), "Plugin reason");
return; return;
} }

View File

@ -65,8 +65,8 @@ namespace {
} }
namespace pocketmine { namespace pocketmine {
use LogLevel;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use \LogLevel;
use pocketmine\utils\MainLogger; use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\wizard\Installer; use pocketmine\wizard\Installer;

View File

@ -26,8 +26,6 @@
namespace pocketmine; namespace pocketmine;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\Chest;
use pocketmine\block\Furnace;
use pocketmine\command\CommandReader; use pocketmine\command\CommandReader;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender; use pocketmine\command\ConsoleCommandSender;
@ -40,10 +38,9 @@ use pocketmine\inventory\CraftingManager;
use pocketmine\inventory\InventoryType; use pocketmine\inventory\InventoryType;
use pocketmine\inventory\Recipe; use pocketmine\inventory\Recipe;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\pmf\LevelFormat; use pocketmine\level\format\LevelProviderManager;
use pocketmine\level\generator\Flat; use pocketmine\level\generator\GenerationRequestManager;
use pocketmine\level\generator\Generator; use pocketmine\level\generator\Generator;
use pocketmine\level\generator\Normal;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\level\LevelImport; use pocketmine\level\LevelImport;
use pocketmine\level\WorldGenerator; use pocketmine\level\WorldGenerator;
@ -61,10 +58,11 @@ use pocketmine\nbt\tag\Long;
use pocketmine\nbt\tag\Short; use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String; use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\network\protocol\Info;
use pocketmine\network\query\QueryHandler; use pocketmine\network\query\QueryHandler;
use pocketmine\network\query\QueryPacket;
use pocketmine\network\RakLibInterface; use pocketmine\network\RakLibInterface;
use pocketmine\network\rcon\RCON; use pocketmine\network\rcon\RCON;
use pocketmine\network\SourceInterface;
use pocketmine\network\upnp\UPnP; use pocketmine\network\upnp\UPnP;
use pocketmine\permission\BanList; use pocketmine\permission\BanList;
use pocketmine\permission\DefaultPermissions; use pocketmine\permission\DefaultPermissions;
@ -75,7 +73,6 @@ use pocketmine\scheduler\CallbackTask;
use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\SendUsageTask;
use pocketmine\scheduler\ServerScheduler; use pocketmine\scheduler\ServerScheduler;
use pocketmine\scheduler\TickScheduler; use pocketmine\scheduler\TickScheduler;
use pocketmine\tile\Sign;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Config; use pocketmine\utils\Config;
@ -83,7 +80,6 @@ use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\utils\VersionString; use pocketmine\utils\VersionString;
use pocketmine\network\SourceInterface;
/** /**
* The class that manages everything * The class that manages everything
@ -116,6 +112,9 @@ class Server{
/** @var ServerScheduler */ /** @var ServerScheduler */
private $scheduler = null; private $scheduler = null;
/** @var GenerationRequestManager */
private $generationManager = null;
/** @var TickScheduler */ /** @var TickScheduler */
private $tickScheduler = null; private $tickScheduler = null;
@ -493,6 +492,13 @@ class Server{
return $this->scheduler; return $this->scheduler;
} }
/**
* @return GenerationRequestManager
*/
public function getGenerationManager(){
return $this->generationManager;
}
/** /**
* @return int * @return int
*/ */
@ -781,17 +787,32 @@ class Server{
* @return bool * @return bool
*/ */
public function isLevelLoaded($name){ public function isLevelLoaded($name){
return isset($this->levels[$name]); return $this->getLevelByName($name) instanceof Level;
} }
/** /**
* @param string $name * @param int $levelId
* *
* @return Level * @return Level
*/ */
public function getLevel($name){ public function getLevel($levelId){
if(isset($this->levels[$name])){ if(isset($this->levels[$levelId])){
return $this->levels[$name]; return $this->levels[$levelId];
}
return null;
}
/**
* @param $name
*
* @return Level
*/
public function getLevelByName($name){
foreach($this->getLevels() as $level){
if($level->getName() === $name){
return $level;
}
} }
return null; return null;
@ -802,8 +823,8 @@ class Server{
* @param bool $forceUnload * @param bool $forceUnload
*/ */
public function unloadLevel(Level $level, $forceUnload = false){ public function unloadLevel(Level $level, $forceUnload = false){
if((!$level->isLoaded() or $level->unload($forceUnload) === true) and $this->isLevelLoaded($level->getName())){ if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getName())){
unset($this->levels[$level->getName()]); unset($this->levels[$level->getID()]);
} }
} }
@ -829,20 +850,20 @@ class Server{
} }
$path = $this->getDataPath() . "worlds/" . $name . "/"; $path = $this->getDataPath() . "worlds/" . $name . "/";
$this->logger->info("Preparing level \"" . $name . "\"");
$level = new LevelFormat($path . "level.pmf"); $provider = LevelProviderManager::getProvider($path);
if(!$level->isLoaded){ if($provider === null){
$this->logger->error("Could not load level \"" . $name . "\""); $this->logger->error("Could not load level \"" . $name . "\"");
return false; return false;
} }
//$entities = new Config($path."entities.yml", Config::YAML); //$entities = new Config($path."entities.yml", Config::YAML);
if(file_exists($path . "tileEntities.yml")){ //if(file_exists($path . "tileEntities.yml")){
@rename($path . "tileEntities.yml", $path . "tiles.yml"); // @rename($path . "tileEntities.yml", $path . "tiles.yml");
} //}
$level = new Level($this, $level, $name); $level = new Level($this, $path, $provider);
$this->levels[$level->getName()] = $level; $this->levels[$level->getID()] = $level;
/*foreach($entities->getAll() as $entity){ /*foreach($entities->getAll() as $entity){
if(!isset($entity["id"])){ if(!isset($entity["id"])){
break; break;
@ -872,7 +893,7 @@ class Server{
} }
}*/ }*/
if(file_exists($path . "tiles.yml")){ /*if(file_exists($path . "tiles.yml")){
$tiles = new Config($path . "tiles.yml", Config::YAML); $tiles = new Config($path . "tiles.yml", Config::YAML);
foreach($tiles->getAll() as $tile){ foreach($tiles->getAll() as $tile){
if(!isset($tile["id"])){ if(!isset($tile["id"])){
@ -934,7 +955,7 @@ class Server{
} }
unlink($path . "tiles.yml"); unlink($path . "tiles.yml");
$level->save(true, true); $level->save(true, true);
} }*/
return true; return true;
} }
@ -954,20 +975,32 @@ class Server{
return false; return false;
} }
$seed = $seed === null ? Binary::readInt(Utils::getRandomBytes(4, false)) : (int) $seed;
if($generator !== null and class_exists($generator) and is_subclass_of($generator, "pocketmine\\level\\generator\\Generator")){ if($generator !== null and class_exists($generator) and is_subclass_of($generator, "pocketmine\\level\\generator\\Generator")){
$generator = new $generator($options); $generator = new $generator($options);
}else{ }else{
if(strtoupper($this->getLevelType()) == "FLAT"){ if(strtoupper($this->getLevelType()) == "FLAT"){
$generator = new Flat($options); $generator = Generator::getGenerator("flat");
$options["preset"] = $this->getConfigString("generator-settings", ""); $options["preset"] = $this->getConfigString("generator-settings", "");
}else{ }else{
$generator = new Normal($options); $generator = Generator::getGenerator("normal");
} }
} }
$gen = new WorldGenerator($this, $generator, $name, $seed === null ? Binary::readInt(Utils::getRandomBytes(4, false)) : (int) $seed); $provider = "pocketmine\\level\\format\\anvil\\Anvil";
$gen->generate();
$gen->close(); $path = $this->getDataPath() . "worlds/" . $name . "/";
/** @var \pocketmine\level\format\LevelProvider $provider */
$provider::generate($path, $name, $seed, $generator, $options);
$level = new Level($this, $path, $provider);
$this->levels[$level->getID()] = $level;
for($Z = 6; $Z <= 10; ++$Z){
for($X = 6; $X <= 10; ++$X){
$level->generateChunk($X, $Z);
}
}
return true; return true;
} }
@ -982,7 +1015,7 @@ class Server{
return false; return false;
} }
$path = $this->getDataPath() . "worlds/" . $name . "/"; $path = $this->getDataPath() . "worlds/" . $name . "/";
if(!($this->getLevel($name) instanceof Level) and !file_exists($path . "level.pmf")){ if(!($this->getLevelByName($name) instanceof Level) and !file_exists($path . "level.pmf")){
if(file_exists($path)){ if(file_exists($path)){
$level = new LevelImport($path); $level = new LevelImport($path);
if($level->import() === false){ //Try importing a world if($level->import() === false){ //Try importing a world
@ -1318,6 +1351,10 @@ class Server{
$this->enablePlugins(PluginLoadOrder::STARTUP); $this->enablePlugins(PluginLoadOrder::STARTUP);
$this->generationManager = new GenerationRequestManager($this);
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil");
Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat"); Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat");
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal"); Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal");
@ -1333,10 +1370,9 @@ class Server{
if($this->loadLevel($default) === false){ if($this->loadLevel($default) === false){
$seed = $this->getConfigInt("level-seed", time()); $seed = $this->getConfigInt("level-seed", time());
$this->generateLevel($default, $seed === 0 ? time() : $seed); $this->generateLevel($default, $seed === 0 ? time() : $seed);
$this->loadLevel($default);
} }
$this->setDefaultLevel($this->getLevel($default)); $this->setDefaultLevel($this->getLevelByName($default));
} }
@ -1564,6 +1600,7 @@ class Server{
foreach($this->getLevels() as $level){ foreach($this->getLevels() as $level){
$this->unloadLevel($level, true); $this->unloadLevel($level, true);
} }
$this->generationManager->shutdown();
HandlerList::unregisterAll(); HandlerList::unregisterAll();
$this->scheduler->cancelAllTasks(); $this->scheduler->cancelAllTasks();
@ -1629,6 +1666,7 @@ class Server{
$lastLoop = 0; $lastLoop = 0;
} }
} }
$this->generationManager->handlePackets();
if(($ticks = $this->tick()) !== true){ if(($ticks = $this->tick()) !== true){
++$lastLoop; ++$lastLoop;
@ -1717,7 +1755,7 @@ class Server{
$dump .= "server.properties: " . var_export($p, true) . "\r\n\r\n\r\n"; $dump .= "server.properties: " . var_export($p, true) . "\r\n\r\n\r\n";
if(class_exists("pocketmine\\plugin\\PluginManager", false)){ if(class_exists("pocketmine\\plugin\\PluginManager", false)){
$dump .= "Loaded plugins:\r\n"; $dump .= "Loaded plugins:\r\n";
foreach(PluginManager::getPlugins() as $p){ foreach($this->getPluginManager()->getPlugins() as $p){
$d = $p->getDescription(); $d = $p->getDescription();
$dump .= $d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . "\r\n"; $dump .= $d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . "\r\n";
} }
@ -1751,6 +1789,7 @@ class Server{
$lastLoop = 0; $lastLoop = 0;
} }
} }
$this->generationManager->handlePackets();
if(($ticks = $this->tick()) !== true){ if(($ticks = $this->tick()) !== true){
++$lastLoop; ++$lastLoop;

View File

@ -43,12 +43,12 @@ use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Float; use pocketmine\nbt\tag\Float;
use pocketmine\nbt\tag\Short; use pocketmine\nbt\tag\Short;
use pocketmine\Network;
use pocketmine\network\protocol\MoveEntityPacket_PosRot; use pocketmine\network\protocol\MoveEntityPacket_PosRot;
use pocketmine\network\protocol\MovePlayerPacket; use pocketmine\network\protocol\MovePlayerPacket;
use pocketmine\network\protocol\RemoveEntityPacket; use pocketmine\network\protocol\RemoveEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\SetTimePacket;
use pocketmine\Network;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\Server; use pocketmine\Server;

View File

@ -29,10 +29,10 @@ use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Short; use pocketmine\nbt\tag\Short;
use pocketmine\Network;
use pocketmine\network\protocol\AddPlayerPacket; use pocketmine\network\protocol\AddPlayerPacket;
use pocketmine\network\protocol\RemovePlayerPacket; use pocketmine\network\protocol\RemovePlayerPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Network;
use pocketmine\Player; use pocketmine\Player;
class Human extends Creature implements ProjectileSource, InventoryHolder{ class Human extends Creature implements ProjectileSource, InventoryHolder{

View File

@ -25,7 +25,6 @@ use pocketmine\entity\Entity;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\Event; use pocketmine\Event;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\math\Vector3 as Vector3;
class EntityTeleportEvent extends EntityEvent implements Cancellable{ class EntityTeleportEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;

View File

@ -22,7 +22,6 @@
namespace pocketmine\event\player; namespace pocketmine\event\player;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\item\Item;
use pocketmine\Player; use pocketmine\Player;
/** /**

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\player; namespace pocketmine\event\player;
use pocketmine\event\Cancellable;
use pocketmine\Event; use pocketmine\Event;
use pocketmine\event\Cancellable;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\Player; use pocketmine\Player;

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\server; namespace pocketmine\event\server;
use pocketmine\event;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\event;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\Player; use pocketmine\Player;

View File

@ -21,8 +21,8 @@
namespace pocketmine\event\server; namespace pocketmine\event\server;
use pocketmine\event;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\event;
use pocketmine\network\protocol\DataPacket; use pocketmine\network\protocol\DataPacket;
use pocketmine\Player; use pocketmine\Player;

View File

@ -34,7 +34,6 @@ class Painting extends Item{
public function onActivate(Level $level, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){ public function onActivate(Level $level, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
if($target->isTransparent === false and $face > 1 and $block->isSolid === false){ if($target->isTransparent === false and $face > 1 and $block->isSolid === false){
$server = Server::getInstance();
$faces = array( $faces = array(
2 => 1, 2 => 1,
3 => 3, 3 => 3,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\generator\Generator;
use pocketmine\Server;
use pocketmine\utils\Binary;
use pocketmine\utils\Random;
use pocketmine\utils\Utils;
class WorldGenerator{
private $seed, $level, $path, $random, $generator, $server;
/**
* @param Server $server
* @param Generator $generator
* @param string $name
* @param int $seed
*/
public function __construct(Server $server, Generator $generator, $name, $seed = null){
$this->seed = $seed !== null ? (int) $seed : Binary::readInt(Utils::getRandomBytes(4, false));
$this->random = new Random($this->seed);
$this->server = $server;
$this->path = $this->server->getDataPath() . "worlds/" . $name . "/";
$this->generator = $generator;
$level = new LevelFormat($this->path . "level.pmf", array(
"name" => $name,
"seed" => $this->seed,
"time" => 0,
"spawnX" => 128,
"spawnY" => 128,
"spawnZ" => 128,
"height" => 8,
"generator" => $this->generator->getName(),
"generatorSettings" => $this->generator->getSettings(),
"extra" => ""
));
$this->level = new Level($this->server, $level, $name);
}
public function generate(){
$this->generator->init($this->level, $this->random);
for($Z = 6; $Z <= 10; ++$Z){
for($X = 6; $X <= 10; ++$X){
$this->level->level->loadChunk($X, $Z);
}
}
$this->level->setSpawn($this->generator->getSpawn());
}
public function close(){
$this->level->close();
}
}

View File

@ -151,13 +151,24 @@ interface Chunk{
*/ */
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false); public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false);
/**
* @param Entity $entity
*/
public function addEntity(Entity $entity); public function addEntity(Entity $entity);
/**
* @param Entity $entity
*/
public function removeEntity(Entity $entity); public function removeEntity(Entity $entity);
/**
* @param Tile $tile
*/
public function addTile(Tile $tile); public function addTile(Tile $tile);
/**
* @param Tile $tile
*/
public function removeTile(Tile $tile); public function removeTile(Tile $tile);
/** /**

View File

@ -45,6 +45,29 @@ interface LevelProvider{
*/ */
public static function isValid($path); public static function isValid($path);
/**
* Generate the needed files in the path given
*
* @param string $path
* @param string $name
* @param int $seed
* @param string $generator
* @param array[] $options
*/
public static function generate($path, $name, $seed, $generator, array $options = []);
/**
* Returns the generator name
*
* @return string
*/
public function getGenerator();
/**
* @return array
*/
public function getGeneratorOptions();
/** /**
* Gets the Chunk object * Gets the Chunk object
* This method must be implemented by all the level formats. * This method must be implemented by all the level formats.
@ -92,6 +115,14 @@ interface LevelProvider{
*/ */
public function isChunkGenerated($X, $Z); public function isChunkGenerated($X, $Z);
/**
* @param int $X
* @param int $Z
*
* @return bool
*/
public function isChunkPopulated($X, $Z);
/** /**
* @param int $X * @param int $X
* @param int $Z * @param int $Z
@ -100,6 +131,15 @@ interface LevelProvider{
*/ */
public function isChunkLoaded($X, $Z); public function isChunkLoaded($X, $Z);
/**
* @param int $chunkX
* @param int $chunkZ
* @param SimpleChunk $chunk
*
* @return mixed
*/
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk);
/** /**
* @return string * @return string
*/ */
@ -115,6 +155,16 @@ interface LevelProvider{
*/ */
public function setTime($value); public function setTime($value);
/**
* @return int
*/
public function getSeed();
/**
* @param int $value
*/
public function setSeed($value);
/** /**
* @return Vector3 * @return Vector3
*/ */
@ -135,4 +185,6 @@ interface LevelProvider{
*/ */
public function getLevel(); public function getLevel();
public function close();
} }

View File

@ -0,0 +1,59 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\format;
use pocketmine\Server;
abstract class LevelProviderManager{
protected static $providers = [];
/**
* @param Server $server
* @param string $class
*
* @throws \Exception
*/
public static function addProvider(Server $server, $class){
if(!is_subclass_of($class, "pocketmine\\level\\format\\LevelProvider")){
throw new \Exception("Class is not a subclass of LevelProvider");
}
self::$providers[strtolower($class)] = $class;
}
/**
* Returns a LevelProvider class for this path, or null
*
* @param string $path
*
* @return string
*/
public static function getProvider($path){
foreach(self::$providers as $provider){
/** @var $provider LevelProvider */
if($provider::isValid($path)){
return $provider;
}
}
return null;
}
}

View File

@ -125,9 +125,9 @@ class SimpleChunk{
} }
/** /**
* @param int $x 0-15 * @param int $x 0-15
* @param int $y 0-127 * @param int $y 0-127
* @param int $z 0-15 * @param int $z 0-15
* @param int $blockId 0-255 * @param int $blockId 0-255
*/ */
public function setBlockId($x, $y, $z, $blockId){ public function setBlockId($x, $y, $z, $blockId){
@ -151,9 +151,9 @@ class SimpleChunk{
} }
/** /**
* @param int $x 0-15 * @param int $x 0-15
* @param int $y 0-127 * @param int $y 0-127
* @param int $z 0-15 * @param int $z 0-15
* @param int $data 0-15 * @param int $data 0-15
*/ */
public function setBlockData($x, $y, $z, $data){ public function setBlockData($x, $y, $z, $data){
@ -236,6 +236,7 @@ class SimpleChunk{
$offset += 2048; $offset += 2048;
} }
} }
return new SimpleChunk($chunkX, $chunkZ, $flags, $ids, $meta); return new SimpleChunk($chunkX, $chunkZ, $flags, $ids, $meta);
} }

View File

@ -22,12 +22,21 @@
namespace pocketmine\level\format\anvil; namespace pocketmine\level\format\anvil;
use pocketmine\level\format\generic\BaseLevelProvider; use pocketmine\level\format\generic\BaseLevelProvider;
use pocketmine\level\format\SimpleChunk;
use pocketmine\level\generator\Generator;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\ByteArray;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Int;
use pocketmine\nbt\tag\Long;
use pocketmine\nbt\tag\String;
use pocketmine\Player; use pocketmine\Player;
class Anvil extends BaseLevelProvider{ class Anvil extends BaseLevelProvider{
/** @var RegionLoader */ /** @var RegionLoader[] */
protected $regions = []; protected $regions = [];
/** @var Chunk[] */ /** @var Chunk[] */
@ -38,6 +47,37 @@ class Anvil extends BaseLevelProvider{
return file_exists(realpath($path) . "level.dat") and file_exists(realpath($path) . "region/"); return file_exists(realpath($path) . "level.dat") and file_exists(realpath($path) . "region/");
} }
public static function generate($path, $name, $seed, $generator, array $options = []){
@mkdir($path, 0777, true);
@mkdir($path . "/region", 0777);
//TODO, add extra details
$levelData = new Compound("Data", [
"hardcore" => new Byte("hardcore", 0),
"initialized" => new Byte("initialized", 1),
"GameType" => new Int("GameType", 0),
"generatorVersion" => new Int("generatorVersion", 1), //2 in MCPE
"SpawnX" => new Int("SpawnX", 128),
"SpawnY" => new Int("SpawnY", 70),
"SpawnZ" => new Int("SpawnZ", 128),
"version" => new Int("version", 19133),
"DayTime" => new Int("DayTime", 0),
"LastPlayed" => new Long("LastPlayed", microtime(true) * 1000),
"RandomSeed" => new Long("RandomSeed", $seed),
"SizeOnDisk" => new Long("SizeOnDisk", 0),
"Time" => new Long("Time", 0),
"generatorName" => new String("generatorName", Generator::getGeneratorName($generator)),
"generatorOptions" => new String("generatorOptions", isset($options["preset"]) ? $options["preset"] : ""),
"LevelName" => new String("LevelName", $name),
"GameRules" => new Compound("GameRules", [])
]);
$nbt = new NBT(NBT::BIG_ENDIAN);
$nbt->setData(new Compound(null, [
"Data" => $levelData
]));
$buffer = $nbt->writeCompressed();
@file_put_contents($path . "level.dat", $buffer);
}
public static function getRegionIndex($chunkX, $chunkZ, &$x, &$z){ public static function getRegionIndex($chunkX, $chunkZ, &$x, &$z){
$x = $chunkX >> 5; $x = $chunkX >> 5;
$z = $chunkZ >> 5; $z = $chunkZ >> 5;
@ -47,6 +87,14 @@ class Anvil extends BaseLevelProvider{
$this->chunks = []; $this->chunks = [];
} }
public function getGenerator(){
return $this->levelData["generatorName"];
}
public function getGeneratorOptions(){
return ["preset" => $this->levelData["generatorOptions"]];
}
public function getLoadedChunks(){ public function getLoadedChunks(){
return $this->chunks; return $this->chunks;
} }
@ -88,12 +136,14 @@ class Anvil extends BaseLevelProvider{
} }
unset($this->chunks[Level::chunkHash($x, $z)]); unset($this->chunks[Level::chunkHash($x, $z)]);
return true; return true;
} }
public function saveChunk($x, $z){ public function saveChunk($x, $z){
if($this->isChunkLoaded($x, $z)){ if($this->isChunkLoaded($x, $z)){
$this->getRegion($x >> 5, $z >> 5)->writeChunk($this->getChunk($x, $z)); $this->getRegion($x >> 5, $z >> 5)->writeChunk($this->getChunk($x, $z));
return true; return true;
} }
@ -107,10 +157,18 @@ class Anvil extends BaseLevelProvider{
* @return RegionLoader * @return RegionLoader
*/ */
protected function getRegion($x, $z){ protected function getRegion($x, $z){
$index = $x.":".$z; $index = $x . ":" . $z;
return isset($this->regions[$index]) ? $this->regions[$index] : null; return isset($this->regions[$index]) ? $this->regions[$index] : null;
} }
/**
* @param int $chunkX
* @param int $chunkZ
* @param bool $create
*
* @return Chunk
*/
public function getChunk($chunkX, $chunkZ, $create = false){ public function getChunk($chunkX, $chunkZ, $create = false){
$index = Level::chunkHash($chunkX, $chunkZ); $index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){ if(isset($this->chunks[$index])){
@ -120,18 +178,55 @@ class Anvil extends BaseLevelProvider{
} }
$this->loadChunk($chunkX, $chunkZ); $this->loadChunk($chunkX, $chunkZ);
return $this->getChunk($chunkX, $chunkZ, false); return $this->getChunk($chunkX, $chunkZ, false);
} }
public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){
if($chunk->isGenerated() === false){
$this->unloadChunk($chunkX, $chunkZ, false);
$region = $this->getRegion($chunkX >> 4, $chunkZ >> 4);
$region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
$this->loadChunk($chunkX, $chunkZ);
}else{
$newChunk = $this->getChunk($chunkX, $chunkZ, true);
for($y = 0; $y < 8; ++$y){
$section = new ChunkSection(new Compound(null, [
"Y" => new Byte("Y", $y),
"Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)),
"Data" => new ByteArray("Data", $chunk->getSectionData($y)),
"BlockLight" => new ByteArray("BlockLight", str_repeat("\xff", 2048)), //TODO
"SkyLight" => new ByteArray("SkyLight", str_repeat("\x00", 2048)) //TODO
]));
$newChunk->setSection($y, $section);
}
if($chunk->isPopulated()){
$newChunk->setPopulated(1);
}
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $newChunk;
$this->saveChunk($chunkX, $chunkZ);
}
}
public function isChunkGenerated($chunkX, $chunkZ){ public function isChunkGenerated($chunkX, $chunkZ){
if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){ if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) instanceof RegionLoader){
return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32); return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32);
} }
return false; return false;
} }
public function isChunkPopulated($chunkX, $chunkZ){
$chunk = $this->getChunk($chunkX, $chunkZ);
if($chunk instanceof Chunk){
return $chunk->isPopulated();
}else{
return false;
}
}
protected function loadRegion($x, $z){ protected function loadRegion($x, $z){
$index = $x.":".$z; $index = $x . ":" . $z;
if(isset($this->regions[$index])){ if(isset($this->regions[$index])){
return true; return true;
} }
@ -140,4 +235,13 @@ class Anvil extends BaseLevelProvider{
return true; return true;
} }
public function close(){
$this->unloadChunks();
foreach($this->regions as $index => $region){
$region->doSlowCleanUp();
$region->close();
unset($this->regions[$index]);
}
}
} }

View File

@ -24,8 +24,8 @@ namespace pocketmine\level\format\anvil;
use pocketmine\level\format\generic\BaseChunk; use pocketmine\level\format\generic\BaseChunk;
use pocketmine\level\format\generic\EmptyChunkSection; use pocketmine\level\format\generic\EmptyChunkSection;
use pocketmine\level\format\LevelProvider; use pocketmine\level\format\LevelProvider;
use pocketmine\level\Level;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Enum;
@ -68,11 +68,33 @@ class Chunk extends BaseChunk{
$sections = []; $sections = [];
foreach($this->nbt->Sections as $section){ foreach($this->nbt->Sections as $section){
if($section instanceof Compound){ if($section instanceof Compound){
$sections[(int) $section["Y"]] = new ChunkSection($section); $y = (int) $section["Y"];
if($y < 8){
$sections[$y] = new ChunkSection($section);
}
}
}
for($y = 0; $y < 8; ++$y){
if(!isset($sections[$y])){
$sections[$y] = new EmptyChunkSection($y);
} }
} }
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $sections, $this->nbt["Entities"], $this->nbt["TileEntities"]); parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $sections, $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
}
/**
* @return bool
*/
public function isPopulated(){
return $this->nbt["TerrainPopulated"] > 0;
}
/**
* @param int $value
*/
public function setPopulated($value = 1){
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
} }
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false){ public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false){
@ -103,7 +125,7 @@ class Chunk extends BaseChunk{
//TODO: maxBlockY, biomeMap, biomeTemp //TODO: maxBlockY, biomeMap, biomeTemp
//TODO: time //TODO: time
return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0/*$this->getLevel()->getTime()*/, $blockId, $blockData, $blockSkyLight, $blockLight, $emptySections, null, null, null, null); return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0 /*$this->getLevel()->getTime()*/, $blockId, $blockData, $blockSkyLight, $blockLight, $emptySections, null, null, null, null);
} }
/** /**

View File

@ -27,8 +27,8 @@ class ChunkSnapshot extends BaseChunkSnapshot{
public function getBlockId($x, $y, $z){ public function getBlockId($x, $y, $z){
return ord($this->blockId{ return ord($this->blockId{
(($y >> 4) << 12) //get section index (($y >> 4) << 12) //get section index
+ ($y << 8) + ($z << 4) + $x //get block index in section + ($y << 8) + ($z << 4) + $x //get block index in section
}); });
} }

View File

@ -103,6 +103,9 @@ class RegionLoader{
if($length <= 0){ //Not yet generated if($length <= 0){ //Not yet generated
$this->generateChunk($x, $z); $this->generateChunk($x, $z);
fseek($this->filePointer, $this->locationTable[$index][0] << 12);
$length = Binary::readInt(fread($this->filePointer, 4));
$compression = ord(fgetc($this->filePointer));
} }
if($length > ($this->locationTable[$index][1] << 12)){ //Invalid chunk, bigger than defined number of sectors if($length > ($this->locationTable[$index][1] << 12)){ //Invalid chunk, bigger than defined number of sectors
@ -133,7 +136,7 @@ class RegionLoader{
public function generateChunk($x, $z){ public function generateChunk($x, $z){
$nbt = new Compound("Level", []); $nbt = new Compound("Level", []);
$nbt->xPos = new Int("xPos", ($this->getX() * 32) + $x); $nbt->xPos = new Int("xPos", ($this->getX() * 32) + $x);
$nbt->zPos = new Int("xPos", ($this->getZ() * 32) + $z); $nbt->zPos = new Int("zPos", ($this->getZ() * 32) + $z);
$nbt->LastUpdate = new Long("LastUpdate", 0); $nbt->LastUpdate = new Long("LastUpdate", 0);
$nbt->LightPopulated = new Byte("LightPopulated", 0); $nbt->LightPopulated = new Byte("LightPopulated", 0);
$nbt->TerrainPopulated = new Byte("TerrainPopulated", 0); $nbt->TerrainPopulated = new Byte("TerrainPopulated", 0);
@ -170,6 +173,12 @@ class RegionLoader{
fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $sectors << 12, "\x00", STR_PAD_RIGHT)); fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $sectors << 12, "\x00", STR_PAD_RIGHT));
} }
public function removeChunk($x, $z){
$index = self::getChunkOffset($x, $z);
$this->locationTable[$index][0] = 0;
$this->locationTable[$index][1] = 0;
}
public function writeChunk(Chunk $chunk){ public function writeChunk(Chunk $chunk){
$nbt = $chunk->getNBT(); $nbt = $chunk->getNBT();
$nbt->Sections = new Enum("Sections", []); $nbt->Sections = new Enum("Sections", []);
@ -215,6 +224,11 @@ class RegionLoader{
return $x + ($z << 5); return $x + ($z << 5);
} }
public function close(){
flock($this->filePointer, LOCK_UN);
fclose($this->filePointer);
}
public function doSlowCleanUp(){ public function doSlowCleanUp(){
for($i = 0; $i < 1024; ++$i){ for($i = 0; $i < 1024; ++$i){
if($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0){ if($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0){

View File

@ -26,7 +26,6 @@ use pocketmine\entity\Entity;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\format\ChunkSection; use pocketmine\level\format\ChunkSection;
use pocketmine\level\format\LevelProvider; use pocketmine\level\format\LevelProvider;
use pocketmine\level\Level;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\String; use pocketmine\nbt\tag\String;
use pocketmine\tile\Chest; use pocketmine\tile\Chest;
@ -58,6 +57,8 @@ abstract class BaseChunk implements Chunk{
* @param ChunkSection[] $sections * @param ChunkSection[] $sections
* @param Compound[] $entities * @param Compound[] $entities
* @param Compound[] $tiles * @param Compound[] $tiles
*
* @throws \Exception
*/ */
protected function __construct(LevelProvider $level, $x, $z, array $sections, array $entities = [], array $tiles = []){ protected function __construct(LevelProvider $level, $x, $z, array $sections, array $entities = [], array $tiles = []){
$this->level = new \WeakRef($level); $this->level = new \WeakRef($level);
@ -68,14 +69,11 @@ abstract class BaseChunk implements Chunk{
$this->sections[$Y] = $section; $this->sections[$Y] = $section;
}else{ }else{
trigger_error("Received invalid ChunkSection instance", E_USER_ERROR); trigger_error("Received invalid ChunkSection instance", E_USER_ERROR);
throw new \Exception("Received invalid ChunkSection instance");
return;
} }
if($section >= self::SECTION_COUNT){ if($Y >= self::SECTION_COUNT){
trigger_error("Invalid amount of chunks", E_USER_WARNING); throw new \Exception("Invalid amount of chunks");
return;
} }
} }

View File

@ -20,6 +20,7 @@
*/ */
namespace pocketmine\level\format\generic; namespace pocketmine\level\format\generic;
use pocketmine\level\format\LevelProvider; use pocketmine\level\format\LevelProvider;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -73,14 +74,22 @@ abstract class BaseLevelProvider implements LevelProvider{
$this->levelData->Time = new Int("Time", (int) $value); $this->levelData->Time = new Int("Time", (int) $value);
} }
public function getSeed(){
return $this->levelData["RandomSeed"];
}
public function setSeed($value){
$this->levelData->RandomSeed = new Int("RandomSeed", (int) $value);
}
public function getSpawn(){ public function getSpawn(){
return new Vector3($this->levelData["SpawnX"], $this->levelData["SpawnY"], $this->levelData["SpawnZ"]); return new Vector3($this->levelData["SpawnX"], $this->levelData["SpawnY"], $this->levelData["SpawnZ"]);
} }
public function setSpawn(Vector3 $pos){ public function setSpawn(Vector3 $pos){
$this->levelData->SpawnX = new Int("SpawnX", $pos->x); $this->levelData->SpawnX = new Int("SpawnX", (int) $pos->x);
$this->levelData->SpawnY = new Int("SpawnY", $pos->y); $this->levelData->SpawnY = new Int("SpawnY", (int) $pos->y);
$this->levelData->SpawnZ = new Int("SpawnZ", $pos->z); $this->levelData->SpawnZ = new Int("SpawnZ", (int) $pos->z);
} }
/** /**

View File

@ -27,6 +27,17 @@ use pocketmine\level\format\ChunkSection;
* Stub used to detect empty chunks * Stub used to detect empty chunks
*/ */
class EmptyChunkSection implements ChunkSection{ class EmptyChunkSection implements ChunkSection{
private $y;
public function __construct($y){
$this->y = $y;
}
final public function getY(){
return $this->y;
}
final public function getBlockId($x, $y, $z){ final public function getBlockId($x, $y, $z){
return 0; return 0;
} }
@ -39,6 +50,15 @@ class EmptyChunkSection implements ChunkSection{
return "\x00\x00\x00\x00\x00\x00\x00\x00"; return "\x00\x00\x00\x00\x00\x00\x00\x00";
} }
final public function getBlock($x, $y, $z, &$id = null, &$meta = null){
$id = 0;
$meta = 0;
}
final public function setBlock($x, $y, $z, $id = null, $meta = null){
throw new \Exception("Tried to modify an empty Chunk");
}
public function getIdArray(){ public function getIdArray(){
return str_repeat("\x00", 4096); return str_repeat("\x00", 4096);
} }
@ -56,7 +76,7 @@ class EmptyChunkSection implements ChunkSection{
} }
final public function setBlockId($x, $y, $z, $id){ final public function setBlockId($x, $y, $z, $id){
throw new \Exception("Tried to modify an empty Chunk");
} }
final public function getBlockData($x, $y, $z){ final public function getBlockData($x, $y, $z){
@ -64,7 +84,7 @@ class EmptyChunkSection implements ChunkSection{
} }
final public function setBlockData($x, $y, $z, $data){ final public function setBlockData($x, $y, $z, $data){
throw new \Exception("Tried to modify an empty Chunk");
} }
final public function getBlockLight($x, $y, $z){ final public function getBlockLight($x, $y, $z){
@ -72,7 +92,7 @@ class EmptyChunkSection implements ChunkSection{
} }
final public function setBlockLight($x, $y, $z, $level){ final public function setBlockLight($x, $y, $z, $level){
throw new \Exception("Tried to modify an empty Chunk");
} }
final public function getBlockSkyLight($x, $y, $z){ final public function getBlockSkyLight($x, $y, $z){
@ -80,6 +100,6 @@ class EmptyChunkSection implements ChunkSection{
} }
final public function setBlockSkyLight($x, $y, $z, $level){ final public function setBlockSkyLight($x, $y, $z, $level){
throw new \Exception("Tried to modify an empty Chunk");
} }
} }

View File

@ -21,7 +21,6 @@
namespace pocketmine\level\generator; namespace pocketmine\level\generator;
use pocketmine\level\generator\populator\Populator;
use pocketmine\block\CoalOre; use pocketmine\block\CoalOre;
use pocketmine\block\DiamondOre; use pocketmine\block\DiamondOre;
use pocketmine\block\Dirt; use pocketmine\block\Dirt;
@ -33,7 +32,7 @@ use pocketmine\block\RedstoneOre;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\SimpleChunk; use pocketmine\level\format\SimpleChunk;
use pocketmine\level\generator\populator\Ore; use pocketmine\level\generator\populator\Ore;
use pocketmine\level\Level; use pocketmine\level\generator\populator\Populator;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
@ -100,7 +99,7 @@ class Flat extends Generator{
$b = Item::fromString($b); $b = Item::fromString($b);
$cnt = $matches[2][$i] === "" ? 1 : intval($matches[2][$i]); $cnt = $matches[2][$i] === "" ? 1 : intval($matches[2][$i]);
for($cY = $y, $y += $cnt; $cY < $y; ++$cY){ for($cY = $y, $y += $cnt; $cY < $y; ++$cY){
$this->structure[$cY] = [$b->getID(),$b->getDamage()]; $this->structure[$cY] = [$b->getID(), $b->getDamage()];
} }
} }

View File

@ -23,7 +23,6 @@ namespace pocketmine\level\generator;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\format\SimpleChunk; use pocketmine\level\format\SimpleChunk;
use pocketmine\level\generator\Generator;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\utils\Random; use pocketmine\utils\Random;
@ -77,6 +76,7 @@ class GenerationChunkManager implements ChunkManager{
*/ */
public function getChunk($chunkX, $chunkZ){ public function getChunk($chunkX, $chunkZ){
$index = Level::chunkHash($chunkX, $chunkZ); $index = Level::chunkHash($chunkX, $chunkZ);
return !isset($this->chunks[$index]) ? $this->requestChunk($chunkX, $chunkZ) : $this->chunks[$index]; return !isset($this->chunks[$index]) ? $this->requestChunk($chunkX, $chunkZ) : $this->chunks[$index];
} }
@ -112,6 +112,7 @@ class GenerationChunkManager implements ChunkManager{
protected function requestChunk($chunkX, $chunkZ){ protected function requestChunk($chunkX, $chunkZ){
$chunk = $this->manager->requestChunk($this->levelID, $chunkX, $chunkZ); $chunk = $this->manager->requestChunk($this->levelID, $chunkX, $chunkZ);
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk;
return $chunk; return $chunk;
} }

View File

@ -88,7 +88,6 @@ class GenerationManager{
const PACKET_SHUTDOWN = 0xff; const PACKET_SHUTDOWN = 0xff;
protected $socket; protected $socket;
/** @var \Logger */ /** @var \Logger */
protected $logger; protected $logger;
@ -138,6 +137,9 @@ class GenerationManager{
protected function generateChunk($levelID, $chunkX, $chunkZ){ protected function generateChunk($levelID, $chunkX, $chunkZ){
if(isset($this->levels[$levelID])){ if(isset($this->levels[$levelID])){
$this->levels[$levelID]->populateChunk($chunkX, $chunkZ); //Request population directly $this->levels[$levelID]->populateChunk($chunkX, $chunkZ); //Request population directly
if(isset($this->levels[$levelID])){
$this->sendChunk($levelID, $this->levels[$levelID]->getChunk($chunkX, $chunkZ));
}
//TODO: wait for queue generation (to wait for extra chunk changes) //TODO: wait for queue generation (to wait for extra chunk changes)
} }
} }
@ -171,7 +173,7 @@ class GenerationManager{
*/ */
public function requestChunk($levelID, $chunkX, $chunkZ){ public function requestChunk($levelID, $chunkX, $chunkZ){
$this->needsChunk = [$levelID, $chunkX, $chunkZ]; $this->needsChunk = [$levelID, $chunkX, $chunkZ];
$binary = chr(self::PACKET_REQUEST_CHUNK . Binary::writeInt($levelID) . Binary::writeInt($chunkX) . Binary::writeInt($chunkZ)); $binary = chr(self::PACKET_REQUEST_CHUNK) . Binary::writeInt($levelID) . Binary::writeInt($chunkX) . Binary::writeInt($chunkZ);
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary); @socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
do{ do{
$this->readPacket(); $this->readPacket();
@ -187,14 +189,14 @@ class GenerationManager{
} }
public function sendChunk($levelID, SimpleChunk $chunk){ public function sendChunk($levelID, SimpleChunk $chunk){
$binary = chr(self::PACKET_SEND_CHUNK . Binary::writeInt($levelID) . $chunk->toBinary()); $binary = chr(self::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . $chunk->toBinary();
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary); @socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
} }
protected function readPacket(){ protected function readPacket(){
$len = socket_read($this->socket, 4); $len = @socket_read($this->socket, 4);
if($len === false or $len === ""){ if($len === false or $len === ""){
usleep(5000); $this->shutdown = true;
return; return;
} }
$packet = socket_read($this->socket, Binary::readInt($len)); $packet = socket_read($this->socket, Binary::readInt($len));

View File

@ -0,0 +1,140 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\generator;
use pocketmine\level\format\SimpleChunk;
use pocketmine\level\Level;
use pocketmine\Server;
use pocketmine\utils\Binary;
class GenerationRequestManager{
protected $socket;
/** @var Server */
protected $server;
/** @var GenerationThread */
protected $generationThread;
/**
* @param Server $server
*/
public function __construct(Server $server){
$this->server = $server;
$this->generationThread = new GenerationThread($server->getLogger(), $server->getLoader());
$this->socket = $this->generationThread->getExternalSocket();
}
/**
* @param Level $level
* @param string $generator
* @param array $options
*/
public function openLevel(Level $level, $generator, array $options = []){
$buffer = chr(GenerationManager::PACKET_OPEN_LEVEL) . Binary::writeInt($level->getID()) . Binary::writeInt($level->getSeed()) .
Binary::writeShort(strlen($generator)) . $generator . serialize($options);
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
/**
* @param Level $level
*/
public function closeLevel(Level $level){
$buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($level->getID());
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
public function addNamespace($namespace, $path){
$buffer = chr(GenerationManager::PACKET_ADD_NAMESPACE) . Binary::writeShort(strlen($namespace)) . $namespace . $path;
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
protected function socketRead($len){
$buffer = "";
while(strlen($buffer) < $len){
$buffer .= @socket_read($this->socket, $len - strlen($buffer));
}
return $buffer;
}
protected function sendChunk($levelID, SimpleChunk $chunk){
$binary = chr(GenerationManager::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . $chunk->toBinary();
@socket_write($this->socket, Binary::writeInt(strlen($binary)) . $binary);
}
public function requestChunk(Level $level, $chunkX, $chunkZ){
$buffer = chr(GenerationManager::PACKET_REQUEST_CHUNK) . Binary::writeInt($level->getID()) . Binary::writeInt($chunkX) . Binary::writeInt($chunkZ);
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
protected function handleRequest($levelID, $chunkX, $chunkZ){
if(($level = $this->server->getLevel($levelID)) instanceof Level){
$this->sendChunk($levelID, $level->getChunk($chunkX, $chunkZ, false));
}else{
$buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID);
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
}
protected function receiveChunk($levelID, SimpleChunk $chunk){
if(($level = $this->server->getLevel($levelID)) instanceof Level){
$level->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
}else{
$buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID);
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
}
}
public function handlePackets(){
if(($len = @socket_read($this->socket, 4)) !== false){
if(strlen($len) < 4){
$len .= $this->socketRead(4 - strlen($len));
}
$packet = $this->socketRead(Binary::readInt($len));
$pid = ord($packet{0});
$offset = 1;
if($pid === GenerationManager::PACKET_REQUEST_CHUNK){
$levelID = Binary::readInt(substr($packet, $offset, 4));
$offset += 4;
$chunkX = Binary::readInt(substr($packet, $offset, 4));
$offset += 4;
$chunkZ = Binary::readInt(substr($packet, $offset, 4));
$this->handleRequest($levelID, $chunkX, $chunkZ);
}elseif($pid === GenerationManager::PACKET_SEND_CHUNK){
$levelID = Binary::readInt(substr($packet, $offset, 4));
$offset += 4;
$chunk = SimpleChunk::fromBinary(substr($packet, $offset));
$this->receiveChunk($levelID, $chunk);
}
}
}
public function shutdown(){
$buffer = chr(GenerationManager::PACKET_SHUTDOWN);
@socket_write($this->socket, Binary::writeInt(strlen($buffer)) . $buffer);
$this->generationThread->join();
}
}

View File

@ -50,6 +50,7 @@ class GenerationThread extends \Thread{
public function __construct(\ThreadedLogger $logger, \SplAutoloader $loader){ public function __construct(\ThreadedLogger $logger, \SplAutoloader $loader){
$this->loader = $loader; $this->loader = $loader;
$this->logger = $logger;
$loadPaths = []; $loadPaths = [];
$this->addDependency($loadPaths, new \ReflectionClass($this->logger)); $this->addDependency($loadPaths, new \ReflectionClass($this->logger));
$this->addDependency($loadPaths, new \ReflectionClass($this->loader)); $this->addDependency($loadPaths, new \ReflectionClass($this->loader));
@ -57,7 +58,7 @@ class GenerationThread extends \Thread{
$sockets = []; $sockets = [];
if(!socket_create_pair((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? AF_INET : AF_UNIX), SOCK_STREAM, 0, $sockets)){ if(!socket_create_pair((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? AF_INET : AF_UNIX), SOCK_STREAM, 0, $sockets)){
throw new \Exception("Could not create IPC sockets. Reason: ".socket_strerror(socket_last_error())); throw new \Exception("Could not create IPC sockets. Reason: " . socket_strerror(socket_last_error()));
} }
$this->internalSocket = $sockets[0]; $this->internalSocket = $sockets[0];

View File

@ -24,7 +24,6 @@
*/ */
namespace pocketmine\level\generator; namespace pocketmine\level\generator;
use pocketmine\level\Level;
use pocketmine\utils\Random; use pocketmine\utils\Random;
abstract class Generator{ abstract class Generator{
@ -48,6 +47,16 @@ abstract class Generator{
return "pocketmine\\level\\generator\\Normal"; return "pocketmine\\level\\generator\\Normal";
} }
public static function getGeneratorName($class){
foreach(Generator::$list as $name => $c){
if($c === $class){
return $name;
}
}
return "unknown";
}
public abstract function __construct(array $settings = []); public abstract function __construct(array $settings = []);
public abstract function init(GenerationChunkManager $level, Random $random); public abstract function init(GenerationChunkManager $level, Random $random);

View File

@ -32,12 +32,11 @@ use pocketmine\block\RedstoneOre;
use pocketmine\level\generator\noise\Simplex; use pocketmine\level\generator\noise\Simplex;
use pocketmine\level\generator\object\OreType; use pocketmine\level\generator\object\OreType;
use pocketmine\level\generator\populator\Ore; use pocketmine\level\generator\populator\Ore;
use pocketmine\level\generator\populator\Populator;
use pocketmine\level\generator\populator\TallGrass; use pocketmine\level\generator\populator\TallGrass;
use pocketmine\level\generator\populator\Tree; use pocketmine\level\generator\populator\Tree;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
use pocketmine\level\generator\populator\Populator;
class Normal extends Generator{ class Normal extends Generator{

View File

@ -22,8 +22,6 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
class BigTree extends Tree{ class BigTree extends Tree{
private $trunkHeightMultiplier = 0.618; private $trunkHeightMultiplier = 0.618;

View File

@ -22,8 +22,6 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\math\VectorMath; use pocketmine\math\VectorMath;
use pocketmine\utils\Random; use pocketmine\utils\Random;

View File

@ -21,13 +21,8 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\block\Dirt;
use pocketmine\block\Leaves;
use pocketmine\block\Wood;
use pocketmine\item\Block; use pocketmine\item\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class PineTree extends Tree{ class PineTree extends Tree{

View File

@ -23,7 +23,6 @@ namespace pocketmine\level\generator\object;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;

View File

@ -21,13 +21,8 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\block\Dirt;
use pocketmine\block\Leaves;
use pocketmine\block\Wood;
use pocketmine\item\Block; use pocketmine\item\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class SmallTree extends Tree{ class SmallTree extends Tree{

View File

@ -21,13 +21,8 @@
namespace pocketmine\level\generator\object; namespace pocketmine\level\generator\object;
use pocketmine\block\Dirt;
use pocketmine\block\Leaves;
use pocketmine\block\Wood;
use pocketmine\item\Block; use pocketmine\item\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class SpruceTree extends Tree{ class SpruceTree extends Tree{

View File

@ -23,7 +23,6 @@ namespace pocketmine\level\generator\object;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;

View File

@ -23,8 +23,6 @@ namespace pocketmine\level\generator\object;
use pocketmine\block\Sapling; use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Tree{ class Tree{

View File

@ -22,7 +22,6 @@
namespace pocketmine\level\generator\populator; namespace pocketmine\level\generator\populator;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Mineshaft extends Populator{ class Mineshaft extends Populator{

View File

@ -23,8 +23,6 @@ namespace pocketmine\level\generator\populator;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\generator\object\Ore as ObjectOre; use pocketmine\level\generator\object\Ore as ObjectOre;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Ore extends Populator{ class Ore extends Populator{

View File

@ -23,8 +23,6 @@ namespace pocketmine\level\generator\populator;
use pocketmine\block\Water; use pocketmine\block\Water;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Pond extends Populator{ class Pond extends Populator{

View File

@ -25,7 +25,6 @@
namespace pocketmine\level\generator\populator; namespace pocketmine\level\generator\populator;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\utils\Random; use pocketmine\utils\Random;
abstract class Populator{ abstract class Populator{

View File

@ -22,10 +22,7 @@
namespace pocketmine\level\generator\populator; namespace pocketmine\level\generator\populator;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\TallGrass as BlockTallGrass;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class TallGrass extends Populator{ class TallGrass extends Populator{

View File

@ -25,8 +25,6 @@ use pocketmine\block\Block;
use pocketmine\block\Sapling; use pocketmine\block\Sapling;
use pocketmine\level\ChunkManager; use pocketmine\level\ChunkManager;
use pocketmine\level\generator\object\Tree as ObjectTree; use pocketmine\level\generator\object\Tree as ObjectTree;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\utils\Random; use pocketmine\utils\Random;
class Tree extends Populator{ class Tree extends Populator{

View File

@ -35,6 +35,16 @@ class Enum extends NamedTag implements \ArrayAccess{
} }
} }
public function &getValue(){
$value = [];
foreach($this as $k => $v){
if($v instanceof Tag){
$value[$k] = $v;
}
}
return $value;
}
public function offsetExists($offset){ public function offsetExists($offset){
return isset($this->{$offset}); return isset($this->{$offset});
} }

View File

@ -1,38 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\network\protocol;
class DisconnectPacket extends DataPacket{
public function pid(){
return Info::DISCONNECT_PACKET;
}
public function decode(){
}
public function encode(){
$this->reset();
}
}

View File

@ -21,8 +21,7 @@
namespace pocketmine\network\query; namespace pocketmine\network\query;
use pocketmine\network\Packet; se pocketmine\utils\Binary;
use pocketmine\utils\Binary;
class QueryPacket extends Packet{ class QueryPacket extends Packet{
const HANDSHAKE = 9; const HANDSHAKE = 9;

View File

@ -21,8 +21,8 @@
namespace pocketmine\plugin; namespace pocketmine\plugin;
use \Logger; use Logger;
use \LogLevel; use LogLevel;
use pocketmine\utils\MainLogger; use pocketmine\utils\MainLogger;
class PluginLogger implements Logger{ class PluginLogger implements Logger{

View File

@ -26,7 +26,6 @@ use pocketmine\inventory\DoubleChestInventory;
use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3; use pocketmine\math\Vector3 as Vector3;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;

View File

@ -27,7 +27,6 @@ use pocketmine\inventory\FurnaceRecipe;
use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\InventoryHolder;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;

View File

@ -22,7 +22,6 @@
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Int; use pocketmine\nbt\tag\Int;

View File

@ -22,7 +22,6 @@
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\Player; use pocketmine\Player;

View File

@ -26,7 +26,6 @@
namespace pocketmine\tile; namespace pocketmine\tile;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\level\Position; use pocketmine\level\Position;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
@ -58,11 +57,6 @@ abstract class Tile extends Position{
protected $lastUpdate; protected $lastUpdate;
protected $server; protected $server;
public function getID(){
return $this->id;
}
public function __construct(Chunk $chunk, Compound $nbt){ public function __construct(Chunk $chunk, Compound $nbt){
$this->server = $chunk->getLevel()->getLevel()->getServer(); $this->server = $chunk->getLevel()->getLevel()->getServer();
$this->chunk = $chunk; $this->chunk = $chunk;
@ -80,6 +74,10 @@ abstract class Tile extends Position{
$this->getLevel()->addTile($this); $this->getLevel()->addTile($this);
} }
public function getID(){
return $this->id;
}
public function saveNBT(){ public function saveNBT(){
$this->namedtag["x"] = $this->x; $this->namedtag["x"] = $this->x;
$this->namedtag["y"] = $this->y; $this->namedtag["y"] = $this->y;
@ -94,6 +92,10 @@ abstract class Tile extends Position{
Tile::$needUpdate[$this->id] = $this; Tile::$needUpdate[$this->id] = $this;
} }
public function __destruct(){
$this->close();
}
public function close(){ public function close(){
if($this->closed === false){ if($this->closed === false){
$this->closed = true; $this->closed = true;
@ -103,10 +105,6 @@ abstract class Tile extends Position{
} }
} }
public function __destruct(){
$this->close();
}
public function getName(){ public function getName(){
return $this->name; return $this->name;
} }

View File

@ -20,7 +20,8 @@
*/ */
namespace pocketmine\utils; namespace pocketmine\utils;
use \LogLevel;
use LogLevel;
class MainLogger extends \ThreadedLogger{ class MainLogger extends \ThreadedLogger{
protected $logFile; protected $logFile;