PMF & Multiworld [part 1]

This commit is contained in:
Shoghi Cervantes Pueyo 2013-04-28 23:44:43 +02:00
parent bbbc54f606
commit db8f50f408
18 changed files with 626 additions and 548 deletions

View File

@ -180,7 +180,7 @@ class BlockAPI{
}else{ }else{
$b = new GenericBlock($id, $meta); $b = new GenericBlock($id, $meta);
} }
if($v instanceof Vector3){ if($v instanceof Position){
$b->position($v); $b->position($v);
} }
return $b; return $b;
@ -197,44 +197,12 @@ class BlockAPI{
return $i; return $i;
} }
public function setBlock(Vector3 $block, $id, $meta, $update = true, $tiles = false){
if(($block instanceof Vector3) or (($block instanceof Block) and $block->inWorld === true)){
$this->server->api->level->setBlock($block->x, $block->y, $block->z, (int) $id, (int) $meta, $update, $tiles);
if($update === true){
$this->blockUpdate($block, BLOCK_UPDATE_NORMAL); //????? water?
$this->blockUpdateAround($block, BLOCK_UPDATE_NORMAL);
}
if($tiles === true){
if(($t = $this->server->api->tileentity->get($block->x, $block->y, $block->z)) !== false){
$t[0]->close();
}
}
return true;
}
return false;
}
public function getBlock($x, $y = 0, $z = 0){
if($x instanceof Vector3){
$y = $x->y;
$z = $x->z;
$x = $x->x;
}
$b = $this->server->api->level->getBlock($x, $y, $z);
return BlockAPI::get($b[0], $b[1], new Vector3($b[2][0], $b[2][1], $b[2][2]));
}
public function getBlockFace(Block $block, $face){
return $this->getBlock($block->getSide($face));
}
function __construct(){ function __construct(){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
} }
public function init(){ public function init(){
$this->server->event("server.tick", array($this, "blockUpdateTick")); $this->server->event("server.tick", array($this, "blockUpdateTick"));
$this->server->addHandler("block.update", array($this, "blockUpdateRemote"), 1);
$this->server->api->console->register("give", "<player> <item[:damage]> [amount]", array($this, "commandHandler")); $this->server->api->console->register("give", "<player> <item[:damage]> [amount]", array($this, "commandHandler"));
} }
@ -291,7 +259,7 @@ class BlockAPI{
public function playerBlockBreak(Player $player, Vector3 $vector){ public function playerBlockBreak(Player $player, Vector3 $vector){
$target = $this->getBlock($vector); $target = $player->level->getBlock($vector);
$item = $player->equipment; $item = $player->equipment;
if($this->server->api->dhandle("player.block.touch", array("type" => "break", "player" => $player, "target" => $target, "item" => $item)) === false){ if($this->server->api->dhandle("player.block.touch", array("type" => "break", "player" => $player, "target" => $target, "item" => $item)) === false){
@ -306,7 +274,7 @@ class BlockAPI{
if($this->server->api->dhandle("player.block.break", array("player" => $player, "target" => $target, "item" => $item)) !== false){ if($this->server->api->dhandle("player.block.break", array("player" => $player, "target" => $target, "item" => $item)) !== false){
$player->lastBreak = microtime(true); $player->lastBreak = microtime(true);
$drops = $target->getDrops($item, $player); $drops = $target->getDrops($item, $player);
$target->onBreak($this, $item, $player); $target->onBreak($item, $player);
}else{ }else{
return $this->cancelAction($target, $player); return $this->cancelAction($target, $player);
} }
@ -320,7 +288,7 @@ class BlockAPI{
return false; return false;
} }
public function drop(Vector3 $pos, Item $item){ public function drop(Position $pos, Item $item){
if($item->getID() === AIR or $item->count <= 0){ if($item->getID() === AIR or $item->count <= 0){
return; return;
} }
@ -335,7 +303,7 @@ class BlockAPI{
$item->count = min($item->getMaxStackSize(), $count); $item->count = min($item->getMaxStackSize(), $count);
$count -= $item->count; $count -= $item->count;
$server = ServerAPI::request(); $server = ServerAPI::request();
$e = $server->api->entity->add(ENTITY_ITEM, $item->getID(), $data); $e = $server->api->entity->add($pos->level, ENTITY_ITEM, $item->getID(), $data);
//$e->speedX = mt_rand(-10, 10) / 100; //$e->speedX = mt_rand(-10, 10) / 100;
//$e->speedY = mt_rand(0, 5) / 100; //$e->speedY = mt_rand(0, 5) / 100;
//$e->speedZ = mt_rand(-10, 10) / 100; //$e->speedZ = mt_rand(-10, 10) / 100;
@ -349,8 +317,8 @@ class BlockAPI{
return false; return false;
} }
$target = $this->getBlock($vector); $target = $player->level->getBlock($vector);
$block = $this->getBlockFace($target, $face); $block = $target->getSide($face);
$item = $player->equipment; $item = $player->equipment;
if($target->getID() === AIR and $this->server->api->dhandle("player.block.place.invalid", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== true){ //If no block exists or not allowed in CREATIVE if($target->getID() === AIR and $this->server->api->dhandle("player.block.place.invalid", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== true){ //If no block exists or not allowed in CREATIVE
@ -364,7 +332,7 @@ class BlockAPI{
$this->blockUpdate($target, BLOCK_UPDATE_TOUCH); $this->blockUpdate($target, BLOCK_UPDATE_TOUCH);
if($target->isActivable === true){ if($target->isActivable === true){
if($this->server->api->dhandle("player.block.activate", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== false and $target->onActivate($this, $item, $player) === true){ if($this->server->api->dhandle("player.block.activate", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== false and $target->onActivate($item, $player) === true){
return false; return false;
} }
} }
@ -397,11 +365,11 @@ class BlockAPI{
if($this->server->api->dhandle("player.block.place", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) === false){ if($this->server->api->dhandle("player.block.place", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) === false){
return $this->cancelAction($block, $player); return $this->cancelAction($block, $player);
}elseif($hand->place($this, $item, $player, $block, $target, $face, $fx, $fy, $fz) === false){ }elseif($hand->place($item, $player, $block, $target, $face, $fx, $fy, $fz) === false){
return $this->cancelAction($block, $player); return $this->cancelAction($block, $player);
} }
if($hand->getID() === SIGN_POST or $hand->getID() === WALL_POST){ if($hand->getID() === SIGN_POST or $hand->getID() === WALL_POST){
$t = $this->server->api->tileentity->addSign($block->x, $block->y, $block->z); $t = $this->server->api->tileentity->addSign($player->level, $block->x, $block->y, $block->z);
$t->data["creator"] = $player->username; $t->data["creator"] = $player->username;
} }
@ -769,36 +737,42 @@ class BlockAPI{
} }
}*/ }*/
public function blockUpdateAround(Vector3 $pos, $type = BLOCK_UPDATE_NORMAL){ public function blockUpdateAround(Position $pos, $type = BLOCK_UPDATE_NORMAL){
$this->blockUpdate($pos->getSide(0), $type);
$this->blockUpdate($pos->getSide(1), $type);
$this->blockUpdate($pos->getSide(2), $type);
$this->blockUpdate($pos->getSide(3), $type);
$this->blockUpdate($pos->getSide(4), $type);
$this->blockUpdate($pos->getSide(5), $type);
}
public function blockUpdate(Vector3 $pos, $type = BLOCK_UPDATE_NORMAL){
if(!($pos instanceof Block)){ if(!($pos instanceof Block)){
$pos = $pos->floor(); $pos = $pos->floor();
$block = $this->getBlock($pos); $block = $pos->level->getBlock($pos);
}else{ }else{
$block = $pos; $block = $pos;
} }
$level = $block->onUpdate($this, $type); $this->blockUpdate($block->getSide(0), $type);
$this->blockUpdate($block->getSide(1), $type);
$this->blockUpdate($block->getSide(2), $type);
$this->blockUpdate($block->getSide(3), $type);
$this->blockUpdate($block->getSide(4), $type);
$this->blockUpdate($block->getSide(5), $type);
}
public function blockUpdate(Position $pos, $type = BLOCK_UPDATE_NORMAL){
if(!($pos instanceof Block)){
$pos = $pos->floor();
$block = $pos->level->getBlock($pos);
}else{
$block = $pos;
}
$level = $block->onUpdate($type);
if($level === BLOCK_UPDATE_NORMAL){ if($level === BLOCK_UPDATE_NORMAL){
$this->blockUpdateAround($block, $level); $this->blockUpdateAround($block, $level);
} }
return $level; return $level;
} }
public function scheduleBlockUpdate(Vector3 $pos, $delay, $type = BLOCK_UPDATE_SCHEDULED){ public function scheduleBlockUpdate(Position $pos, $delay, $type = BLOCK_UPDATE_SCHEDULED){
$type = (int) $type; $type = (int) $type;
if($delay < 0){ if($delay < 0){
return false; return false;
} }
$pos = $pos->floor(); $pos = $pos->floor();
$index = $pos->x.".".$pos->y.".".$pos->z; $index = $pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName();
$delay = microtime(true) + $delay * 0.05; $delay = microtime(true) + $delay * 0.05;
if(!isset($this->scheduledUpdates[$index])){ if(!isset($this->scheduledUpdates[$index])){
$this->scheduledUpdates[$index] = array( $this->scheduledUpdates[$index] = array(
@ -806,29 +780,21 @@ class BlockAPI{
$type, $type,
$delay, $delay,
); );
$this->server->query("INSERT INTO blockUpdates (x, y, z, delay) VALUES (".$pos->x.", ".$pos->y.", ".$pos->z.", ".$delay.");"); $this->server->query("INSERT INTO blockUpdates (x, y, z, level, delay) VALUES (".$pos->x.", ".$pos->y.", ".$pos->z.", '".$pos->level->getName()."', ".$delay.");");
return true; return true;
} }
return false; return false;
} }
public function blockUpdateRemote($data, $event){
if($event !== "block.update"){
return;
}
$this->blockUpdate(new Vector3($data["x"], $data["y"], $data["z"]), isset($data["type"]) ? ((int) $data["type"]):BLOCK_UPDATE_RANDOM);
return true;
}
public function blockUpdateTick($time, $event){ public function blockUpdateTick($time, $event){
if($event !== "server.tick"){ //WTF?? if($event !== "server.tick"){ //WTF??
return; return;
} }
if(count($this->scheduledUpdates) > 0){ if(count($this->scheduledUpdates) > 0){
$update = $this->server->query("SELECT x,y,z FROM blockUpdates WHERE delay <= ".$time.";"); $update = $this->server->query("SELECT x,y,z,level FROM blockUpdates WHERE delay <= ".$time.";");
if($update !== false and $update !== true){ if($update !== false and $update !== true){
while(($up = $update->fetchArray(SQLITE3_ASSOC)) !== false){ while(($up = $update->fetchArray(SQLITE3_ASSOC)) !== false){
$index = $up["x"].".".$up["y"].".".$up["z"]; $index = $up["x"].".".$up["y"].".".$up["z"].".".$up["level"];
if(isset($this->scheduledUpdates[$index])){ if(isset($this->scheduledUpdates[$index])){
$up = $this->scheduledUpdates[$index]; $up = $this->scheduledUpdates[$index];
unset($this->scheduledUpdates[$index]); unset($this->scheduledUpdates[$index]);

View File

@ -27,13 +27,17 @@ the Free Software Foundation, either version 3 of the License, or
class EntityAPI{ class EntityAPI{
private $server; private $server;
private $entities;
private $eCnt = 1;
function __construct(){ function __construct(){
$this->entities = array();
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
} }
public function get($eid){ public function get($eid){
if(isset($this->server->entities[$eid])){ if(isset($this->entities[$eid])){
return $this->server->entities[$eid]; return $this->entities[$eid];
} }
return false; return false;
} }
@ -42,8 +46,21 @@ class EntityAPI{
} }
public function getAll(){ public function getAll($level = null){
return $this->server->entities; if($level instanceof Level){
$entities = array();
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$this->level->getName()."';");
if($l !== false and $l !== true){
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
$e = $this->get($e["EID"]);
if($e instanceof Entity){
$entities[$e->eid] = $e;
}
}
}
return $entities;
}
return $this->entities;
} }
public function heal($eid, $heal = 1, $cause){ public function heal($eid, $heal = 1, $cause){
@ -58,11 +75,11 @@ class EntityAPI{
$e->setHealth($e->getHealth() - $attack, $cause, $force); $e->setHealth($e->getHealth() - $attack, $cause, $force);
} }
public function add($class, $type = 0, $data = array()){ public function add(Level $level, $class, $type = 0, $data = array()){
$eid = $this->server->eidCnt++; $eid = $this->eCnt++;
$this->server->entities[$eid] = new Entity($eid, $class, $type, $data); $this->entities[$eid] = new Entity($level, $eid, $class, $type, $data);
$this->server->handle("entity.add", $this->server->entities[$eid]); $this->server->handle("entity.add", $this->entities[$eid]);
return $this->server->entities[$eid]; return $this->entities[$eid];
} }
public function spawnTo($eid, $player){ public function spawnTo($eid, $player){
@ -92,10 +109,10 @@ class EntityAPI{
} }
public function remove($eid){ public function remove($eid){
if(isset($this->server->entities[$eid])){ if(isset($this->entities[$eid])){
$entity = $this->server->entities[$eid]; $entity = $this->entities[$eid];
$this->server->entities[$eid] = null; $this->entities[$eid] = null;
unset($this->server->entities[$eid]); unset($this->entities[$eid]);
$entity->closed = true; $entity->closed = true;
$this->server->query("DELETE FROM entities WHERE EID = ".$eid.";"); $this->server->query("DELETE FROM entities WHERE EID = ".$eid.";");
$this->server->api->dhandle("entity.remove", $entity); $this->server->api->dhandle("entity.remove", $entity);

View File

@ -26,15 +26,80 @@ the Free Software Foundation, either version 3 of the License, or
*/ */
class LevelAPI{ class LevelAPI{
private $server, $map; private $server, $levels, $default;
function __construct(){ public function __construct(){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
$this->map = $this->server->map; $this->levels = array();
$this->heightMap = array_fill(0, 256, array()); $this->map = $this->server->level;
}
public function getDefault(){
return $this->levels[$this->default];
} }
public function init(){ public function init(){
$this->default = $this->server->api->getProperty("level-name");
if($this->loadLevel($this->default) === false){
$path = DATA_PATH."worlds/".$this->default."/";
$generator = "SuperflatGenerator";
if($this->server->api->getProperty("generator") !== false and class_exists($this->server->api->getProperty("generator"))){
$generator = $this->server->api->getProperty("generator");
}
$gen = new WorldGenerator($generator, $this->server->seed);
if($this->server->api->getProperty("generator-settings") !== false and trim($this->server->api->getProperty("generator-settings")) != ""){
$gen->set("preset", $this->server->api->getProperty("generator-settings"));
}
$gen->init();
$gen->generate();
$gen->save($path, $this->default);
$this->loadLevel($this->default)
}
}
public function loadLevel($name){
$path = DATA_PATH."worlds/".$name."/";
if(!file_exists($path."level.pmf")){
$level = new LevelImport($path);
if($level->import() === false){
return false;
}
}
console("[INFO] Preparing level \"".$name."\"");
$level = new PMFLevel($path."level.pmf");
$entities = new Config($path."entities.yml", CONFIG_YAML);
$tileEntities = new Config($path."tileEntities.yml", CONFIG_YAML);
$this->levels[$name] = new Level($level, $entities, $tileEntities);
foreach($entities->getAll() as $entity){
if(!isset($entity["id"])){
break;
}
if($entity["id"] === 64){ //Item Drop
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_ITEM, $entity["Item"]["id"], array(
"meta" => $entity["Item"]["Damage"],
"stack" => $entity["Item"]["Count"],
"x" => $entity["Pos"][0],
"y" => $entity["Pos"][1],
"z" => $entity["Pos"][2],
"yaw" => $entity["Rotation"][0],
"pitch" => $entity["Rotation"][1],
));
}elseif($entity["id"] === OBJECT_PAINTING){ //Painting
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_OBJECT, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}else{
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_MOB, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}
}
foreach($tileEntities->getAll() as $tile){
if(!isset($tile["id"])){
break;
}
$t = $this->server->api->tileentity->add($this->levels[$name], $tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
}
} }
public function handle($data, $event){ public function handle($data, $event){
@ -46,91 +111,124 @@ class LevelAPI{
return $this->server->spawn; return $this->server->spawn;
} }
public function getChunk($X, $Z){ /*
return $this->map->map[$X][$Z]; if(file_exists(DATA_PATH."worlds/level.dat")){
} console("[NOTICE] Detected unimported map data. Importing...");
$this->importMap(DATA_PATH."worlds/", true);
public function getBlockFace($block, $face){ }
$data = array("x" => $block[2][0], "y" => $block[2][1], "z" => $block[2][2]);
BlockFace::setPosition($data, $face); $this->server->mapName = $this->getProperty("level-name");
return $this->getBlock($data["x"], $data["y"], $data["z"]); $this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
} if($this->server->mapName === false or trim($this->server->mapName) === "" or (!file_exists($this->server->mapDir."chunks.dat") and !file_exists($this->server->mapDir."chunks.dat.gz") and !file_exists($this->server->mapDir."level.pmf"))){
if($this->server->mapName === false or trim($this->server->mapName) === ""){
public function getBlock($x, $y, $z){ $this->server->mapName = "world";
$b = $this->map->getBlock($x, $y, $z); }
$b[2] = array($x, $y, $z); $this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
return $b; $generator = "SuperflatGenerator";
} if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){
$generator = $this->getProperty("generator");
public function getFloor($x, $z){ }
if(!isset($this->heightMap[$z][$x])){ $this->gen = new WorldGenerator($generator, $this->server->seed);
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z); if($this->getProperty("generator-settings") !== false and trim($this->getProperty("generator-settings")) != ""){
$this->gen->set("preset", $this->getProperty("generator-settings"));
}
$this->gen->init();
$this->gen->generate();
$this->gen->save($this->server->mapDir, $this->server->mapName);
$this->setProperty("level-name", $this->server->mapName);
$this->setProperty("gamemode", SURVIVAL);
}
$this->server->loadMap();
*/
public function loadMap(){
if($this->mapName !== false and trim($this->mapName) !== ""){
if(!file_exists($this->mapDir."level.pmf")){
$level = new LevelImport($this->mapDir);
$level->import();
}
$this->level = new PMFLevel($this->mapDir."level.pmf");
console("[INFO] Preparing level \"".$this->level->getData("name")."\"");
$this->time = (int) $this->level->getData("time");
$this->seed = (int) $this->level->getData("seed");
$this->spawn = $this->level->getSpawn();
} }
return $this->heightMap[$z][$x];
} }
public function setBlock($x, $y, $z, $block, $meta = 0){ public function save($final = false){
if($x < 0 or $y < 0 or $z < 0){ if($this->mapName !== false){
return false; $this->levelData["Time"] = $this->time;
} file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
if($this->server->api->dhandle("block.change", array( $this->map->saveMap($final);
"x" => $x, $this->trigger("server.save", $final);
"y" => $y, if(count($this->entities) > 0){
"z" => $z, $entities = array();
"block" => $block, foreach($this->entities as $entity){
"meta" => $meta, if($entity->class === ENTITY_MOB){
)) !== false){ $entities[] = array(
$this->map->setBlock($x, $y, $z, $block, $meta); "id" => $entity->type,
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z); "Color" => @$entity->data["Color"],
} "Sheared" => @$entity->data["Sheared"],
return true; "Health" => $entity->health,
} "Pos" => array(
0 => $entity->x,
public function getOrderedChunks($X, $Z, $columnsPerPacket = 2){ 1 => $entity->y,
$columnsPerPacket = max(1, (int) $columnsPerPacket); 2 => $entity->z,
$ordered = array(); ),
$i = 0; "Rotation" => array(
$cnt = 0; 0 => $entity->yaw,
$ordered[$i] = ""; 1 => $entity->pitch,
for($z = 0; $z < 16; ++$z){ ),
for($x = 0; $x < 16; ++$x){ );
if($cnt >= $columnsPerPacket){ }elseif($entity->class === ENTITY_OBJECT){
++$i; $entities[] = array(
$ordered[$i] = str_repeat("\x00", $i * $columnsPerPacket); "id" => $entity->type,
$cnt = 0; "TileX" => $entity->x,
"TileX" => $entity->y,
"TileX" => $entity->z,
"Health" => $entity->health,
"Motive" => $entity->data["Motive"],
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => $entity->yaw,
1 => $entity->pitch,
),
);
}elseif($entity->class === ENTITY_ITEM){
$entities[] = array(
"id" => 64,
"Item" => array(
"id" => $entity->type,
"Damage" => $entity->meta,
"Count" => $entity->stack,
),
"Health" => $entity->health,
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => 0,
1 => 0,
),
);
}
} }
$ordered[$i] .= "\xff"; file_put_contents($this->mapDir."entities.dat", serialize($entities));
$block = $this->map->getChunkColumn($X, $Z, $x, $z, 0); }
$meta = $this->map->getChunkColumn($X, $Z, $x, $z, 1); if(count($this->tileEntities) > 0){
for($k = 0; $k < 8; ++$k){ $tiles = array();
$ordered[$i] .= substr($block, $k << 4, 16); foreach($this->tileEntities as $tile){
$ordered[$i] .= substr($meta, $k << 3, 8); $tiles[] = $tile->data;
} }
++$cnt; file_put_contents($this->mapDir."tileEntities.dat", serialize($tiles));
} }
} }
return $ordered;
} }
public function getMiniChunk($X, $Z, $Y, $MTU){
$ordered = array();
$i = 0;
$ordered[$i] = "";
$cnt = 0;
for($z = 0; $z < 16; ++$z){
for($x = 0; $x < 16; ++$x){
if((strlen($ordered[$i]) + 16 + 8 + 1) > $MTU){
++$i;
$ordered[$i] = str_repeat("\x00", $cnt);
}
$ordered[$i] .= chr(1 << $Y);
$block = $this->map->getChunkColumn($X, $Z, $x, $z, 0);
$meta = $this->map->getChunkColumn($X, $Z, $x, $z, 1);
$ordered[$i] .= substr($block, $Y << 4, 16);
$ordered[$i] .= substr($meta, $Y << 3, 8);
++$cnt;
}
}
return $ordered;
}
} }

View File

@ -318,14 +318,16 @@ class PlayerAPI{
$default = array( $default = array(
"caseusername" => $name, "caseusername" => $name,
"position" => array( "position" => array(
"x" => $this->server->spawn["x"], "level" => $this->server->spawn->level->getName(),
"y" => $this->server->spawn["y"], "x" => $this->server->spawn->x,
"z" => $this->server->spawn["z"], "y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
), ),
"spawn" => array( "spawn" => array(
"x" => $this->server->spawn["x"], "level" => $this->server->spawn->level->getName(),
"y" => $this->server->spawn["y"], "x" => $this->server->spawn->x,
"z" => $this->server->spawn["z"], "y" => $this->server->spawn->y,
"z" => $this->server->spawn->z,
), ),
"inventory" => array_fill(0, 36, array(AIR, 0, 0)), "inventory" => array_fill(0, 36, array(AIR, 0, 0)),
"armor" => array_fill(0, 4, array(AIR, 0, 0)), "armor" => array_fill(0, 4, array(AIR, 0, 0)),

View File

@ -54,7 +54,7 @@ class ServerAPI{
@mkdir(DATA_PATH."players/", 0755); @mkdir(DATA_PATH."players/", 0755);
@mkdir(DATA_PATH."worlds/", 0755); @mkdir(DATA_PATH."worlds/", 0755);
@mkdir(DATA_PATH."plugins/", 0755); @mkdir(DATA_PATH."plugins/", 0755);
console("[INFO] \x1b[33;1mPocketMine-MP ".MAJOR_VERSION.", LGPL License", true, true, 0); console("[INFO] \x1b[33;1mPocketMine-MP ".MAJOR_VERSION." API #".CURRENT_API_VERSION.", LGPL License", true, true, 0);
console("[INFO] Loading properties..."); console("[INFO] Loading properties...");
$this->config = new Config(DATA_PATH . "server.properties", CONFIG_PROPERTIES, array( $this->config = new Config(DATA_PATH . "server.properties", CONFIG_PROPERTIES, array(
@ -149,33 +149,9 @@ class ServerAPI{
} }
} }
if(file_exists(DATA_PATH."worlds/level.dat")){
console("[NOTICE] Detected unimported map data. Importing...");
$this->importMap(DATA_PATH."worlds/", true);
}
$this->server->mapName = $this->getProperty("level-name");
$this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
if($this->server->mapName === false or trim($this->server->mapName) === "" or (!file_exists($this->server->mapDir."chunks.dat") and !file_exists($this->server->mapDir."chunks.dat.gz"))){
if($this->server->mapName === false or trim($this->server->mapName) === ""){
$this->server->mapName = "world";
}
$this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
$generator = "SuperflatGenerator";
if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){
$generator = $this->getProperty("generator");
}
$this->gen = new WorldGenerator($generator, $this->server->seed);
if($this->getProperty("generator-settings") !== false and trim($this->getProperty("generator-settings")) != ""){
$this->gen->set("preset", $this->getProperty("generator-settings"));
}
$this->gen->init();
$this->gen->generate();
$this->gen->save($this->server->mapDir, $this->server->mapName);
$this->setProperty("level-name", $this->server->mapName);
$this->setProperty("gamemode", SURVIVAL);
}
$this->loadProperties(); $this->loadProperties();
$this->server->loadMap();
$this->loadAPI("console", "ConsoleAPI"); $this->loadAPI("console", "ConsoleAPI");
$this->loadAPI("level", "LevelAPI"); $this->loadAPI("level", "LevelAPI");
@ -228,7 +204,7 @@ class ServerAPI{
"online" => count($this->server->clients), "online" => count($this->server->clients),
"max" => $this->server->maxClients, "max" => $this->server->maxClients,
"plugins" => $plist, "plugins" => $plist,
), 2); ), 10);
} }
public function __destruct(){ public function __destruct(){
@ -480,7 +456,7 @@ class ServerAPI{
} }
$this->$name = new $class(); $this->$name = new $class();
$this->apiList[] = $this->$name; $this->apiList[] = $this->$name;
console("[".($internal === true ? "INTERNAL":"DEBUG")."] API \x1b[36m".$name."\x1b[0m [\x1b[30;1m".$class."\x1b[0m] loaded", true, true, ($internal === true ? 2:1)); console("[".($internal === true ? "INTERNAL":"DEBUG")."] API \x1b[36m".$name."\x1b[0m [\x1b[30;1m".$class."\x1b[0m] loaded", true, true, ($internal === true ? 3:2));
} }
} }

View File

@ -27,21 +27,15 @@ the Free Software Foundation, either version 3 of the License, or
class TileEntityAPI{ class TileEntityAPI{
private $server; private $server;
private $tileEntities;
private $tCnt = 1;
function __construct(){ function __construct(){
$this->tileEntities = array();
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
} }
public function get($x, $y = false, $z = false){ public function get(Position $pos){
if(($x instanceof Vector3) or ($x instanceof Block)){ $tiles = $this->server->query("SELECT * FROM tileentities WHERE level = '".$pos->level->getName()."' AND x = {$pos->x} AND y = {$pos->y} AND z = {$pos->z};");
$z = (int) $x->z;
$y = (int) $x->y;
$x = (int) $x->x;
}else{
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
}
$tiles = $this->server->query("SELECT * FROM tileentities WHERE x = $x AND y = $y AND z = $z;");
$ret = array(); $ret = array();
if($tiles !== false and $tiles !== true){ if($tiles !== false and $tiles !== true){
while(($t = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){ while(($t = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){
@ -61,8 +55,8 @@ class TileEntityAPI{
public function getByID($id){ public function getByID($id){
if($id instanceof TileEntity){ if($id instanceof TileEntity){
return $id; return $id;
}elseif(isset($this->server->tileEntities[$id])){ }elseif(isset($this->tileEntities[$id])){
return $this->server->tileEntities[$id]; return $this->tileEntities[$id];
} }
return false; return false;
} }
@ -71,18 +65,31 @@ class TileEntityAPI{
} }
public function getAll(){ public function getAll($level = null){
return $this->server->tileEntities; if($level instanceof Level){
$tileEntities = array();
$l = $this->server->query("SELECT ID FROM tileentities WHERE level = '".$this->level->getName()."';");
if($l !== false and $l !== true){
while(($t = $l->fetchArray(SQLITE3_ASSOC)) !== false){
$t = $this->get($e["ID"]);
if($t instanceof TileEntity){
$tileEntities[$t->id] = $t;
}
}
}
return $tileEntities;
}
return $this->tileEntities;
} }
public function add($class, $x, $y, $z, $data = array()){ public function add(Level $level, $class, $x, $y, $z, $data = array()){
$id = $this->tCnt++; $id = $this->tCnt++;
$this->server->tileEntities[$id] = new TileEntity($id, $class, $x, $y, $z, $data); $this->tileEntities[$id] = new TileEntity($id, $class, $x, $y, $z, $data);
$this->spawnToAll($id); $this->spawnToAll($id);
return $this->server->tileEntities[$id]; return $this->tileEntities[$id];
} }
public function addSign($x, $y, $z, $lines = array("", "", "", "")){ public function addSign(Level $level, $x, $y, $z, $lines = array("", "", "", "")){
return $this->add(TILE_SIGN, $x, $y, $z, $data = array( return $this->add(TILE_SIGN, $x, $y, $z, $data = array(
"id" => "Sign", "id" => "Sign",
"x" => $x, "x" => $x,
@ -122,10 +129,10 @@ class TileEntityAPI{
} }
public function remove($id){ public function remove($id){
if(isset($this->server->tileEntities[$id])){ if(isset($this->tileEntities[$id])){
$t = $this->server->tileEntities[$id]; $t = $this->tileEntities[$id];
$this->server->tileEntities[$id] = null; $this->tileEntities[$id] = null;
unset($this->server->tileEntities[$id]); unset($this->tileEntities[$id]);
$t->closed = true; $t->closed = true;
$t->close(); $t->close();
$this->server->query("DELETE FROM tileentities WHERE ID = ".$id.";"); $this->server->query("DELETE FROM tileentities WHERE ID = ".$id.";");

View File

@ -81,19 +81,19 @@ class Player{
$this->ip = $ip; $this->ip = $ip;
$this->port = $port; $this->port = $port;
$this->itemEnforcement = $this->server->api->getProperty("item-enforcement"); $this->itemEnforcement = $this->server->api->getProperty("item-enforcement");
$this->spawnPosition = new Vector3($this->server->spawn["x"], $this->server->spawn["y"], $this->server->spawn["z"]); $this->spawnPosition = $this->server->spawn;
$this->timeout = microtime(true) + 20; $this->timeout = microtime(true) + 20;
$this->inventory = array_fill(0, 36, array(AIR, 0, 0)); $this->inventory = array_fill(0, 36, array(AIR, 0, 0));
$this->armor = array_fill(0, 4, array(AIR, 0, 0)); $this->armor = array_fill(0, 4, array(AIR, 0, 0));
$this->gamemode = $this->server->gamemode; $this->gamemode = $this->server->gamemode;
$this->level = $this->server->api->level; $this->level = $this->server->api->level->getDefault();
$this->equipment = BlockAPI::getItem(AIR); $this->equipment = BlockAPI::getItem(AIR);
$this->evid[] = $this->server->event("server.tick", array($this, "onTick")); $this->evid[] = $this->server->event("server.tick", array($this, "onTick"));
$this->evid[] = $this->server->event("server.close", array($this, "close")); $this->evid[] = $this->server->event("server.close", array($this, "close"));
console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2); console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2);
} }
public function setSpawn(Vector3 $pos){ public function setSpawn(Position $pos){
$this->spawnPosition = $pos; $this->spawnPosition = $pos;
$this->dataPacket(MC_SET_SPAWN_POSITION, array( $this->dataPacket(MC_SET_SPAWN_POSITION, array(
"x" => (int) $this->spawnPosition->x, "x" => (int) $this->spawnPosition->x,
@ -141,7 +141,7 @@ class Player{
$z = $Z << 4; $z = $Z << 4;
$y = $Y << 4; $y = $Y << 4;
$MTU = $this->MTU - 16; $MTU = $this->MTU - 16;
$chunk = $this->level->getMiniChunk($X, $Z, $Y, $MTU); $chunk = $this->level->getOrderedMiniChunk($X, $Z, $Y, $MTU);
foreach($chunk as $d){ foreach($chunk as $d){
$this->dataPacket(MC_CHUNK_DATA, array( $this->dataPacket(MC_CHUNK_DATA, array(
"x" => $X, "x" => $X,
@ -197,11 +197,13 @@ class Player{
public function save(){ public function save(){
if($this->entity instanceof Entity){ if($this->entity instanceof Entity){
$this->data->set("position", array( $this->data->set("position", array(
"level" => $this->entity->level->getName(),
"x" => $this->entity->x, "x" => $this->entity->x,
"y" => $this->entity->y, "y" => $this->entity->y,
"z" => $this->entity->z, "z" => $this->entity->z,
)); ));
$this->data->set("spawn", array( $this->data->set("spawn", array(
"level" => $this->entity->level->getName(),
"x" => $this->spawnPosition->x, "x" => $this->spawnPosition->x,
"y" => $this->spawnPosition->y, "y" => $this->spawnPosition->y,
"z" => $this->spawnPosition->z, "z" => $this->spawnPosition->z,

View File

@ -27,7 +27,7 @@ the Free Software Foundation, either version 3 of the License, or
class PocketMinecraftServer{ class PocketMinecraftServer{
public $tCnt; public $tCnt;
public $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $spawn, $entities, $mapDir, $mapName, $map, $levelData, $tileEntities; public $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond;
private $port, $serverip, $database, $interface, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick; private $port, $serverip, $database, $interface, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick;
private function load(){ private function load(){
@ -45,12 +45,9 @@ class PocketMinecraftServer{
$this->startDatabase(); $this->startDatabase();
$this->api = false; $this->api = false;
$this->tCnt = 1; $this->tCnt = 1;
$this->mapDir = false;
$this->mapName = false;
$this->events = array(); $this->events = array();
$this->eventsID = array(); $this->eventsID = array();
$this->handlers = array(); $this->handlers = array();
$this->map = false;
$this->invisible = false; $this->invisible = false;
$this->levelData = false; $this->levelData = false;
$this->difficulty = 1; $this->difficulty = 1;
@ -113,15 +110,15 @@ class PocketMinecraftServer{
public function startDatabase(){ public function startDatabase(){
$this->preparedSQL = new stdClass(); $this->preparedSQL = new stdClass();
$this->database = new SQLite3(":memory:"); $this->database = new SQLite3(":memory:");
//$this->query("PRAGMA journal_mode = OFF;"); $this->query("PRAGMA journal_mode = OFF;");
//$this->query("PRAGMA encoding = \"UTF-8\";"); $this->query("PRAGMA encoding = \"UTF-8\";");
//$this->query("PRAGMA secure_delete = OFF;"); $this->query("PRAGMA secure_delete = OFF;");
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE COLLATE NOCASE);"); $this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE COLLATE NOCASE);");
$this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);"); $this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, level TEXT, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);");
$this->query("CREATE TABLE tileentities (ID INTEGER PRIMARY KEY, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);"); $this->query("CREATE TABLE tileentities (ID INTEGER PRIMARY KEY, level TEXT, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);");
$this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);"); $this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);");
$this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);"); $this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);");
$this->query("CREATE TABLE blockUpdates (x INTEGER, y INTEGER, z INTEGER, delay NUMERIC);"); $this->query("CREATE TABLE blockUpdates (level TEXT, x INTEGER, y INTEGER, z INTEGER, delay NUMERIC);");
//$this->query("PRAGMA synchronous = OFF;"); //$this->query("PRAGMA synchronous = OFF;");
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;"); $this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
$this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);"); $this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);");
@ -255,34 +252,6 @@ class PocketMinecraftServer{
} }
} }
public function loadMap(){
if($this->mapName !== false and trim($this->mapName) !== ""){
$this->levelData = unserialize(file_get_contents($this->mapDir."level.dat"));
if($this->levelData === false){
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
$this->close("invalid world data");
}
$this->time = (int) $this->levelData["Time"];
$this->seed = (int) $this->levelData["RandomSeed"];
if(isset($this->levelData["SpawnX"])){
$this->spawn = array("x" => $this->levelData["SpawnX"], "y" => $this->levelData["SpawnY"], "z" => $this->levelData["SpawnZ"]);
}else{
$this->levelData["SpawnX"] = $this->spawn["x"];
$this->levelData["SpawnY"] = $this->spawn["y"];
$this->levelData["SpawnZ"] = $this->spawn["z"];
}
$this->levelData["Time"] = $this->time;
console("[INFO] Preparing level \"".$this->levelData["LevelName"]."\"");
$this->map = new ChunkParser();
if(!$this->map->loadFile($this->mapDir."chunks.dat")){
console("[ERROR] Couldn't load the map \"\x1b[32m".$this->levelData["LevelName"]."\x1b[0m\"!", true, true, 0);
$this->map = false;
}else{
$this->map->loadMap();
}
}
}
public function getGamemode(){ public function getGamemode(){
switch($this->gamemode){ switch($this->gamemode){
case SURVIVAL: case SURVIVAL:
@ -296,131 +265,9 @@ class PocketMinecraftServer{
} }
} }
public function loadEntities(){
if($this->map !== false){
$entities = unserialize(file_get_contents($this->mapDir."entities.dat"));
if($entities === false or !is_array($entities)){
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
$this->close("invalid world data");
}
foreach($entities as $entity){
if(!isset($entity["id"])){
break;
}
if(isset($this->api) and $this->api !== false){
if($entity["id"] === 64){ //Item Drop
$e = $this->api->entity->add(ENTITY_ITEM, $entity["Item"]["id"], array(
"meta" => $entity["Item"]["Damage"],
"stack" => $entity["Item"]["Count"],
"x" => $entity["Pos"][0],
"y" => $entity["Pos"][1],
"z" => $entity["Pos"][2],
"yaw" => $entity["Rotation"][0],
"pitch" => $entity["Rotation"][1],
));
}elseif($entity["id"] === OBJECT_PAINTING){ //Painting
$e = $this->api->entity->add(ENTITY_OBJECT, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}else{
$e = $this->api->entity->add(ENTITY_MOB, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}
}
}
$tiles = unserialize(file_get_contents($this->mapDir."tileEntities.dat"));
foreach($tiles as $tile){
if(!isset($tile["id"])){
break;
}
$t = $this->api->tileentity->add($tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
}
$this->action(1000000 * 60 * 25, '$this->api->chat->broadcast("Forcing save...");$this->save();');
}
}
public function save($final = false){
if($this->mapName !== false){
$this->levelData["Time"] = $this->time;
file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
$this->map->saveMap($final);
$this->trigger("server.save", $final);
if(count($this->entities) > 0){
$entities = array();
foreach($this->entities as $entity){
if($entity->class === ENTITY_MOB){
$entities[] = array(
"id" => $entity->type,
"Color" => @$entity->data["Color"],
"Sheared" => @$entity->data["Sheared"],
"Health" => $entity->health,
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => $entity->yaw,
1 => $entity->pitch,
),
);
}elseif($entity->class === ENTITY_OBJECT){
$entities[] = array(
"id" => $entity->type,
"TileX" => $entity->x,
"TileX" => $entity->y,
"TileX" => $entity->z,
"Health" => $entity->health,
"Motive" => $entity->data["Motive"],
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => $entity->yaw,
1 => $entity->pitch,
),
);
}elseif($entity->class === ENTITY_ITEM){
$entities[] = array(
"id" => 64,
"Item" => array(
"id" => $entity->type,
"Damage" => $entity->meta,
"Count" => $entity->stack,
),
"Health" => $entity->health,
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => 0,
1 => 0,
),
);
}
}
file_put_contents($this->mapDir."entities.dat", serialize($entities));
}
if(count($this->tileEntities) > 0){
$tiles = array();
foreach($this->tileEntities as $tile){
$tiles[] = $tile->data;
}
file_put_contents($this->mapDir."tileEntities.dat", serialize($tiles));
}
}
}
public function init(){ public function init(){
if($this->mapName !== false and $this->map === false){
$this->loadMap();
$this->loadEntities();
}
$this->loadEvents(); $this->loadEvents();
declare(ticks=40); declare(ticks=40);
register_tick_function(array($this, "tick")); register_tick_function(array($this, "tick"));

View File

@ -92,5 +92,9 @@ if($errors > 0){
} }
/***REM_START***/ /***REM_START***/
require_once(FILE_PATH."/src/math/Vector3.php");
require_once(FILE_PATH."/src/world/Position.php");
require_once(FILE_PATH."/src/pmf/PMF.php");
require_all(FILE_PATH . "src/"); require_all(FILE_PATH . "src/");
/***REM_END***/ /***REM_END***/

View File

@ -25,11 +25,7 @@ the Free Software Foundation, either version 3 of the License, or
*/ */
/***REM_START***/ abstract class Block extends Position{
require_once(FILE_PATH."/src/math/Vector3.php");
/***REM_END***/
abstract class Block extends Vector3{
public static $class = array( public static $class = array(
AIR => "AirBlock", AIR => "AirBlock",
STONE => "StoneBlock", STONE => "StoneBlock",
@ -147,12 +143,12 @@ abstract class Block extends Vector3{
public $isTransparent = false; public $isTransparent = false;
public $isReplaceable = false; public $isReplaceable = false;
public $isPlaceable = true; public $isPlaceable = true;
public $inWorld = false; public $level = false;
public $hasPhysics = false; public $hasPhysics = false;
public $isLiquid = false; public $isLiquid = false;
public $x; public $x = 0;
public $y; public $y = 0;
public $z; public $z = 0;
public function __construct($id, $meta = 0, $name = "Unknown"){ public function __construct($id, $meta = 0, $name = "Unknown"){
$this->id = (int) $id; $this->id = (int) $id;
@ -173,8 +169,8 @@ abstract class Block extends Vector3{
return $this->meta & 0x0F; return $this->meta & 0x0F;
} }
final public function position(Vector3 $v){ final public function position(Position $v){
$this->inWorld = true; $this->level = $v->level;
$this->x = (int) $v->x; $this->x = (int) $v->x;
$this->y = (int) $v->y; $this->y = (int) $v->y;
$this->z = (int) $v->z; $this->z = (int) $v->z;
@ -197,19 +193,27 @@ abstract class Block extends Vector3{
return $this->breakTime; return $this->breakTime;
} }
public function getSide($side){
$v = parent::getSide($side);
if($this->level instanceof Level){
return $this->level->getBlock($v);
}
return $v;
}
final public function __toString(){ final public function __toString(){
return "Block ". $this->name ." (".$this->id.":".$this->meta.")"; return "Block ". $this->name ." (".$this->id.":".$this->meta.")";
} }
abstract function isBreakable(Item $item, Player $player); abstract function isBreakable(Item $item, Player $player);
abstract function onBreak(BlockAPI $level, Item $item, Player $player); abstract function onBreak(Item $item, Player $player);
abstract function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz); abstract function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz);
abstract function onActivate(BlockAPI $level, Item $item, Player $player); abstract function onActivate(Item $item, Player $player);
abstract function onUpdate(BlockAPI $level, $type); abstract function onUpdate($type);
} }
/***REM_START***/ /***REM_START***/

View File

@ -30,31 +30,23 @@ class GenericBlock extends Block{
public function __construct($id, $meta = 0, $name = "Unknown"){ public function __construct($id, $meta = 0, $name = "Unknown"){
parent::__construct($id, $meta, $name); parent::__construct($id, $meta, $name);
} }
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){ public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
if($block->inWorld === true){ return $this->level->setBlock($block, $this);
$level->setBlock($block, $this->id, $this->getMetadata());
return true;
}
return false;
} }
public function isBreakable(Item $item, Player $player){ public function isBreakable(Item $item, Player $player){
return ($this->breakable); return ($this->breakable);
} }
public function onBreak(BlockAPI $level, Item $item, Player $player){ public function onBreak(Item $item, Player $player){
if($this->inWorld === true){ return $this->level->setBlock($this, BlockAPI::getBlock(AIR, 0));
$level->setBlock($this, AIR, 0); }
return true;
} public function onUpdate($type){
return false; return false;
} }
public function onUpdate(BlockAPI $level, $type){ public function onActivate(Item $item, Player $player){
return false;
}
public function onActivate(BlockAPI $level, Item $item, Player $player){
return ($this->isActivable); return ($this->isActivable);
} }
} }

View File

@ -25,10 +25,6 @@ the Free Software Foundation, either version 3 of the License, or
*/ */
/***REM_START***/
require_once(FILE_PATH."/src/pmf/PMF.php");
/***REM_END***/
define("PMF_CURRENT_LEVEL_VERSION", 0x00); define("PMF_CURRENT_LEVEL_VERSION", 0x00);
class PMFLevel extends PMF{ class PMFLevel extends PMF{
@ -40,6 +36,21 @@ class PMFLevel extends PMF{
private $chunks = array(); private $chunks = array();
private $chunkChange = array(); private $chunkChange = array();
public function getData($index){
if(!isset($this->levelData[$index])){
return false;
}
return ($this->levelData[$index]);
}
public function setData($index, $data){
if(!isset($this->levelData[$index])){
return false;
}
$this->levelData[$index] = $data;
return true;
}
public function __construct($file, $blank = false){ public function __construct($file, $blank = false){
if(is_array($blank)){ if(is_array($blank)){
$this->create($file, 0); $this->create($file, 0);
@ -62,8 +73,9 @@ class PMFLevel extends PMF{
} }
} }
private function createBlank(){ public function saveData($locationTable = true){
$this->levelData["version"] = PMF_CURRENT_LEVEL_VERSION; $this->levelData["version"] = PMF_CURRENT_LEVEL_VERSION;
@ftruncate($this->fp, 5);
$this->seek(5); $this->seek(5);
$this->write(chr($this->levelData["version"])); $this->write(chr($this->levelData["version"]));
$this->write(Utils::writeShort(strlen($this->levelData["name"])).$this->levelData["name"]); $this->write(Utils::writeShort(strlen($this->levelData["name"])).$this->levelData["name"]);
@ -74,11 +86,20 @@ class PMFLevel extends PMF{
$this->write(Utils::writeFloat($this->levelData["spawnZ"])); $this->write(Utils::writeFloat($this->levelData["spawnZ"]));
$this->write(chr($this->levelData["width"])); $this->write(chr($this->levelData["width"]));
$this->write(chr($this->levelData["height"])); $this->write(chr($this->levelData["height"]));
$this->write(gzdeflate("", 9)); $extra = gzdeflate($this->levelData["extra"], 9);
$this->write(Utils::writeShort(strlen($extra)).$extra);
$this->payloadOffset = ftell($this->fp);
if($locationTable !== false){
$this->writeLocationTable();
}
}
private function createBlank(){
$this->saveData(false);
$this->locationTable = array(); $this->locationTable = array();
$cnt = pow($this->levelData["width"], 2); $cnt = pow($this->levelData["width"], 2);
@mkdir(dirname($this->file)."/chunks/", 0755); @mkdir(dirname($this->file)."/chunks/", 0755);
$this->payloadOffset = ftell($this->fp);
for($index = 0; $index < $cnt; ++$index){ for($index = 0; $index < $cnt; ++$index){
$this->chunks[$index] = false; $this->chunks[$index] = false;
$this->chunkChange[$index] = false; $this->chunkChange[$index] = false;
@ -154,6 +175,15 @@ class PMFLevel extends PMF{
return true; return true;
} }
private function writeLocationTable(){
$cnt = pow($this->levelData["width"], 2);
@ftruncate($this->fp, $this->payloadOffset);
$this->seek($this->payloadOffset);
for($index = 0; $index < $cnt; ++$index){
$this->write(Utils::writeShort($this->locationTable[$index]));
}
}
private function getChunkPath($X, $Z){ private function getChunkPath($X, $Z){
return dirname($this->file)."/chunks/".$Z.".".$X.".pmc"; return dirname($this->file)."/chunks/".$Z.".".$X.".pmc";
} }
@ -186,6 +216,18 @@ class PMFLevel extends PMF{
return true; return true;
} }
public function unloadChunk($X, $Z, $save = true){
$X = (int) $X;
$Z = (int) $Z;
if($this->isChunkLoaded($X, $Z)){
return false;
}elseif($save !== false){
$this->saveChunk($X, $Z);
}
unset($this->chunks[$index], $this->chunkChange[$index]);
return true;
}
public function isChunkLoaded($X, $Z){ public function isChunkLoaded($X, $Z){
$index = $this->getIndex($X, $Z); $index = $this->getIndex($X, $Z);
if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){ if(!isset($this->chunks[$index]) or $this->chunks[$index] === false){
@ -205,9 +247,9 @@ class PMFLevel extends PMF{
} }
public function getBlock($x, $y, $z){ public function getBlock($x, $y, $z){
$X = $x << 4; $X = $x >> 4;
$Z = $z << 4; $Z = $z >> 4;
$Y = $y << 4; $Y = $y >> 4;
if($X >= 32 or $Z >= 32){ if($X >= 32 or $Z >= 32){
return array(AIR, 0); return array(AIR, 0);
} }
@ -222,8 +264,8 @@ class PMFLevel extends PMF{
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
$bindex = $aY + $aZ << 5 + $aX << 9; $bindex = $aY + ($aX << 5) + ($aZ << 9);
$mindex = $aY >> 1 + 16 + $aZ << 5 + $aX << 9; $mindex = ($aY >> 1) + 16 + ($aX << 5) + ($aZ << 9);
$b = ord($this->chunks[$index][$Y]{$bindex}); $b = ord($this->chunks[$index][$Y]{$bindex});
$m = ord($this->chunks[$index][$Y]{$mindex}); $m = ord($this->chunks[$index][$Y]{$mindex});
if(($y & 1) === 0){ if(($y & 1) === 0){
@ -245,11 +287,11 @@ class PMFLevel extends PMF{
} }
public function getMiniChunk($X, $Z, $Y){ public function getMiniChunk($X, $Z, $Y){
if($this->isChunkLoaded($X, $Z) === false){ if($this->loadChunk($X, $Z) === false){
return str_repeat("\x00", 8192); return str_repeat("\x00", 8192);
} }
$index = $this->getIndex($X, $Z); $index = $this->getIndex($X, $Z);
if(!isset($this->chunks[$index][$Y])){ if($this->chunks[$index][$Y] === false){
return str_repeat("\x00", 8192); return str_repeat("\x00", 8192);
} }
return $this->chunks[$index][$Y]; return $this->chunks[$index][$Y];
@ -259,16 +301,20 @@ class PMFLevel extends PMF{
if($this->isChunkLoaded($X, $Z) === false){ if($this->isChunkLoaded($X, $Z) === false){
$this->loadChunk($X, $Z); $this->loadChunk($X, $Z);
} }
if(strlen($data) !== 8192){
return false;
}
$index = $this->getIndex($X, $Z); $index = $this->getIndex($X, $Z);
$this->chunks[$index][$Y] = substr($data, 0, 8192); $this->chunks[$index][$Y] = $data;
$this->chunkChange[$index][$Y] = 8192;
$this->locationTable[$index][0] |= 1 << $Y; $this->locationTable[$index][0] |= 1 << $Y;
return true; return true;
} }
public function setBlock($x, $y, $z, $block, $meta = 0){ public function setBlock($x, $y, $z, $block, $meta = 0){
$X = $x << 4; $X = $x >> 4;
$Z = $z << 4; $Z = $z >> 4;
$Y = $y << 4; $Y = $y >> 4;
$block &= 0xFF; $block &= 0xFF;
$meta &= 0x0F; $meta &= 0x0F;
if($X >= 32 or $Z >= 32){ if($X >= 32 or $Z >= 32){
@ -285,8 +331,8 @@ class PMFLevel extends PMF{
$aX = $x - ($X << 4); $aX = $x - ($X << 4);
$aZ = $z - ($Z << 4); $aZ = $z - ($Z << 4);
$aY = $y - ($Y << 4); $aY = $y - ($Y << 4);
$bindex = $aY + $aZ << 5 + $aX << 9; $bindex = $aY + ($aX << 5) + ($aZ << 9);
$mindex = $aY >> 1 + 16 + $aZ << 5 + $aX << 9; $mindex = ($aY >> 1) + 16 + ($aX << 5) + ($aZ << 9);
$old_b = $this->chunks[$index][$Y]{$bindex}; $old_b = $this->chunks[$index][$Y]{$bindex};
$old_m = ord($this->map[$X][$Z][1][$index]{$y >> 1}); $old_m = ord($this->map[$X][$Z][1][$index]{$y >> 1});
if(($y & 1) === 0){ if(($y & 1) === 0){
@ -319,16 +365,24 @@ class PMFLevel extends PMF{
$chunk = @gzopen($this->getChunkPath($X, $Z), "wb9"); $chunk = @gzopen($this->getChunkPath($X, $Z), "wb9");
$bitmap = 0; $bitmap = 0;
for($Y = 0; $Y < $this->levelData["height"]; ++$Y){ for($Y = 0; $Y < $this->levelData["height"]; ++$Y){
if($this->chunks[$index][$Y] !== false and !$this->isMiniChunkEmpty($X, $Z, $Y)){ if($this->chunks[$index][$Y] !== false and ((isset($this->chunkChange[$index][$Y]) and $this->chunkChange[$index][$Y] === 0) or !$this->isMiniChunkEmpty($X, $Z, $Y))){
gzwrite($chunk, $this->chunks[$index][$Y]); gzwrite($chunk, $this->chunks[$index][$Y]);
$bitmap |= 1 << $Y; $bitmap |= 1 << $Y;
}else{ }else{
$this->chunks[$index][$Y] = false; $this->chunks[$index][$Y] = false;
} }
$this->chunkChange[$index][$Y] = 0;
} }
$this->locationTable[$index][0] = $bitmap; $this->locationTable[$index][0] = $bitmap;
$this->seek($this->payloadOffset + ($index << 1)); $this->seek($this->payloadOffset + ($index << 1));
$this->write(Utils::writeShort($this->locationTable[$index][0])); $this->write(Utils::writeShort($this->locationTable[$index][0]));
} }
public function doSaveRound(){
foreach($this->chunks as $index => $chunk){
$this->getXZ($index, $X, $Z);
$this->saveChunk($X, $Z);
}
}
} }

View File

@ -45,7 +45,7 @@ define("ENTITY_OBJECT", 2);
define("ENTITY_ITEM", 3); define("ENTITY_ITEM", 3);
class Entity extends stdClass{ class Entity extends Position{
public $age; public $age;
public $air; public $air;
public $spawntime; public $spawntime;
@ -74,7 +74,9 @@ class Entity extends stdClass{
private $tickCounter; private $tickCounter;
private $speedMeasure = array(0, 0, 0, 0, 0); private $speedMeasure = array(0, 0, 0, 0, 0);
private $server; private $server;
function __construct($eid, $class, $type = 0, $data = array()){ public $level;
function __construct(Level $level, $eid, $class, $type = 0, $data = array()){
$this->level = $level;
$this->fallY = false; $this->fallY = false;
$this->fallStart = false; $this->fallStart = false;
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
@ -97,7 +99,7 @@ class Entity extends stdClass{
$this->closed = false; $this->closed = false;
$this->name = ""; $this->name = "";
$this->tickCounter = 0; $this->tickCounter = 0;
$this->server->query("INSERT OR REPLACE INTO entities (EID, type, class, health) VALUES (".$this->eid.", ".$this->type.", ".$this->class.", ".$this->health.");"); $this->server->query("INSERT OR REPLACE INTO entities (EID, level, type, class, health) VALUES (".$this->eid.", '".$this->level->getName()."', ".$this->type.", ".$this->class.", ".$this->health.");");
$this->x = isset($this->data["x"]) ? $this->data["x"]:0; $this->x = isset($this->data["x"]) ? $this->data["x"]:0;
$this->y = isset($this->data["y"]) ? $this->data["y"]:0; $this->y = isset($this->data["y"]) ? $this->data["y"]:0;
$this->z = isset($this->data["z"]) ? $this->data["z"]:0; $this->z = isset($this->data["z"]) ? $this->data["z"]:0;
@ -107,7 +109,7 @@ class Entity extends stdClass{
$this->speed = 0; $this->speed = 0;
$this->yaw = isset($this->data["yaw"]) ? $this->data["yaw"]:0; $this->yaw = isset($this->data["yaw"]) ? $this->data["yaw"]:0;
$this->pitch = isset($this->data["pitch"]) ? $this->data["pitch"]:0; $this->pitch = isset($this->data["pitch"]) ? $this->data["pitch"]:0;
$this->position = array("x" => &$this->x, "y" => &$this->y, "z" => &$this->z, "yaw" => &$this->yaw, "pitch" => &$this->pitch); $this->position = array("level" => $this->level, "x" => &$this->x, "y" => &$this->y, "z" => &$this->z, "yaw" => &$this->yaw, "pitch" => &$this->pitch);
switch($this->class){ switch($this->class){
case ENTITY_PLAYER: case ENTITY_PLAYER:
$this->player = $this->data["player"]; $this->player = $this->data["player"];
@ -175,7 +177,7 @@ class Entity extends stdClass{
private function spawnDrops(){ private function spawnDrops(){
foreach($this->getDrops() as $drop){ foreach($this->getDrops() as $drop){
$this->server->api->block->drop(new Vector3($this->x, $this->y, $this->z), BlockAPI::getItem($drop[0] & 0xFFFF, $drop[1] & 0xFFFF, $drop[2] & 0xFF), true); $this->server->api->block->drop($this, BlockAPI::getItem($drop[0] & 0xFFFF, $drop[1] & 0xFFFF, $drop[2] & 0xFF), true);
} }
} }
@ -186,8 +188,8 @@ class Entity extends stdClass{
$this->close(); //Despawn timer $this->close(); //Despawn timer
return false; return false;
} }
if(($time - $this->spawntime) >= 2){ if(($time - $this->spawntime) >= 0.6){ //TODO: set this on Player class, updates things when it moves
$player = $this->server->query("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND abs(x - {$this->x}) <= 1.5 AND abs(y - {$this->y}) <= 1.5 AND abs(z - {$this->z}) <= 1.5 LIMIT 1;", true); $player = $this->server->query("SELECT EID FROM entities WHERE level = '".$this->level->getName()."' AND class = ".ENTITY_PLAYER." AND abs(x - {$this->x}) <= 1.5 AND abs(y - {$this->y}) <= 1.5 AND abs(z - {$this->z}) <= 1.5 LIMIT 1;", true);
$player = $this->server->api->entity->get($player["EID"]); $player = $this->server->api->entity->get($player["EID"]);
if($player instanceof Entity){ if($player instanceof Entity){
$player = $player->player; $player = $player->player;
@ -439,7 +441,7 @@ class Entity extends stdClass{
if(!($player instanceof Player)){ if(!($player instanceof Player)){
$player = $this->server->api->player->get($player); $player = $this->server->api->player->get($player);
} }
if($player->eid === $this->eid or $this->closed !== false){ if($player->eid === $this->eid or $this->closed !== false or $player->level !== $this->level){
return false; return false;
} }
switch($this->class){ switch($this->class){
@ -530,17 +532,23 @@ class Entity extends stdClass{
$this->server->query("UPDATE entities SET pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";"); $this->server->query("UPDATE entities SET pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
} }
public function setCoords($x, $y, $z){ public function setCoords(Vector3 $pos){
$this->x = $x; if($pos instanceof Position){
$this->y = $y; $this->level = $pos->level;
$this->z = $z; $this->server->query("UPDATE entities SET level = '".$this->level->getName()."' WHERE EID = ".$this->eid.";");
}
$this->x = $pos->x;
$this->y = $pos->y;
$this->z = $pos->z;
$this->yaw = $yaw;
$this->pitch = $pitch;
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE EID = ".$this->eid.";"); $this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE EID = ".$this->eid.";");
} }
public function move($x, $y, $z, $yaw = 0, $pitch = 0){ public function move(Vector3 $pos, $yaw = 0, $pitch = 0){
$this->x += $x; $this->x += $pos->x;
$this->y += $y; $this->y += $pos->y;
$this->z += $z; $this->z += $pos->z;
$this->yaw += $yaw; $this->yaw += $yaw;
$this->yaw %= 360; $this->yaw %= 360;
$this->pitch += $pitch; $this->pitch += $pitch;
@ -548,17 +556,20 @@ class Entity extends stdClass{
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";"); $this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
} }
public function setPosition($x, $y, $z, $yaw, $pitch){ public function setPosition(Vector3 $pos, $yaw, $pitch){
$this->x = $x; if($pos instanceof Position){
$this->y = $y; $this->level = $pos->level;
$this->z = $z; $this->server->query("UPDATE entities SET level = '".$this->level->getName()."' WHERE EID = ".$this->eid.";");
}
$this->x = $pos->x;
$this->y = $pos->y;
$this->z = $pos->z;
$this->yaw = $yaw; $this->yaw = $yaw;
$this->pitch = $pitch; $this->pitch = $pitch;
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";"); $this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
} }
public function inBlock($x, $y, $z, $radius = 0.8){ public function inBlock(Vector3 $block, $radius = 0.8){
$block = new Vector3($x, $y, $z);
$me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5); $me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5);
if(($y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){ if(($y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){
return true; return true;
@ -566,8 +577,7 @@ class Entity extends stdClass{
return false; return false;
} }
public function touchingBlock($x, $y, $z, $radius = 0.9){ public function touchingBlock(Vector3 $block, $radius = 0.9){
$block = new Vector3($x, $y, $z);
$me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5); $me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5);
if(($y == (((int) $this->y) - 1) or $y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){ if(($y == (((int) $this->y) - 1) or $y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){
return true; return true;

151
src/world/Level.php Normal file
View File

@ -0,0 +1,151 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
class Level{
public $entities, $tileEntities;
private $level, $time, $startCheck, $startTime, $server;
public function __construct(PMFLevel $level, Config $entities, Config $tileEntities){
$this->server = ServerAPI::request();
$this->level = $level;
$this->entities = $entities;
$this->tileEntities = $tileEntities;
$this->startTime = $this->time = (int) $this->level->getData("time");
$this->startCheck = microtime(true);
$this->server->schedule(15, array($this, "checkThings"));
}
public function __destruct(){
$this->save();
unset($this->level);
}
public function save(){
$this->level->setData("time", $this->time);
$this->level->doSaveRound();
$this->level->saveData();
}
public function getBlock(Vector3 $pos){
if(($pos instanceof Position) and $pos->level !== $this){
return false;
}
$b = $this->level->getBlock($pos->x, $pos->y, $pos->z);
return BlockAPI::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this));
}
public function setBlock(Position $pos, Block $block, $update = true, $tiles = false){
if((($pos instanceof Position) and $pos->level !== $this) or $pos->x < 0 or $pos->y < 0 or $pos->z < 0){
return false;
}elseif($this->server->api->dhandle("block.change", array(
"position" => $pos,
"block" => $block,
)) !== false){
$ret = $this->level->setBlock($pos->x, $pos->y, $pos->z, $block->getID(), $block->getMetadata());
if($update === true){
$this->server->api->block->blockUpdate($pos, BLOCK_UPDATE_NORMAL); //????? water?
$this->server->api->block->blockUpdateAround($pos, BLOCK_UPDATE_NORMAL);
}
if($tiles === true){
if(($t = $this->server->api->tileentity->get($pos)) !== false){
$t[0]->close();
}
}
return $ret;
}
return false;
}
public function getMiniChunk($X, $Z){
return $this->level->getMiniChunk($X, $Z);
}
public function setMiniChunk($X, $Z, $data){
return $this->level->setMiniChunk($X, $Z, $data);
}
public function loadChunk($X, $Z){
return $this->level->loadChunk($X, $Z);
}
public function unloadChunk($X, $Z){
return $this->level->unloadChunk($X, $Z);
}
public function getOrderedMiniChunk($X, $Z, $Y, $MTU){
$raw = $this->map->getMiniChunk($X, $Z, $Y);
$ordered = array();
$i = 0;
$ordered[$i] = "";
$cnt = 0;
$flag = chr(1 << $Y);
for($j = 0; $j < 256; ++$j){
if((strlen($ordered[$i]) + 16 + 8 + 1) > $MTU){
++$i;
$ordered[$i] = str_repeat("\x00", $cnt);
}
$index = $j << 5;
$ordered[$i] .= $flag;
$ordered[$i] .= substr($raw, $index, 16);
$ordered[$i] .= substr($raw, $index + 16, 8);
++$cnt;
}
return $ordered;
}
public function getSpawn(){
return new Position($this->level->getData("spawnX"), $this->level->getData("spawnY"), $this->level->getData("spawnZ"), $this);
}
public function setSpawn(Vector3 $pos){
$this->level->setData("spawnX", $pos->x);
$this->level->setData("spawnY", $pos->y);
$this->level->setData("spawnZ", $pos->z);
}
public function getTime(){
return ($this->time);
}
public function getName(){
return $this->level->getData("name");
}
public function setTime($time){
$this->startTime = $this->time = (int) $time;
$this->startCheck = microtime(true);
}
public function checkThings(){
$now = microtime(true);
$this->time = $this->startTime + ($now - $this->startCheck) * 20;
}
public function getSeed(){
return (int) $this->level->getData("seed");
}
}

View File

@ -33,6 +33,8 @@ class LevelImport{
public function import(){ public function import(){
if(file_exists($this->path."tileEntities.dat")){ //OldPM if(file_exists($this->path."tileEntities.dat")){ //OldPM
$level = unserialize(file_get_contents($this->path."level.dat"));
console("[INFO] Importing OldPM level \"".$level["LevelName"]."\" to PMF format");
$entities = new Config($this->path."entities.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."entities.dat"))); $entities = new Config($this->path."entities.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."entities.dat")));
$entities->save(); $entities->save();
$tileEntities = new Config($this->path."tileEntities.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."tileEntities.dat"))); $tileEntities = new Config($this->path."tileEntities.yml", CONFIG_YAML, unserialize(file_get_contents($this->path."tileEntities.dat")));
@ -43,9 +45,8 @@ class LevelImport{
if($level["LevelName"] == ""){ if($level["LevelName"] == ""){
$level["LevelName"] = "world".time(); $level["LevelName"] = "world".time();
} }
console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2); console("[INFO] Importing Pocket level \"".$level["LevelName"]."\" to PMF format");
unset($level["Player"]); unset($level["Player"]);
$lvName = $level["LevelName"]."/";
$entities = parseNBTData($nbt->loadFile($this->path."entities.dat")); $entities = parseNBTData($nbt->loadFile($this->path."entities.dat"));
if(!isset($entities["TileEntities"])){ if(!isset($entities["TileEntities"])){
$entities["TileEntities"] = array(); $entities["TileEntities"] = array();
@ -56,6 +57,8 @@ class LevelImport{
$entities->save(); $entities->save();
$tileEntities = new Config($this->path."tileEntities.yml", CONFIG_YAML, $tileEntities); $tileEntities = new Config($this->path."tileEntities.yml", CONFIG_YAML, $tileEntities);
$tileEntities->save(); $tileEntities->save();
}else{
return false;
} }
$pmf = new PMFLevel($this->path."level.pmf", array( $pmf = new PMFLevel($this->path."level.pmf", array(
@ -65,6 +68,7 @@ class LevelImport{
"spawnX" => $level["SpawnX"], "spawnX" => $level["SpawnX"],
"spawnY" => $level["SpawnY"], "spawnY" => $level["SpawnY"],
"spawnZ" => $level["SpawnZ"], "spawnZ" => $level["SpawnZ"],
"extra" => "",
"width" => 16, "width" => 16,
"height" => 8 "height" => 8
)); ));
@ -99,16 +103,17 @@ class LevelImport{
} }
$pmf->saveChunk($X, $Z); $pmf->saveChunk($X, $Z);
} }
console("[NOTICE] Importing level ".ceil(($Z + 1)/0.16)."%");
} }
$chunks->map = null; $chunks->map = null;
$chunks = null; $chunks = null;
/*@unlink($this->path."level.dat"); @unlink($this->path."level.dat");
@unlink($this->path."level.dat_old"); @unlink($this->path."level.dat_old");
@unlink($this->path."player.dat"); @unlink($this->path."player.dat");
@unlink($this->path."entities.dat"); @unlink($this->path."entities.dat");
@unlink($this->path."chunks.dat"); @unlink($this->path."chunks.dat");
@unlink($this->path."chunks.dat.gz"); @unlink($this->path."chunks.dat.gz");
@unlink($this->path."tileEntities.dat");*/ @unlink($this->path."tileEntities.dat");
unset($chunks, $level, $entities, $tileEntities, $nbt); unset($chunks, $level, $entities, $tileEntities, $nbt);
return true; return true;
} }

View File

@ -24,8 +24,17 @@ the Free Software Foundation, either version 3 of the License, or
*/ */
/*
class BlockIterator implements Iterator{
class Position{
public $level;
}*/ public function __construct($x = 0, $y = 0, $z = 0, Level $level){
parent::__construct($x, $y, $z);
$this->level = $level;
}
public function __toString(){
return "Position(level=".$this->level->getName().",x=".$this->x.",y=".$this->y.",z=".$this->z.")";
}
}

View File

@ -32,7 +32,7 @@ define("TILE_CHEST", "Chest");
define("TILE_FURNACE", "Furnace"); define("TILE_FURNACE", "Furnace");
define("FURNACE_SLOTS", 3); define("FURNACE_SLOTS", 3);
class TileEntity extends stdClass{ class TileEntity extends Position{
public $name; public $name;
public $normal; public $normal;
public $id; public $id;
@ -45,8 +45,9 @@ class TileEntity extends stdClass{
public $metadata; public $metadata;
public $closed; public $closed;
private $server; private $server;
function __construct($id, $class, $x, $y, $z, $data = array()){ function __construct(Level $level, $id, $class, $x, $y, $z, $data = array()){
$this->server = ServerAPI::request(); $this->server = ServerAPI::request();
$this->level = $level;
$this->normal = true; $this->normal = true;
$this->class = $class; $this->class = $class;
$this->data = $data; $this->data = $data;
@ -59,7 +60,7 @@ class TileEntity extends stdClass{
$this->x = (int) $x; $this->x = (int) $x;
$this->y = (int) $y; $this->y = (int) $y;
$this->z = (int) $z; $this->z = (int) $z;
$this->server->query("INSERT OR REPLACE INTO tileentities (ID, class, x, y, z) VALUES (".$this->id.", '".$this->class."', ".$this->x.", ".$this->y.", ".$this->z.");"); $this->server->query("INSERT OR REPLACE INTO tileentities (ID, level, class, x, y, z) VALUES (".$this->id.", '".$this->level->getName()."', '".$this->class."', ".$this->x.", ".$this->y.", ".$this->z.");");
switch($this->class){ switch($this->class){
case TILE_SIGN: case TILE_SIGN:
$this->server->query("UPDATE tileentities SET spawnable = 1 WHERE ID = ".$this->id.";"); $this->server->query("UPDATE tileentities SET spawnable = 1 WHERE ID = ".$this->id.";");
@ -148,7 +149,7 @@ class TileEntity extends stdClass{
public function close(){ public function close(){
if($this->closed === false){ if($this->closed === false){
$this->closed = true; $this->closed = true;
$this->server->api->entity->remove($this->eid); $this->server->api->tileentity->remove($this->id);
} }
} }
@ -160,17 +161,16 @@ class TileEntity extends stdClass{
return $this->name; return $this->name;
} }
public function setName($name){
$this->name = $name;
$this->server->query("UPDATE entities SET name = '".str_replace("'", "", $this->name)."' WHERE EID = ".$this->eid.";");
}
public function setPosition(Vector3 $pos){
public function setPosition($x, $y, $z){ if($pos instanceof Position){
$this->x = (int) $x; $this->level = $pos->level;
$this->y = (int) $y; $this->server->query("UPDATE tileentities SET level = '".$this->level->getName()."' WHERE ID = ".$this->id.";");
$this->z = (int) $z; }
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE EID = ".$this->eid.";"); $this->x = (int) $pos->x;
$this->y = (int) $pos->y;
$this->z = (int) $pos->z;
$this->server->query("UPDATE tileentities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE ID = ".$this->id.";");
} }
} }

View File

@ -1,66 +0,0 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
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.
*/
class NormalGenerator{
private $config, $spawn, $structure;
public function __construct($seed){
$this->config = array(
"seed" => (int) $seed,
);
}
public function set($name, $value){
$this->config[$name] = $value;
}
public function init(){
$this->spawn = array(128, 128, 128);
}
public function getSpawn(){
return $this->spawn;
}
public function getColumn($x, $z){
$x = (int) $x;
$z = (int) $z;
$column = $this->structure;
if(floor(sqrt(pow($x - $this->spawn[0], 2) + pow($z - $this->spawn[2], 2))) <= $this->config["spawn-radius"]){
$column[0]{strlen($column[0])-1} = chr($this->config["spawn-surface"]);
}
if(($x % 8) === 0 and ($z % 8) === 0 and $this->config["torches"] == "1"){
$column[0] .= chr(50);
}
$column[0] .= str_repeat(chr(0), 128 - strlen($column[0]));
$column[1] .= str_repeat(chr(0), 64 - strlen($column[1]));
$column[2] .= str_repeat(chr(0), 64 - strlen($column[2]));
$column[3] .= str_repeat(chr(0), 64 - strlen($column[3]));
return $column;
}
}