Map importing, entity loading and more

This commit is contained in:
Shoghi Cervantes Pueyo
2012-12-07 14:46:40 +01:00
parent 92469a426f
commit 02b2e980eb
12 changed files with 396 additions and 19 deletions

View File

@ -0,0 +1,27 @@
<?php
/*
-
/ \
/ \
/ POCKET \
/ MINECRAFT PHP \
|\ @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.
*/

View File

@ -0,0 +1,155 @@
<?php
/*
-
/ \
/ \
/ POCKET \
/ MINECRAFT PHP \
|\ @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 MapInterface{
protected $map, $floor, $column, $biome, $material, $biomes;
function __construct($client){
$this->client = $client;
$this->map = $this->client->mapParser;
$this->floor = method_exists($this->map, "getFloor");
$this->column = method_exists($this->map, "getColumn");
//$this->biome = method_exists($this->map, "getBiome");
//include("misc/materials.php");
//$this->material = $material;
//include("misc/biomes.php");
//$this->biomes = $biomes;
}
public function getBiome($x, $z){
$x = (int) $x;
$z = (int) $z;
if($this->biome === true){
return $this->map->getBiome($x, $z);
}else{
return 0;
}
}
/*public function getBiomeName($x, $z){
$biome = $this->getBiome($x, $z);
return isset($this->biomes[$biome]) ? $this->biomes[$biome]:"Unknown";
}*/
public function getBlockName($x, $y, $z){
$block = $this->getBlock($x, $y, $z);
return isset($this->material[$block[0]]) ? $this->material[$block[0]]:"Unknown";
}
public function getFloor($x, $z, $startY = -1){
$x = (int) $x;
$z = (int) $z;
if($this->floor === true){
$map = $this->map->getFloor($x, $z, $startY);
return $map;
}else{
$startY = ((int) $startY) > -1 ? ((int) $startY):HEIGHT_LIMIT - 1;
for($y = $startY; $y > 0; --$y){
$block = $this->getBlock($x, $y, $z);
if(!isset($this->material["nosolid"][$block[0]])){
break;
}
}
return array($y, $block[0], $block[1]);
}
}
public function changeBlock($x, $y, $z, $block, $metadata = 0){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
return $this->map->changeBlock($x, $y, $z, $block, $metadata);
}
public function getBlock($x, $y, $z){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
return $this->map->getBlock($x, $y, $z);
}
public function getColumn($x, $z){
$x = (int) $x;
$z = (int) $z;
if($this->column === true){
return $this->map->getColumn($x, $z);
}else{
$zone = $this->getZone($x,0,$z,$x,HEIGHT_LIMIT,$z);
$data = array();
foreach($zone as $x => $a){
foreach($a as $y => $b){
foreach($b as $z => $block){
$data[$y] = $block;
}
}
}
return $data;
}
}
public function getEllipse($x, $y, $z, $rX = 4, $rZ = 4, $rY = 4){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
$rY = abs((int) $rX);
$rY = abs((int) $rZ);
$rY = abs((int) $rY);
return $this->getZone($x-$rX,max(0,$y-$rY),$z-$rZ,$x+$rX,$y+$rY,$z+$rZ);
}
public function getSphere($x, $y, $z, $r=4){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
$r = abs((int) $r);
return $this->getZone($x-$r,max(0,$y-$r),$z-$r,$x+$r,$y+$r,$z+$r);
}
public function getZone($x1, $y1, $z1, $x2, $y2, $z2){
$x1 = (int) $x1;
$y1 = (int) $y1;
$z1 = (int) $z1;
$x2 = (int) $x2;
$y2 = (int) $y2;
$z2 = (int) $z2;
if($x1>$x2 or $y1>$y2 or $z1>$z2){
return array();
}
$blocks = array();
for($x=$x1;$x<=$x2;++$x){
$blocks[$x] = array();
for($z=$z1;$z<=$z2;++$z){
$blocks[$x][$z] = array();
for($y=$y1;$y<=$y2;++$y){
$blocks[$x][$z][$y] = $this->getBlock($x,$y,$z);
}
}
}
return $blocks;
}
}

View File

@ -55,7 +55,7 @@ class MinecraftInterface{
}
protected function writeDump($pid, $raw, $data, $origin = "client", $ip = "", $port = 0){
if(LOG === true and DEBUG >= 2){
if(LOG === true and DEBUG >= 3){
$p = "[".(microtime(true) - $this->start)."] [".((($origin === "client" and $this->client === true) or ($origin === "server" and $this->client === false)) ? "CLIENT->SERVER":"SERVER->CLIENT")." ".$ip.":".$port."]: ".(isset($data["id"]) ? "MC Packet ".$this->dataName[$pid]:$this->name[$pid])." (0x".Utils::strTohex(chr($pid)).") [length ".strlen($raw)."]".PHP_EOL;
$p .= Utils::hexdump($raw);
if(is_array($data)){

102
classes/NBT.class.php Normal file
View File

@ -0,0 +1,102 @@
<?php
/**
* Class for reading in NBT-format files.
*
* @author Justin Martin <frozenfire@thefrozenfire.com>
* @version 1.0
* MODIFIED BY @shoghicp
*
* Dependencies:
* PHP 4.3+ (5.3+ recommended)
*/
class NBT {
public $root = array();
const TAG_END = 0;
const TAG_BYTE = 1;
const TAG_SHORT = 2;
const TAG_INT = 3;
const TAG_LONG = 4;
const TAG_FLOAT = 5;
const TAG_DOUBLE = 6;
const TAG_BYTE_ARRAY = 7;
const TAG_STRING = 8;
const TAG_LIST = 9;
const TAG_COMPOUND = 10;
public function loadFile($filename) {
if(is_file($filename)) {
$fp = fopen($filename, "rb");
}else{
trigger_error("First parameter must be a filename", E_USER_WARNING);
return false;
}
switch(basename($filename, ".dat")){
case "level":
$version = Utils::readInt(strrev(fread($fp, 4)));
$lenght = Utils::readInt(strrev(fread($fp, 4)));
break;
case "entities":
fread($fp, 12);
break;
}
$this->traverseTag($fp, $this->root);
return end($this->root);
}
public function traverseTag($fp, &$tree) {
if(feof($fp)) {
return false;
}
$tagType = $this->readType($fp, self::TAG_BYTE); // Read type byte.
if($tagType == self::TAG_END) {
return false;
} else {
$tagName = $this->readType($fp, self::TAG_STRING);
$tagData = $this->readType($fp, $tagType);
$tree[] = array("type"=>$tagType, "name"=>$tagName, "value"=>$tagData);
return true;
}
}
public function readType($fp, $tagType) {
switch($tagType) {
case self::TAG_BYTE: // Signed byte (8 bit)
return Utils::readByte(fread($fp, 1));
case self::TAG_SHORT: // Signed short (16 bit, big endian)
return Utils::readShort(strrev(fread($fp, 2)));
case self::TAG_INT: // Signed integer (32 bit, big endian)
return Utils::readInt(strrev(fread($fp, 4)));
case self::TAG_LONG: // Signed long (64 bit, big endian)
return Utils::readLong(strrev(fread($fp, 8)));
case self::TAG_FLOAT: // Floating point value (32 bit, big endian, IEEE 754-2008)
return Utils::readFloat(strrev(fread($fp, 4)));
case self::TAG_DOUBLE: // Double value (64 bit, big endian, IEEE 754-2008)
return Utils::readDouble(strrev(fread($fp, 8)));
case self::TAG_BYTE_ARRAY: // Byte array
$arrayLength = $this->readType($fp, self::TAG_INT);
$array = array();
for($i = 0; $i < $arrayLength; $i++) $array[] = $this->readType($fp, self::TAG_BYTE);
return $array;
case self::TAG_STRING: // String
if(!$stringLength = $this->readType($fp, self::TAG_SHORT)) return "";
$string = fread($fp, $stringLength); // Read in number of bytes specified by string length, and decode from utf8.
return $string;
case self::TAG_LIST: // List
$tagID = $this->readType($fp, self::TAG_BYTE);
$listLength = $this->readType($fp, self::TAG_INT);
$list = array("type"=>$tagID, "value"=>array());
for($i = 0; $i < $listLength; $i++) {
if(feof($fp)) break;
$list["value"][] = $this->readType($fp, $tagID);
}
return $list;
case self::TAG_COMPOUND: // Compound
$tree = array();
while($this->traverseTag($fp, $tree));
return $tree;
}
}
}
?>

View File

@ -28,7 +28,7 @@ the Free Software Foundation, either version 3 of the License, or
require_once("classes/Session.class.php");
class PocketMinecraftServer{
var $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities;
var $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities, $mapDir, $mapParser, $map, $level, $tileEntities;
private $database, $interface, $cnt, $events, $version, $serverType, $lastTick;
function __construct($name, $gamemode = 1, $seed = false, $protocol = CURRENT_PROTOCOL, $port = 19132, $serverID = false, $version = CURRENT_VERSION){
$this->port = (int) $port;
@ -38,6 +38,12 @@ class PocketMinecraftServer{
$this->gamemode = (int) $gamemode;
$this->version = (int) $version;
$this->name = $name;
$this->mapDir = false;
$this->mapParser = false;
$this->map = false;
$this->level = false;
$this->tileEntities = array();
$this->entities = array();
$this->custom = array();
$this->cnt = 1;
$this->eidCnt = 1;
@ -61,11 +67,8 @@ class PocketMinecraftServer{
console("[INFO] Server Name: ".$this->name);
console("[INFO] Server GUID: ".$this->serverID);
console("[INFO] Protocol Version: ".$this->protocol);
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
console("[INFO] Max Clients: ".$this->maxClients);
$this->stop = false;
console("[INFO] Server started!");
}
public function loadEvents(){
@ -120,7 +123,7 @@ class PocketMinecraftServer{
console("[DEBUG] Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"]."), Entities: ".$info["entities"].", Events: ".$info["events"].", Actions: ".$info["actions"].", Garbage: ".$info["garbage"], true, true, 2);
}
return $info;
}
}
public function close($reason = "stop"){
$this->chat(false, "Stopping server...");
@ -157,12 +160,31 @@ class PocketMinecraftServer{
}
}
private function loadMap(){
$this->level = unserialize(file_get_contents($this->mapDir."level.dat"));
console("[INFO] Map: ".$this->level["LevelName"]);
$this->seed = $this->level["RandomSeed"];
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
console("[DEBUG] Loading entities...");
$entities = unserialize(file_get_contents($this->mapDir."entities.dat"));
foreach($entities as $entity){
$this->entities[$this->eidCnt] = new Entity($this->eidCnt, ENTITY_MOB, $entity["id"], $this);
$this->entities[$this->eidCnt]->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$this->entities[$this->eidCnt]->setHealth($entity["Health"]);
++$this->eidCnt;
}
console("[DEBUG] Loaded ".count($this->entities)." Entities", true, true, 2);
}
public function start(){
declare(ticks=15);
register_tick_function(array($this, "tick"));
$this->event("onTick", "tickerFunction", true);
$this->event("onReceivedPacket", "packetHandler", true);
register_shutdown_function(array($this, "close"));
$this->loadMap();
console("[INFO] Server started!");
$this->process();
}

View File

@ -34,7 +34,6 @@ if(!defined("HEX2BIN")){
define("BIG_ENDIAN", 0x00);
define("LITTLE_ENDIAN", 0x01);
define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? BIG_ENDIAN:LITTLE_ENDIAN));
console("[DEBUG] Endianness: ".(ENDIANNESS === LITTLE_ENDIAN ? "Little Endian":"Big Endian"), true, true, 2);
class Utils{