mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-15 13:55:12 +00:00
Compare commits
69 Commits
Alpha_1.0.
...
Alpha_1.0.
Author | SHA1 | Date | |
---|---|---|---|
b1b16bc366 | |||
aa1a39adfc | |||
b3b38605b5 | |||
7030f9118d | |||
b150d4e001 | |||
125f1c11b4 | |||
82f2a0f2f8 | |||
700314d75a | |||
54e6bd0ee9 | |||
fd1186061f | |||
f03f376535 | |||
586f49994a | |||
c1aec49ad1 | |||
683c05f206 | |||
9ebe68294b | |||
c2a45212dd | |||
344449fa12 | |||
732ee755e8 | |||
f0393f9b93 | |||
f23c2f894d | |||
85dfb651bd | |||
b5e6130214 | |||
957f24c1f3 | |||
518afeae48 | |||
57282225d2 | |||
369f268b90 | |||
ab0abfab1c | |||
a64f0c8bbe | |||
8d9f9ed9ed | |||
38eed99789 | |||
284daff67f | |||
a1e6184c74 | |||
a495e8f436 | |||
3e9afbdf54 | |||
3ba8662c2c | |||
52b4220ade | |||
b9eca491e8 | |||
d7b1ae4b47 | |||
9b09ff4042 | |||
f9c71f1800 | |||
d71167f66c | |||
4b641bba39 | |||
00379bb2d1 | |||
b96070a53a | |||
db1b7ec4f2 | |||
aafd36859f | |||
0bea6e8051 | |||
96bac5aaec | |||
a501020198 | |||
19436d4953 | |||
6c8e283599 | |||
2b5c21d909 | |||
2370ca6fd4 | |||
04c3229835 | |||
9cd5a0c030 | |||
302c865f4e | |||
b3cc13d4f2 | |||
c922b073b5 | |||
f1956464b0 | |||
aa7d6b12b5 | |||
9ea1a05536 | |||
29a5041ef1 | |||
000ba5de52 | |||
637d1c313b | |||
3e392820f1 | |||
3ab149cf58 | |||
473f5ec01e | |||
cacf14df81 | |||
e20251eaf4 |
5
.gitattributes
vendored
5
.gitattributes
vendored
@ -1,5 +1,10 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
*.php text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.txt text eol=lf
|
||||
*.properties text eol=lf
|
||||
*.bat text eol=crlf
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
|
@ -3,6 +3,19 @@
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ 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
|
||||
@ -16,24 +29,11 @@ require_once("src/common/dependencies.php");
|
||||
require_once("classes/PocketMinecraftServer.class.php");
|
||||
require_once("API/ServerAPI.php");
|
||||
|
||||
while(true){
|
||||
$server = new ServerAPI();
|
||||
//You can add simple things here
|
||||
|
||||
if($server->start() !== true){
|
||||
break;
|
||||
}else{
|
||||
console("[INFO] Cleaning up...");
|
||||
hard_unset($server);
|
||||
$excludeList = array("GLOBALS", "_FILES", "_COOKIE", "_POST", "_GET", "excludeList");
|
||||
foreach(get_defined_vars() as $key => $value){
|
||||
if(!in_array($key, $excludeList)){
|
||||
$$key = null;
|
||||
unset($$key);
|
||||
}
|
||||
}
|
||||
$server = null;
|
||||
unset($server);
|
||||
console("[NOTICE] The server is restarting... (".gc_collect_cycles()." cycles collected)", true, true, 0);
|
||||
}
|
||||
$server = new ServerAPI();
|
||||
if($server->start() !== true){
|
||||
//Stop
|
||||
}else{
|
||||
//Restart
|
||||
}
|
||||
|
||||
kill(getmypid()); //Fix for segfault
|
12
README.md
12
README.md
@ -40,10 +40,6 @@ The entire server is done in PHP, and has been tested, profiled and optimized to
|
||||
|
||||
[FAQ: Frequently Asked Questions](https://github.com/shoghicp/PocketMine-MP/wiki/Frequently-Asked-Questions)
|
||||
|
||||
**Project Status: `ALPHA`**
|
||||
|
||||
**Tested in: `v4.0.0, v5.0.0`**
|
||||
|
||||
|
||||
## Current features of the server:
|
||||
|
||||
@ -53,14 +49,6 @@ The entire server is done in PHP, and has been tested, profiled and optimized to
|
||||
* Update Channels!! (stable / dev)
|
||||
|
||||
|
||||
## How to contact me
|
||||
|
||||
* Email - <shoghicp@gmail.com>
|
||||
* Twitter - [@shoghicp](https://twitter.com/shoghicp)
|
||||
* Via IRC - #mcdevs or #mcpedevs on *irc.freenode.net* (or just /msg me there)
|
||||
* [MinecraftForums profile](http://www.minecraftforum.net/user/1476633-shoghicp/)
|
||||
|
||||
|
||||
## Third-party Libraries Used
|
||||
* __[PHP cURL](http://php.net/manual/en/book.curl.php)__
|
||||
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
|
||||
|
35
TODO.md
35
TODO.md
@ -1,35 +0,0 @@
|
||||
|
||||
__Check Milestones [here](https://github.com/shoghicp/PocketMine-MP/issues/milestones)__
|
||||
|
||||
|
||||
## Not Fixing
|
||||
- Random strips and chunks of different land not sticking (the ones shown before world chunks are loaded)
|
||||
|
||||
## Known Bugs
|
||||
- Players jerk sometimes
|
||||
- Some chunk columns doesn't get loaded
|
||||
- Players don't despawn
|
||||
- Players can often hear "echos" of their own block interactions' SFX (torch placed, block destroyed, etc. most noticeable when moving around as you place.)
|
||||
|
||||
### Alpha 1.1
|
||||
* Threading
|
||||
|
||||
### Alpha 1.2
|
||||
* Scheduled block updates for events like grow, grass spread
|
||||
* Random Wheat growth
|
||||
* Random Melon growth
|
||||
* Random Sapling growth
|
||||
* Random Cactus growth
|
||||
* Random Sugarcane growth
|
||||
|
||||
## Beta (Survival)
|
||||
|
||||
- Mob spawning, item pick up
|
||||
- Mob behavior
|
||||
- Placing Paintings
|
||||
- Inventory loading and saving
|
||||
- Entity saving
|
||||
- Mob interaction (hitting)
|
||||
- Firing Arrows
|
||||
- Eating
|
||||
- Nether???
|
75
compile_php.sh
Normal file
75
compile_php.sh
Normal file
@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
echo "[INFO] PocketMine-MP PHP compiler for Linux - by @shoghicp v0.1"
|
||||
if [ "$(whoami)" != 'root' ]; then
|
||||
echo "[ERROR] You must be root to run this script"
|
||||
exit 1;
|
||||
fi
|
||||
DIR=`pwd`
|
||||
mkdir -m 0777 install_data
|
||||
mkdir -m 0777 php5
|
||||
cd install_data
|
||||
apt-get -f -y install
|
||||
apt-get -y install \
|
||||
php5-cli \
|
||||
php5-common \
|
||||
php5-curl \
|
||||
php5-gd \
|
||||
php5-gmp \
|
||||
php5-mcrypt \
|
||||
build-essential \
|
||||
git-core \
|
||||
libxml2-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libjpeg-dev \
|
||||
libpng-dev \
|
||||
libmysqlclient-dev \
|
||||
libfreetype6-dev \
|
||||
libmcrypt-dev \
|
||||
libmhash-dev
|
||||
wget ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.0.tar.bz2 -O gmp-5.1.0.tar.bz2
|
||||
tar -jxvf gmp-5.1.0.tar.bz2
|
||||
cd gmp-5.1.0
|
||||
./configure
|
||||
make
|
||||
make check
|
||||
make install
|
||||
wget http://php.net/get/php-5.4.10.tar.gz/from/this/mirror -O php-5.4.10.tar.gz
|
||||
tar -zxvf php-5.4.10.tar.gz
|
||||
cd php-5.4.10
|
||||
cd ext
|
||||
git clone https://github.com/krakjoe/pthreads.git
|
||||
cd ../
|
||||
./buildconf --force
|
||||
./configure --prefix=$DIR/php5 \
|
||||
--exec-prefix=$DIR/php5 \
|
||||
--enable-embedded-mysqli \
|
||||
--with-openssl \
|
||||
--with-mcrypt \
|
||||
--with-mhash \
|
||||
--enable-exif \
|
||||
--with-freetype-dir \
|
||||
--enable-calendar \
|
||||
--enable-soap \
|
||||
--enable-mbstring \
|
||||
--enable-bcmath \
|
||||
--enable-gd-native-ttf \
|
||||
--with-gmp \
|
||||
--with-curl \
|
||||
--enable-zip \
|
||||
--with-gd \
|
||||
--with-jpeg-dir \
|
||||
--with-png-dir \
|
||||
--with-mysql \
|
||||
--with-mcrypt \
|
||||
--with-zlib \
|
||||
--enable-sockets \
|
||||
--enable-pthreads \
|
||||
--enable-maintainer-zts \
|
||||
--enable-cli
|
||||
make
|
||||
echo "n" | make test
|
||||
make install
|
||||
cd $DIR
|
||||
rm -r -f install_data/
|
||||
rmdir install_data/
|
||||
echo "[INFO] Compilation Completed!"
|
@ -42,15 +42,51 @@ class BlockAPI{
|
||||
$this->server->addHandler("world.block.update", array($this, "updateBlockRemote"), 1);
|
||||
$this->server->addHandler("player.block.break", array($this, "blockBreak"), 1);
|
||||
$this->server->addHandler("player.block.action", array($this, "blockAction"), 1);
|
||||
$this->server->api->console->register("give", "Give items to a player", array($this, "commandHandler"));
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params){
|
||||
switch($cmd){
|
||||
case "give":
|
||||
if(!isset($params[0]) or !isset($params[1])){
|
||||
console("[INFO] Usage: /give <username> <item> [amount] [damage]");
|
||||
break;
|
||||
}
|
||||
$username = $params[0];
|
||||
$b = explode(":", $params[1]);
|
||||
if(!isset($b[1])){
|
||||
$meta = 0;
|
||||
}else{
|
||||
$meta = (int) $b[1];
|
||||
}
|
||||
$block = ((int) $b[0]) & 0xFFFF;
|
||||
if(!isset($params[2])){
|
||||
$amount = 64;
|
||||
}else{
|
||||
$amount = (int) $params[2];
|
||||
}
|
||||
if(isset($params[3])){
|
||||
$meta = (int) $params[3];
|
||||
}
|
||||
if(($player = $this->server->api->player->get($username)) !== false){
|
||||
$this->drop($player->entity->x - 0.5, $player->entity->y, $player->entity->z - 0.5, $block, $meta, $amount);
|
||||
console("[INFO] Giving ".$amount." of ".$block.":".$meta." to ".$username);
|
||||
}else{
|
||||
console("[INFO] Unknown player");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function cancelAction($block){
|
||||
$this->server->trigger("world.block.change", array(
|
||||
$this->server->api->dhandle("world.block.change", array(
|
||||
"x" => $block[2][0],
|
||||
"y" => $block[2][1],
|
||||
"z" => $block[2][2],
|
||||
"block" => $block[0],
|
||||
"meta" => $block[1],
|
||||
"fake" => true,
|
||||
));
|
||||
return false;
|
||||
}
|
||||
@ -136,7 +172,6 @@ class BlockAPI{
|
||||
$data2 = $data;
|
||||
--$data2["y"];
|
||||
$this->server->trigger("player.block.break", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}else{
|
||||
$up = $this->server->api->level->getBlock($data["x"], $data["y"] + 1, $data["z"]);
|
||||
@ -144,7 +179,6 @@ class BlockAPI{
|
||||
$data2 = $data;
|
||||
++$data2["y"];
|
||||
$this->server->trigger("player.block.break", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -153,7 +187,6 @@ class BlockAPI{
|
||||
$this->drop($data["x"], $data["y"], $data["z"], $drop[0], $drop[1] & 0x0F, $drop[2] & 0xFF);
|
||||
}
|
||||
$this->server->trigger("player.block.break", $data);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -169,10 +202,16 @@ class BlockAPI{
|
||||
"stack" => $stack,
|
||||
);
|
||||
$data["x"] += mt_rand(2, 8) / 10;
|
||||
$data["y"] += mt_rand(2, 8) / 10;
|
||||
$data["y"] += 0.19;
|
||||
$data["z"] += mt_rand(2, 8) / 10;
|
||||
$e = $this->server->api->entity->add(ENTITY_ITEM, $block, $data);
|
||||
$this->server->api->entity->spawnToAll($e->eid);
|
||||
if($this->server->api->handle("block.drop", $data) !== false){
|
||||
for($count = $stack; $count > 0; ){
|
||||
$data["stack"] = min(64, $count);
|
||||
$count -= $data["stack"];
|
||||
$e = $this->server->api->entity->add(ENTITY_ITEM, $block, $data);
|
||||
$this->server->api->entity->spawnToAll($e->eid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function blockAction($data, $event){
|
||||
@ -183,9 +222,38 @@ class BlockAPI{
|
||||
return false;
|
||||
}
|
||||
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
if($target[0] === 0){ //If no block exists
|
||||
$this->cancelAction($target);
|
||||
$block = $this->server->api->level->getBlockFace($target, $data["face"]);
|
||||
return $this->cancelAction($block);
|
||||
}
|
||||
|
||||
$cancelPlace = false;
|
||||
if(isset(Material::$activable[$target[0]])){
|
||||
switch($target[0]){
|
||||
case 54:
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
}
|
||||
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => 1,
|
||||
"type" => WINDOW_CHEST,
|
||||
"slots" => 27,
|
||||
"title" => "Chest",
|
||||
));
|
||||
break;
|
||||
case 61:
|
||||
case 62:
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
}
|
||||
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => 1,
|
||||
"type" => WINDOW_FURNACE,
|
||||
"slots" => 3,
|
||||
"title" => "Furnace",
|
||||
));
|
||||
break;
|
||||
case 6:
|
||||
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
|
||||
Sapling::growTree($this->server->api->level, $target, $target[1] & 0x03);
|
||||
@ -197,8 +265,7 @@ class BlockAPI{
|
||||
if($data["block"] === 292){ //Hoe
|
||||
$data["block"] = 60;
|
||||
$data["meta"] = 0;
|
||||
$this->server->trigger("player.block.place", $data);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.place", $data);
|
||||
$cancelPlace = true;
|
||||
}
|
||||
case 59:
|
||||
@ -206,8 +273,7 @@ class BlockAPI{
|
||||
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
|
||||
$data["block"] = $target[0];
|
||||
$data["meta"] = 0x07;
|
||||
$this->server->trigger("player.block.place", $data);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.place", $data);
|
||||
$cancelPlace = true;
|
||||
}
|
||||
break;
|
||||
@ -224,22 +290,23 @@ class BlockAPI{
|
||||
"meta" => $down[1],
|
||||
"eid" => $data["eid"],
|
||||
);
|
||||
$this->server->trigger("player.block.update", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
if($this->server->handle("player.block.update", $data2) !== false){
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$data["block"] = $target[0];
|
||||
$data["meta"] = $target[1] ^ 0x04;
|
||||
$this->server->trigger("player.block.update", $data);
|
||||
$up = $this->server->api->level->getBlock($data["x"], $data["y"] + 1, $data["z"]);
|
||||
if($up[0] === 64){
|
||||
$data2 = $data;
|
||||
$data2["meta"] = $up[1];
|
||||
++$data2["y"];
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
if($this->server->handle("player.block.update", $data) !== false){
|
||||
$up = $this->server->api->level->getBlock($data["x"], $data["y"] + 1, $data["z"]);
|
||||
if($up[0] === 64){
|
||||
$data2 = $data;
|
||||
$data2["meta"] = $up[1];
|
||||
++$data2["y"];
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$cancelPlace = true;
|
||||
break;
|
||||
@ -247,8 +314,7 @@ class BlockAPI{
|
||||
case 107: //Fence gates
|
||||
$data["block"] = $target[0];
|
||||
$data["meta"] = $target[1] ^ 0x04;
|
||||
$this->server->trigger("player.block.update", $data);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.update", $data);
|
||||
$cancelPlace = true;
|
||||
break;
|
||||
default:
|
||||
@ -258,10 +324,7 @@ class BlockAPI{
|
||||
}
|
||||
|
||||
if($cancelPlace === true){
|
||||
$this->cancelAction($target);
|
||||
BlockFace::setPosition($data, $data["face"]);
|
||||
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
return $this->cancelAction($target);
|
||||
return false;
|
||||
}
|
||||
|
||||
$replace = false;
|
||||
@ -307,7 +370,7 @@ class BlockAPI{
|
||||
}
|
||||
case 37:
|
||||
case 38:
|
||||
if($target[0] !== 2 and $target[0] !== 3){
|
||||
if(($target[0] !== 2 and $target[0] !== 3) or $data["face"] !== 1){
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -395,8 +458,7 @@ class BlockAPI{
|
||||
$data2["meta"] = 0x08;
|
||||
$data["meta"] = $direction & 0x03;
|
||||
++$data2["y"];
|
||||
$this->server->trigger("player.block.place", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.place", $data2);
|
||||
}
|
||||
break;
|
||||
case 54:
|
||||
@ -426,8 +488,7 @@ class BlockAPI{
|
||||
$data2["x"] = $next[2][0];
|
||||
$data2["y"] = $next[2][1];
|
||||
$data2["z"] = $next[2][2];
|
||||
$this->server->trigger("player.block.place", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.place", $data2);
|
||||
break;
|
||||
case 65: //Ladder
|
||||
if(isset(Material::$transparent[$target[0]])){
|
||||
@ -463,9 +524,7 @@ class BlockAPI{
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->server->trigger("player.block.place", $data);
|
||||
$this->updateBlock($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
|
||||
$this->server->handle("player.block.place", $data);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -500,7 +559,7 @@ class BlockAPI{
|
||||
"z" => $spread[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
|
||||
return true;
|
||||
}
|
||||
}elseif(isset(Material::$flowable[$spread[0]])){
|
||||
@ -510,10 +569,10 @@ class BlockAPI{
|
||||
"z" => $spread[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 10, $level | $down);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 10, $level | $down, false);
|
||||
return true;
|
||||
}elseif(($source[1] & 0x08) === 0x08){
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -539,7 +598,7 @@ class BlockAPI{
|
||||
"z" => $spread[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
|
||||
return true;
|
||||
}
|
||||
}elseif(isset(Material::$flowable[$spread[0]])){
|
||||
@ -549,10 +608,10 @@ class BlockAPI{
|
||||
"z" => $spread[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 8, $level | $down);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 8, $level | $down, false);
|
||||
return true;
|
||||
}elseif(($source[1] & 0x08) === 0x08){
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07);
|
||||
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -631,7 +690,7 @@ class BlockAPI{
|
||||
"z" => $block[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0);
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false);
|
||||
}else{
|
||||
$block[1] = ($block[1] & 0x08) | $level;
|
||||
$this->server->schedule(10, array($this, "blockScheduler"), array(
|
||||
@ -670,7 +729,7 @@ class BlockAPI{
|
||||
"z" => $block[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1]);
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +802,7 @@ class BlockAPI{
|
||||
"z" => $block[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0);
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false);
|
||||
}else{
|
||||
$block[1] = ($block[1] & 0x08) | $level;
|
||||
$this->server->schedule(20, array($this, "blockScheduler"), array(
|
||||
@ -782,7 +841,7 @@ class BlockAPI{
|
||||
"z" => $block[2][2],
|
||||
"type" => BLOCK_UPDATE_NORMAL,
|
||||
));
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1]);
|
||||
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,14 +850,14 @@ class BlockAPI{
|
||||
case 74:
|
||||
if($type === BLOCK_UPDATE_SCHEDULED or $type === BLOCK_UPDATE_RANDOM){
|
||||
$changed = true;
|
||||
$this->server->api->level->setBlock($x, $y, $z, 73, $block[1]);
|
||||
$this->server->api->level->setBlock($x, $y, $z, 73, $block[1], false);
|
||||
$type = BLOCK_UPDATE_WEAK;
|
||||
}
|
||||
break;
|
||||
case 73:
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
$changed = true;
|
||||
$this->server->api->level->setBlock($x, $y, $z, 74, $block[1]);
|
||||
$this->server->api->level->setBlock($x, $y, $z, 74, $block[1], false);
|
||||
$this->server->schedule(mt_rand(40, 100), array($this, "blockScheduler"), array(
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
|
@ -26,21 +26,25 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class ConsoleAPI{
|
||||
private $input, $server, $event;
|
||||
private $loop, $server, $event, $help, $cmds;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->help = array();
|
||||
$this->cmds = array();
|
||||
$this->server = $server;
|
||||
$this->input = fopen(FILE_PATH."logs/console.in", "w+b");
|
||||
$this->last = microtime(true);
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->event = $this->server->event("server.tick", array($this, "handle"));
|
||||
$this->loop = new ConsoleLoop;
|
||||
$this->loop->start();
|
||||
}
|
||||
|
||||
function __destroy(){
|
||||
function __destruct(){
|
||||
$this->server->deleteEvent($this->event);
|
||||
fclose($this->input);
|
||||
$this->loop->stop = true;
|
||||
$this->loop->notify();
|
||||
$this->loop->join();
|
||||
}
|
||||
|
||||
public function defaultCommands($cmd, $params){
|
||||
@ -74,6 +78,7 @@ class ConsoleAPI{
|
||||
$this->server->api->setProperty("last-update", time());
|
||||
break;
|
||||
case "stop":
|
||||
$this->loop->stop = true;
|
||||
console("[INFO] Stopping the server...");
|
||||
$this->server->close();
|
||||
break;
|
||||
@ -212,7 +217,7 @@ class ConsoleAPI{
|
||||
console("[INFO] /stop: Stops the server");
|
||||
//console("[INFO] /restart: Restarts the server");
|
||||
foreach($this->help as $c => $h){
|
||||
console("[INFO] /$c: ".$h[0]);
|
||||
console("[INFO] /$c: ".$h);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -221,30 +226,49 @@ class ConsoleAPI{
|
||||
}
|
||||
}
|
||||
|
||||
public function register($cmd, $help,$callback){
|
||||
public function alias($alias, $cmd){
|
||||
$this->cmds[strtolower(trim($alias))] = &$this->cmds[$cmd];
|
||||
}
|
||||
|
||||
public function register($cmd, $help, $callback){
|
||||
if(!is_callable($callback)){
|
||||
return false;
|
||||
}
|
||||
$this->help[strtolower(trim($cmd))] = array($help, $callback);
|
||||
$cmd = strtolower(trim($cmd));
|
||||
$this->cmds[$cmd] = $callback;
|
||||
$this->help[$cmd] = $help;
|
||||
}
|
||||
|
||||
public function handle($time){
|
||||
while(($line = fgets($this->input)) !== false){
|
||||
$line = trim($line);
|
||||
if($line === ""){
|
||||
continue;
|
||||
}
|
||||
$params = explode(" ", $line);
|
||||
$cmd = strtolower(array_shift($params));
|
||||
console("[INFO] Issued server command: /$cmd ".implode(" ", $params));
|
||||
if(isset($this->help[$cmd]) and is_callable($this->help[$cmd][1])){
|
||||
call_user_func($this->help[$cmd][1], $cmd, $params);
|
||||
}elseif($this->server->trigger("api.console.command", array("cmd" => $cmd, "params" => $params)) !== false){
|
||||
$this->defaultCommands($cmd, $params);
|
||||
if($this->loop->line !== false){
|
||||
$line = trim($this->loop->line);
|
||||
$this->loop->line = false;
|
||||
if($line !== ""){
|
||||
$params = explode(" ", $line);
|
||||
$cmd = strtolower(array_shift($params));
|
||||
console("[INFO] Issued server command: /$cmd ".implode(" ", $params));
|
||||
if(isset($this->cmds[$cmd]) and is_callable($this->cmds[$cmd])){
|
||||
call_user_func($this->cmds[$cmd], $cmd, $params);
|
||||
}elseif($this->server->api->dhandle("api.console.command", array("cmd" => $cmd, "params" => $params)) !== false){
|
||||
$this->defaultCommands($cmd, $params);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$this->loop->notify();
|
||||
}
|
||||
ftruncate($this->input, 0);
|
||||
fseek($this->input, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConsoleLoop extends Thread{
|
||||
var $line = false, $stop = false;
|
||||
public function run(){
|
||||
$fp = fopen("php://stdin", "r");
|
||||
while($this->stop === false and ($line = fgets($fp)) !== false){
|
||||
$this->line = $line;
|
||||
$this->wait();
|
||||
$this->line = false;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ class EntityAPI{
|
||||
|
||||
public function init(){
|
||||
$this->server->addHandler("player.death", array($this, "handle"), 1);
|
||||
$this->server->api->console->register("give", "Give items to a player [DUMMY]", array($this, "commandHandler"));
|
||||
}
|
||||
|
||||
public function handle($data, $event){
|
||||
@ -62,13 +61,6 @@ class EntityAPI{
|
||||
}
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params){
|
||||
switch($cmd){
|
||||
case "give":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function get($eid){
|
||||
if(isset($this->server->entities[$eid])){
|
||||
return $this->server->entities[$eid];
|
||||
|
@ -47,13 +47,13 @@ class LevelAPI{
|
||||
$this->setBlock($data["x"], $data["y"], $data["z"], $data["block"], $data["meta"]);
|
||||
break;
|
||||
case "player.block.break":
|
||||
$block = $this->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
console("[DEBUG] EID ".$data["eid"]." broke ".$block[0].":".$block[1]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
|
||||
$block = $this->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
console("[DEBUG] EID ".$data["eid"]." broke ".$block[0].":".$block[1]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
|
||||
|
||||
if($block[0] === 0){
|
||||
break;
|
||||
}
|
||||
$this->setBlock($data["x"], $data["y"], $data["z"], 0, 0);
|
||||
if($block[0] === 0){
|
||||
break;
|
||||
}
|
||||
$this->setBlock($data["x"], $data["y"], $data["z"], 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -85,16 +85,21 @@ class LevelAPI{
|
||||
return $this->heightMap[$z][$x];
|
||||
}
|
||||
|
||||
public function setBlock($x, $y, $z, $block, $meta = 0){
|
||||
public function setBlock($x, $y, $z, $block, $meta = 0, $update = true){
|
||||
$this->map->setBlock($x, $y, $z, $block, $meta);
|
||||
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z);
|
||||
$this->server->trigger("world.block.change", array(
|
||||
if($this->server->api->dhandle("world.block.change", array(
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"block" => $block,
|
||||
"meta" => $meta,
|
||||
));
|
||||
)) !== false){
|
||||
if($update === true){
|
||||
$this->server->api->block->updateBlock($x, $y, $z, BLOCK_UPDATE_NORMAL);
|
||||
$this->server->api->block->updateBlocksAround($x, $y, $z, BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrderedChunk($X, $Z, $columnsPerPacket = 2){
|
||||
|
@ -42,10 +42,12 @@ class PlayerAPI{
|
||||
public function handle($data, $event){
|
||||
switch($event){
|
||||
case "server.regeneration":
|
||||
$result = $this->server->query("SELECT ip,port FROM players WHERE EID = (SELECT EID FROM entities WHERE health < 20);", true);
|
||||
$result = $this->server->query("SELECT EID FROM players WHERE EID = (SELECT EID FROM entities WHERE health < 20);");
|
||||
if($result !== true and $result !== false){
|
||||
while(false !== ($player = $result->fetchArray())){
|
||||
$player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration");
|
||||
if(($player = $this->server->api->player->getByEID($player["EID"])) !== false){
|
||||
$player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -157,7 +157,7 @@ class PluginAPI extends stdClass{
|
||||
console("[INFO] Loading Plugins...");
|
||||
$dir = dir(FILE_PATH."plugins/");
|
||||
while(false !== ($file = $dir->read())){
|
||||
if($file !== "." and $file !== ".."){
|
||||
if($file{0} !== "."){
|
||||
if(strtolower(substr($file, -3)) === "php"){
|
||||
$this->load(FILE_PATH."plugins/" . $file);
|
||||
}
|
||||
|
@ -29,14 +29,12 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
var $restart = false;
|
||||
private $server, $config, $apiList = array();
|
||||
function __construct(){
|
||||
console("[INFO] Starting ServerAPI server handler...");
|
||||
console("[DEBUG] Checking data folders...", true, true, 2);
|
||||
@mkdir(FILE_PATH."logs/", 0777, true);
|
||||
@mkdir(FILE_PATH."players/", 0777);
|
||||
@mkdir(FILE_PATH."worlds/", 0777);
|
||||
@mkdir(FILE_PATH."plugins/", 0777);
|
||||
console("[INFO] Starting ServerAPI server handler...");
|
||||
file_put_contents(FILE_PATH."logs/packets.log", "");
|
||||
file_put_contents(FILE_PATH."logs/console.in", "");
|
||||
if(!file_exists(FILE_PATH."logs/test.bin.log") or md5_file(FILE_PATH."logs/test.bin.log") !== TEST_MD5){
|
||||
console("[NOTICE] Executing integrity tests...");
|
||||
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
|
||||
@ -90,7 +88,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
console("[DEBUG] Loading server.properties...", true, true, 2);
|
||||
$this->parseProperties();
|
||||
define("DEBUG", $this->config["debug"]);
|
||||
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), false, CURRENT_PROTOCOL, $this->getProperty("port"), $this->getProperty("server-id"));
|
||||
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), false, $this->getProperty("port"), $this->getProperty("server-id"));
|
||||
$this->server->api = $this;
|
||||
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
|
||||
console("[INFO] Checking for new server version");
|
||||
@ -123,12 +121,23 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
if($info === false or !isset($info[0])){
|
||||
console("[ERROR] GitHub API Error");
|
||||
}else{
|
||||
$info = $info[0];
|
||||
if($info["name"] != MAJOR_VERSION){
|
||||
|
||||
$newest = new VersionString(MAJOR_VERSION);
|
||||
$newest = array(-1, $newest->getNumber());
|
||||
foreach($info as $i => $tag){
|
||||
$update = new VersionString($tag["name"]);
|
||||
$update = $update->getNumber();
|
||||
if($update > $newest[1]){
|
||||
$newest = array($i, $update);
|
||||
}
|
||||
}
|
||||
|
||||
if($newest[0] !== -1){
|
||||
$target = $info[$newest[0]];
|
||||
console("[NOTICE] A new STABLE version of PocketMine-MP has been released");
|
||||
console("[NOTICE] Version \"".$info["name"]."\" [".substr($info["commit"]["sha"], 0, 10)."]");
|
||||
console("[NOTICE] Download it at ".$info["zipball_url"]);
|
||||
console("[NOTICE] This message will dissapear as soon as you update\"");
|
||||
console("[NOTICE] Version \"".(new VersionString($newest[1]))."\" #".$newest[1]." [".substr($target["commit"]["sha"], 0, 10)."]");
|
||||
console("[NOTICE] Download it at ".$target["zipball_url"]);
|
||||
console("[NOTICE] This message will dissapear as soon as you update");
|
||||
sleep(5);
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
@ -144,7 +153,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
}
|
||||
$this->server->mapName = $this->getProperty("level-name");
|
||||
$this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/";
|
||||
if($this->server->mapName === false or trim($this->server->mapName) === "" or !file_exists($this->server->mapDir."chunks.dat")){
|
||||
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";
|
||||
}
|
||||
@ -170,7 +179,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
console("[INFO] Loading default APIs");
|
||||
$dir = dir(FILE_PATH."src/API/");
|
||||
while(false !== ($file = $dir->read())){
|
||||
if($file !== "." and $file !== ".."){
|
||||
if($file{0} !== "."){ //Hidden and upwards folders
|
||||
$API = basename($file, ".php");
|
||||
if(strtolower($API) !== "serverapi"){
|
||||
$name = strtolower(substr($API, 0, -3));
|
||||
@ -187,6 +196,16 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
$this->server->loadEntities();
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
foreach($this->apiList as $ob){
|
||||
if(is_callable($ob, "__destruct")){
|
||||
$ob->__destruct();
|
||||
unset($this->apiList[$ob]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function loadProperties(){
|
||||
if(isset($this->config["memory-limit"])){
|
||||
@ini_set("memory_limit", $this->config["memory-limit"]);
|
||||
@ -274,8 +293,9 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
}
|
||||
|
||||
public function start(){
|
||||
$this->server->start();
|
||||
$this->server->init();
|
||||
unregister_tick_function(array($this->server, "tick"));
|
||||
$this->__destruct();
|
||||
unset($this->server);
|
||||
return $this->restart;
|
||||
}
|
||||
@ -286,6 +306,10 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
return $this->server->addHandler($e, $c, $p);
|
||||
}
|
||||
|
||||
public function dhandle($e, $d){
|
||||
return $this->server->handle($e, $d);
|
||||
}
|
||||
|
||||
public function handle($e, &$d){
|
||||
return $this->server->handle($e, $d);
|
||||
}
|
||||
|
71
src/classes/Async.class.php
Normal file
71
src/classes/Async.class.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?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 Async extends Thread {
|
||||
/**
|
||||
* Provide a passthrough to call_user_func_array
|
||||
**/
|
||||
public function __construct($method, $params = array()){
|
||||
$this->method = $method;
|
||||
$this->params = $params;
|
||||
$this->result = null;
|
||||
$this->joined = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The smallest thread in the world
|
||||
**/
|
||||
public function run(){
|
||||
if(($this->result=call_user_func_array($this->method, $this->params))){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to create your threads from functions ...
|
||||
**/
|
||||
public static function call($method, $params = array()){
|
||||
$thread = new Async($method, $params);
|
||||
if($thread->start()){
|
||||
return $thread;
|
||||
} /** else throw Nastyness **/
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever, result stored in $this->result, don't try to join twice
|
||||
**/
|
||||
public function __toString(){
|
||||
if(!$this->joined) {
|
||||
$this->joined = true;
|
||||
$this->join();
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
}
|
@ -59,11 +59,20 @@ class ChunkParser{
|
||||
}
|
||||
|
||||
public function loadFile($file){
|
||||
if(!file_exists($file)){
|
||||
if(ZLIB_EXTENSION === true and file_exists($file.".gz")){
|
||||
$this->raw = gzinflate(file_get_contents($file.".gz"));
|
||||
$r = @gzinflate($this->raw);
|
||||
if($r !== false and $r != ""){
|
||||
$this->raw = $r;
|
||||
}
|
||||
@unlink($file.".gz");
|
||||
file_put_contents($file, $this->raw);
|
||||
}elseif(!file_exists($file)){
|
||||
return false;
|
||||
}else{
|
||||
$this->raw = file_get_contents($file);
|
||||
}
|
||||
$this->file = $file;
|
||||
$this->raw = file_get_contents($file);
|
||||
$this->chunkLength = $this->sectorLength * ord($this->raw{0});
|
||||
return true;
|
||||
}
|
||||
@ -147,8 +156,9 @@ class ChunkParser{
|
||||
console("[DEBUG] Chunks loaded!", true, true, 2);
|
||||
}
|
||||
|
||||
public function saveMap(){
|
||||
public function saveMap($final = false){
|
||||
console("[DEBUG] Saving chunks...", true, true, 2);
|
||||
|
||||
$fp = fopen($this->file, "r+b");
|
||||
flock($fp, LOCK_EX);
|
||||
foreach($this->map as $x => $d){
|
||||
@ -159,6 +169,15 @@ class ChunkParser{
|
||||
}
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
if(ZLIB_EXTENSION === true){
|
||||
$original = filesize($this->file);
|
||||
file_put_contents($this->file .".gz", gzdeflate(gzdeflate(file_get_contents($this->file),9),9)); //Double compression for flat maps
|
||||
$compressed = filesize($this->file .".gz");
|
||||
console("[DEBUG] Saved chunks.dat.gz with ".round(($compressed/$original)*100, 2)."% (".round($compressed/1024, 2)."KB) of the original size", true, true, 2);
|
||||
if($final === true){
|
||||
@unlink($this->file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFloor($x, $z){
|
||||
|
@ -56,6 +56,15 @@ class CustomPacketHandler{
|
||||
$this->raw .= Utils::writeLong($this->data["payload"]);
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
if($this->c === false){
|
||||
$this->data["unknown1"] = Utils::readLong($this->get(8));
|
||||
$this->data["unknown2"] = Utils::readLong($this->get(8));
|
||||
}else{
|
||||
$this->raw .= Utils::writeLong($this->data["unknown1"]);
|
||||
$this->raw .= Utils::writeLong($this->data["unknown2"]);
|
||||
}
|
||||
break;
|
||||
case MC_CLIENT_CONNECT:
|
||||
if($this->c === false){
|
||||
$this->data["clientID"] = Utils::readLong($this->get(8));
|
||||
@ -279,6 +288,15 @@ class CustomPacketHandler{
|
||||
$this->raw .= Utils::writeByte($this->data["roll"]);
|
||||
}
|
||||
break;
|
||||
case MC_TAKE_ITEM_ENTITY:
|
||||
if($this->c === false){
|
||||
$this->data["target"] = Utils::readInt($this->get(4));
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
}else{
|
||||
$this->raw .= Utils::writeInt($this->data["target"]);
|
||||
$this->raw .= Utils::writeInt($this->data["eid"]);
|
||||
}
|
||||
break;
|
||||
case MC_MOVE_ENTITY:
|
||||
if($this->c === false){
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
@ -445,9 +463,9 @@ class CustomPacketHandler{
|
||||
break;
|
||||
case MC_SET_HEALTH:
|
||||
if($this->c === false){
|
||||
$this->data["health"] = ord($this->get(1));
|
||||
$this->data["health"] = Utils::readByte($this->get(1));
|
||||
}else{
|
||||
$this->raw .= chr($this->data["health"]);
|
||||
$this->raw .= Utils::writeByte($this->data["health"]);
|
||||
}
|
||||
break;
|
||||
case MC_ANIMATE:
|
||||
@ -472,6 +490,56 @@ class CustomPacketHandler{
|
||||
$this->raw .= Utils::writeFloat($this->data["z"]);
|
||||
}
|
||||
break;
|
||||
case MC_DROP_ITEM:
|
||||
if($this->c === false){
|
||||
$this->data["eid"] = Utils::readInt($this->get(4));
|
||||
$this->data["unknown1"] = ord($this->get(1));
|
||||
$this->data["block"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["stack"] = ord($this->get(1));
|
||||
$this->data["meta"] = Utils::readShort($this->get(2), false);
|
||||
}else{
|
||||
$this->raw .= Utils::writeInt($this->data["eid"]);
|
||||
$this->raw .= chr($this->data["unknown1"]);
|
||||
$this->raw .= Utils::writeShort($this->data["block"]);
|
||||
$this->raw .= chr($this->data["stack"]);
|
||||
$this->raw .= Utils::writeShort($this->data["meta"]);
|
||||
}
|
||||
break;
|
||||
case MC_CONTAINER_OPEN:
|
||||
if($this->c === false){
|
||||
$this->data["windowid"] = ord($this->get(1));
|
||||
$this->data["type"] = ord($this->get(1));
|
||||
$this->data["slots"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["title"] = $this->get(Utils::readShort($this->get(2), false));
|
||||
}else{
|
||||
$this->raw .= chr($this->data["windowid"]);
|
||||
$this->raw .= chr($this->data["type"]);
|
||||
$this->raw .= Utils::writeShort($this->data["slots"]);
|
||||
$this->raw .= Utils::writeShort(strlen($this->data["title"])).$this->data["title"];
|
||||
}
|
||||
break;
|
||||
case MC_CONTAINER_CLOSE:
|
||||
if($this->c === false){
|
||||
$this->data["windowid"] = ord($this->get(1));
|
||||
}else{
|
||||
$this->raw .= chr($this->data["windowid"]);
|
||||
}
|
||||
break;
|
||||
case MC_CONTAINER_SET_SLOT:
|
||||
if($this->c === false){
|
||||
$this->data["windowid"] = ord($this->get(1));
|
||||
$this->data["slot"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["block"] = Utils::readShort($this->get(2), false);
|
||||
$this->data["stack"] = ord($this->get(1));
|
||||
$this->data["meta"] = Utils::readShort($this->get(2), false);
|
||||
}else{
|
||||
$this->raw .= chr($this->data["windowid"]);
|
||||
$this->raw .= Utils::writeShort($this->data["slot"]);
|
||||
$this->raw .= Utils::writeShort($this->data["block"]);
|
||||
$this->raw .= chr($this->data["stack"]);
|
||||
$this->raw .= Utils::writeShort($this->data["meta"]);
|
||||
}
|
||||
break;
|
||||
case MC_CLIENT_MESSAGE:
|
||||
if($this->c === false){
|
||||
$this->data["message"] = $this->get(Utils::readShort($this->get(2), false));
|
||||
@ -509,6 +577,13 @@ class CustomPacketHandler{
|
||||
$this->raw .= $this->data["unknown2"];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if($this->c === false){
|
||||
console("[DEBUG] Received unknown Data Packet ID 0x".dechex($pid), true, true, 2);
|
||||
}else{
|
||||
console("[DEBUG] Sent unknown Data Packet ID 0x".dechex($pid), true, true, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class Material{
|
||||
);
|
||||
static $unbreakable = array(
|
||||
0 => true,
|
||||
//7 => true,
|
||||
7 => true,
|
||||
8 => true,
|
||||
9 => true,
|
||||
10 => true,
|
||||
|
@ -2,20 +2,20 @@
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
/ 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
|
||||
@ -34,7 +34,7 @@ define("ENTITY_PAINTING", 4);
|
||||
|
||||
class Entity extends stdClass{
|
||||
var $eid, $type, $name, $x, $y, $z, $yaw, $pitch, $dead, $data, $class, $attach, $metadata, $closed, $player, $onTick;
|
||||
private $ev, $server;
|
||||
private $server;
|
||||
function __construct($server, $eid, $class, $type = 0, $data = array()){
|
||||
$this->server = $server;
|
||||
$this->eid = (int) $eid;
|
||||
@ -49,7 +49,7 @@ class Entity extends stdClass{
|
||||
$this->closed = false;
|
||||
$this->name = "";
|
||||
$this->server->query("INSERT OR REPLACE INTO entities (EID, type, class, health) VALUES (".$this->eid.", ".$this->type.", ".$this->class.", ".$this->health.");");
|
||||
$this->ev = $this->server->event("server.tick", array($this, "update"));
|
||||
$this->server->schedule(20, array($this, "update"), array(), true);
|
||||
$this->metadata = array();
|
||||
$this->x = isset($this->data["x"]) ? $this->data["x"]:0;
|
||||
$this->y = isset($this->data["y"]) ? $this->data["y"]:0;
|
||||
@ -76,7 +76,20 @@ class Entity extends stdClass{
|
||||
}
|
||||
|
||||
public function update(){
|
||||
|
||||
if($this->class === ENTITY_ITEM and $this->closed === false){
|
||||
$this->server->api->dhandle("entity.move", $this);
|
||||
$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);
|
||||
if($player !== true and $player !== false){
|
||||
if($this->server->api->dhandle("player.item.pick", array(
|
||||
"eid" => $player["EID"],
|
||||
"block" => $this->type,
|
||||
"meta" => $this->meta,
|
||||
"target" => $this->eid
|
||||
)) !== false){
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getDirection(){
|
||||
@ -151,9 +164,9 @@ class Entity extends stdClass{
|
||||
public function close(){
|
||||
if($this->closed === false){
|
||||
$this->server->query("DELETE FROM entities WHERE EID = ".$this->eid.";");
|
||||
$this->server->trigger("entity.remove", $this->eid);
|
||||
$this->server->deleteEvent($this->ev);
|
||||
$this->server->api->dhandle("entity.remove", $this);
|
||||
$this->closed = true;
|
||||
$this->__destruct();
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +230,7 @@ class Entity extends stdClass{
|
||||
public function setHealth($health, $cause = ""){
|
||||
$this->health = (int) $health;
|
||||
$this->server->query("UPDATE entities SET health = ".$this->health." WHERE EID = ".$this->eid.";");
|
||||
$this->server->trigger("entity.health.change", array("eid" => $this->eid, "health" => $health, "cause" => $cause));
|
||||
$this->server->api->dhandle("entity.health.change", array("eid" => $this->eid, "health" => $health, "cause" => $cause));
|
||||
if($this->player !== false){
|
||||
$this->player->dataPacket(MC_SET_HEALTH, array(
|
||||
"health" => $this->health,
|
||||
@ -226,7 +239,7 @@ class Entity extends stdClass{
|
||||
if($this->health <= 0 and $this->dead === false){
|
||||
$this->dead = true;
|
||||
if($this->player !== false){
|
||||
$this->server->handle("player.death", array("name" => $this->name, "cause" => $cause));
|
||||
$this->server->api->dhandle("player.death", array("name" => $this->name, "cause" => $cause));
|
||||
}
|
||||
}elseif($this->health > 0){
|
||||
$this->dead = false;
|
||||
|
@ -26,10 +26,11 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class WorldGenerator{
|
||||
private $gen, $seed, $raw;
|
||||
private $gen, $seed, $genName, $raw;
|
||||
public function __construct($genName, $seed){
|
||||
$this->seed = (int) $seed;
|
||||
$this->raw = b"";
|
||||
$this->genName = $genName;
|
||||
$this->gen = new $genName($this->seed);
|
||||
}
|
||||
|
||||
@ -345,6 +346,7 @@ class WorldGenerator{
|
||||
"Time" => 0,
|
||||
"Gamemode" => 1,
|
||||
"RandomSeed" => $this->seed,
|
||||
"Generator" => $this->genName,
|
||||
"SpawnX" => $s[0],
|
||||
"SpawnY" => $s[1],
|
||||
"SpawnZ" => $s[2],
|
||||
|
@ -26,14 +26,13 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class MinecraftInterface{
|
||||
var $pstruct, $name, $protocol, $client, $dataName;
|
||||
var $pstruct, $name, $client, $dataName;
|
||||
private $socket, $data;
|
||||
function __construct($server, $protocol = CURRENT_PROTOCOL, $port = 25565, $listen = false, $client = true){
|
||||
function __construct($server, $port = 25565, $listen = false, $client = true){
|
||||
$this->socket = new UDPSocket($server, $port, (bool) $listen);
|
||||
$this->protocol = (int) $protocol;
|
||||
require("pstruct/RakNet.php");
|
||||
require("pstruct/packetName.php");
|
||||
require("pstruct/".$this->protocol.".php");
|
||||
require("pstruct/protocol.php");
|
||||
require("pstruct/dataName.php");
|
||||
$this->pstruct = $pstruct;
|
||||
$this->name = $packetName;
|
||||
@ -93,7 +92,6 @@ class MinecraftInterface{
|
||||
}
|
||||
|
||||
$packet = new Packet($pid, $struct, $data[0]);
|
||||
$packet->protocol = $this->protocol;
|
||||
$packet->parse();
|
||||
$this->data[] = array($pid, $packet->data, $data[0], $data[1], $data[2]);
|
||||
return $this->popPacket();
|
||||
@ -119,7 +117,6 @@ class MinecraftInterface{
|
||||
$struct = $this->getStruct($pid);
|
||||
if($raw === false){
|
||||
$packet = new Packet($pid, $struct);
|
||||
$packet->protocol = $this->protocol;
|
||||
$packet->data = $data;
|
||||
$packet->create();
|
||||
$write = $this->socket->write($packet->raw, $dest, $port);
|
||||
|
66
src/classes/NormalGenerator.class.php
Normal file
66
src/classes/NormalGenerator.class.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class Packet{
|
||||
private $struct, $sock;
|
||||
protected $pid, $packet;
|
||||
public $data, $raw, $protocol;
|
||||
public $data, $raw;
|
||||
|
||||
function __construct($pid, $struct, $data = ""){
|
||||
$this->pid = $pid;
|
||||
@ -75,7 +75,7 @@ class Packet{
|
||||
case 0x40:
|
||||
$reply = new CustomPacketHandler($this->data[$field]["id"], "", $this->data[$field], true);
|
||||
$this->addRaw(Utils::writeShort((strlen($reply->raw) + 1) << 3));
|
||||
$this->addRaw(Utils::writeTriad($this->data[$field]["count"]));
|
||||
$this->addRaw(Utils::writeTriad(strrev($this->data[$field]["count"])));
|
||||
$this->addRaw(chr($this->data[$field]["id"]));
|
||||
$this->addRaw($reply->raw);
|
||||
break;
|
||||
|
@ -105,7 +105,7 @@ class Player{
|
||||
|
||||
$this->connected = false;
|
||||
if($msg === true){
|
||||
$this->server->trigger("server.chat", $this->username." left the game");
|
||||
$this->server->api->dhandle("server.chat", $this->username." left the game");
|
||||
}
|
||||
console("[INFO] Session with ".$this->ip.":".$this->port." Client ID ".$this->clientID." closed due to ".$reason);
|
||||
$this->server->api->player->remove($this->CID);
|
||||
@ -113,6 +113,12 @@ class Player{
|
||||
|
||||
public function eventHandler($data, $event){
|
||||
switch($event){
|
||||
case "player.item.pick":
|
||||
if($data["eid"] === $this->eid){
|
||||
$data["eid"] = 0;
|
||||
}
|
||||
$this->dataPacket(MC_TAKE_ITEM_ENTITY, $data);
|
||||
break;
|
||||
case "player.equipment.change":
|
||||
if($data["eid"] === $this->eid){
|
||||
break;
|
||||
@ -123,25 +129,24 @@ class Player{
|
||||
$this->dataPacket(MC_UPDATE_BLOCK, $data);
|
||||
break;
|
||||
case "entity.move":
|
||||
if($data === $this->eid){
|
||||
if($data->eid === $this->eid){
|
||||
break;
|
||||
}
|
||||
$entity = $this->server->entities[$data];
|
||||
$this->dataPacket(MC_MOVE_ENTITY_POSROT, array(
|
||||
"eid" => $data,
|
||||
"x" => $entity->x,
|
||||
"y" => $entity->y,
|
||||
"z" => $entity->z,
|
||||
"yaw" => $entity->yaw,
|
||||
"pitch" => $entity->pitch,
|
||||
"eid" => $data->eid,
|
||||
"x" => $data->x,
|
||||
"y" => $data->y,
|
||||
"z" => $data->z,
|
||||
"yaw" => $data->yaw,
|
||||
"pitch" => $data->pitch,
|
||||
));
|
||||
break;
|
||||
case "entity.remove":
|
||||
if($data === $this->eid){
|
||||
if($data->eid === $this->eid){
|
||||
break;
|
||||
}
|
||||
$this->dataPacket(MC_ENTITY_REMOVE, array(
|
||||
"eid" => $data,
|
||||
$this->dataPacket(MC_REMOVE_ENTITY, array(
|
||||
"eid" => $data->eid,
|
||||
));
|
||||
break;
|
||||
case "server.time.change":
|
||||
@ -207,9 +212,21 @@ class Player{
|
||||
));
|
||||
break;
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x86:
|
||||
case 0x87:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8a:
|
||||
case 0x8b:
|
||||
case 0x8c:
|
||||
case 0x8d:
|
||||
case 0x8e:
|
||||
case 0x8f:
|
||||
if(isset($data[0])){
|
||||
$diff = $data[0] - $this->counter[1];
|
||||
if($diff > 1){ //Packet recovery
|
||||
@ -223,6 +240,13 @@ class Player{
|
||||
$this->send(0xc0, array(1, true, $data[0]));
|
||||
}
|
||||
switch($data["id"]){
|
||||
|
||||
case MC_KEEP_ALIVE:
|
||||
|
||||
break;
|
||||
case 0x03:
|
||||
|
||||
break;
|
||||
case MC_DISCONNECT:
|
||||
$this->connected = false;
|
||||
$this->close("client disconnect");
|
||||
@ -238,7 +262,7 @@ class Player{
|
||||
|
||||
break;
|
||||
case MC_LOGIN:
|
||||
$this->username = str_replace("/", "", $data["username"]);
|
||||
$this->username = str_replace(array("\x00", "/", " ", "\r", "\n"), array("", "-", "_", "", ""), $data["username"]);
|
||||
if($this->username == ""){
|
||||
$this->close("bad username", false);
|
||||
break;
|
||||
@ -275,35 +299,42 @@ class Player{
|
||||
));
|
||||
break;
|
||||
case MC_READY:
|
||||
if($this->spawned !== false){
|
||||
break;
|
||||
}
|
||||
$this->spawned = true;
|
||||
$this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this));
|
||||
$this->eid = $this->entity->eid;
|
||||
$this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";");
|
||||
$this->entity->setName($this->username);
|
||||
$this->entity->data["clientID"] = $this->clientID;
|
||||
$this->server->api->entity->spawnAll($this);
|
||||
$this->server->api->entity->spawnToAll($this->eid);
|
||||
$this->evid[] = $this->server->event("server.time.change", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("server.chat", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.remove", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.move", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("player.equipment.change", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("world.block.change", array($this, "eventHandler"));
|
||||
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
|
||||
switch($data["status"]){
|
||||
case 1:
|
||||
if($this->spawned !== false){
|
||||
break;
|
||||
}
|
||||
$this->spawned = true;
|
||||
$this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this));
|
||||
$this->eid = $this->entity->eid;
|
||||
$this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";");
|
||||
$this->entity->setName($this->username);
|
||||
$this->entity->data["clientID"] = $this->clientID;
|
||||
$this->server->api->entity->spawnAll($this);
|
||||
$this->server->api->entity->spawnToAll($this->eid);
|
||||
$this->evid[] = $this->server->event("server.time.change", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("server.chat", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.remove", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.move", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("player.equipment.change", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("player.item.pick", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("world.block.change", array($this, "eventHandler"));
|
||||
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
|
||||
|
||||
$this->eventHandler($this->server->motd, "server.chat");
|
||||
if($this->MTU <= 548){
|
||||
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "server.chat");
|
||||
$this->eventHandler($this->server->motd, "server.chat");
|
||||
if($this->MTU <= 548){
|
||||
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "server.chat");
|
||||
}
|
||||
break;
|
||||
case 2://Chunk loaded?
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MC_MOVE_PLAYER:
|
||||
if(is_object($this->entity)){
|
||||
$this->entity->setPosition($data["x"], $data["y"], $data["z"], $data["yaw"], $data["pitch"]);
|
||||
$this->server->trigger("entity.move", $this->eid);
|
||||
$this->server->api->dhandle("entity.move", $this->entity);
|
||||
}
|
||||
break;
|
||||
case MC_PLAYER_EQUIPMENT:
|
||||
@ -330,13 +361,16 @@ class Player{
|
||||
break;
|
||||
case MC_USE_ITEM:
|
||||
$data["eid"] = $this->eid;
|
||||
if(Utils::distance($this->entity->position, $data) > 10){
|
||||
break;
|
||||
}
|
||||
$this->server->handle("player.block.action", $data);
|
||||
break;
|
||||
case MC_PLACE_BLOCK:
|
||||
|
||||
break;
|
||||
case MC_REMOVE_BLOCK:
|
||||
$data["eid"] = $this->eid;
|
||||
if(Utils::distance($this->entity->position, $data) > 8){
|
||||
break;
|
||||
}
|
||||
$this->server->handle("player.block.break", $data);
|
||||
break;
|
||||
case MC_INTERACT:
|
||||
@ -348,13 +382,24 @@ class Player{
|
||||
}
|
||||
break;
|
||||
case MC_ANIMATE:
|
||||
$this->server->trigger("entity.animate", array("eid" => $this->eid, "action" => $data["action"]));
|
||||
$this->server->api->dhandle("entity.animate", array("eid" => $this->eid, "action" => $data["action"]));
|
||||
break;
|
||||
case MC_RESPAWN:
|
||||
$this->entity->setHealth(20, "respawn");
|
||||
$this->entity->setPosition($data["x"], $data["y"], $data["z"], 0, 0);
|
||||
break;
|
||||
|
||||
case MC_SET_HEALTH:
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
}
|
||||
$this->entity->setHealth($data["health"], "client");
|
||||
break;
|
||||
case MC_DROP_ITEM:
|
||||
$this->server->api->block->drop($this->entity->x, $this->entity->y, $this->entity->z, $data["block"], $data["meta"], $data["stack"]);
|
||||
break;
|
||||
default:
|
||||
console("[DEBUG] Unhandled 0x".dechex($data["id"])." Data Packet for Client ID ".$this->clientID.": ".print_r($data, true), true, true, 2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -26,11 +26,14 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class PocketMinecraftServer extends stdClass{
|
||||
var $invisible, $tickMeasure, $preparedSQL, $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities, $mapDir, $mapName, $map, $level, $tileEntities;
|
||||
var $invisible, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities, $mapDir, $mapName, $map, $level, $tileEntities;
|
||||
private $database, $interface, $evCnt, $handCnt, $events, $handlers, $version, $serverType, $lastTick;
|
||||
function __construct($name, $gamemode = 1, $seed = false, $protocol = CURRENT_PROTOCOL, $port = 19132, $serverID = false, $version = CURRENT_VERSION){
|
||||
function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $serverID = false){
|
||||
$this->port = (int) $port; //19132 - 19135
|
||||
console("[INFO] PocketMine-MP ".MAJOR_VERSION." by @shoghicp, LGPL License", true, true, 0);
|
||||
$vNumber = new VersionString();
|
||||
$vNumber = $vNumber->getNumber();
|
||||
console("[INFO] PocketMine-MP ".MAJOR_VERSION." #".$vNumber." by @shoghicp, LGPL License", true, true, 0);
|
||||
console("[DEBUG] Target Minecraft PE: ".CURRENT_MINECRAFT_VERSION, true, true, 2);
|
||||
console("[INFO] Starting Minecraft PE Server at *:".$this->port);
|
||||
if($this->port < 19132 or $this->port > 19135){
|
||||
console("[WARNING] You've selected a not-standard port. Normal port range is from 19132 to 19135 included");
|
||||
@ -38,7 +41,6 @@ class PocketMinecraftServer extends stdClass{
|
||||
console("[INFO] Loading database...");
|
||||
$this->startDatabase();
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->version = (int) $version;
|
||||
$this->name = $name;
|
||||
$this->mapDir = false;
|
||||
$this->mapName = false;
|
||||
@ -64,17 +66,16 @@ class PocketMinecraftServer extends stdClass{
|
||||
$this->serverID = $serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$serverID;
|
||||
$this->seed = $seed === false ? Utils::readInt(Utils::getRandomBytes(4)):$seed;
|
||||
$this->clients = array();
|
||||
$this->protocol = (int) $protocol;
|
||||
$this->spawn = array("x" => 128.5,"y" => 100,"z" => 128.5);
|
||||
$this->time = 0;
|
||||
$this->timePerSecond = 10;
|
||||
$this->tickMeasure = array_fill(0, 40, 0);
|
||||
$this->setType("normal");
|
||||
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, $this->port, true, false);
|
||||
$this->interface = new MinecraftInterface("255.255.255.255", $this->port, true, false);
|
||||
$this->reloadConfig();
|
||||
console("[INFO] Server Name: ".$this->name);
|
||||
console("[INFO] Server GUID: ".$this->serverID);
|
||||
console("[INFO] Protocol Version: ".$this->protocol);
|
||||
console("[INFO] Protocol Version: ".CURRENT_PROTOCOL);
|
||||
console("[INFO] Max Clients: ".$this->maxClients);
|
||||
$this->stop = false;
|
||||
}
|
||||
@ -89,14 +90,14 @@ class PocketMinecraftServer extends stdClass{
|
||||
$this->event("server.chat", array($this, "eventHandler"));
|
||||
$this->event("player.new", array($this, "eventHandler"));
|
||||
|
||||
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->trigger("server.time.change", $this->time);');
|
||||
$this->action(5000000, 'if($this->difficulty < 2){$this->trigger("server.regeneration", 1);}');
|
||||
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->api->dhandle("server.time.change", $this->time);');
|
||||
$this->action(5000000, 'if($this->difficulty < 2){$this->api->dhandle("server.regeneration", 1);}');
|
||||
$this->action(1000000 * 60, '$this->reloadConfig();');
|
||||
$this->action(1000000 * 60 * 10, '$this->custom = array();');
|
||||
if($this->api !== false){
|
||||
$this->action(1000000 * 80, '$this->chat(false, count($this->clients)."/".$this->maxClients." online: ".implode(", ",$this->api->player->online()));');
|
||||
$this->action(1000000 * 80, '$this->chat(false, "Online (".count($this->clients)."): ".implode(", ",$this->api->player->online()));');
|
||||
}
|
||||
$this->action(1000000 * 75, '$this->debugInfo(true);');
|
||||
$this->action(1000000 * 120, '$this->debugInfo(true);');
|
||||
}
|
||||
|
||||
public function startDatabase(){
|
||||
@ -155,9 +156,9 @@ class PocketMinecraftServer extends stdClass{
|
||||
public function close($reason = "stop"){
|
||||
if($this->stop !== true){
|
||||
$this->chat(false, "Stopping server...");
|
||||
$this->save();
|
||||
$this->save(true);
|
||||
$this->stop = true;
|
||||
$this->trigger("server.close");
|
||||
$this->trigger("server.close", $reason);
|
||||
$this->interface->close();
|
||||
}
|
||||
}
|
||||
@ -168,7 +169,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
$message = "<".$owner."> ";
|
||||
}
|
||||
$message .= $text;
|
||||
$this->trigger("server.chat", $message);
|
||||
$this->handle("server.chat", $message);
|
||||
}
|
||||
|
||||
public function setType($type = "normal"){
|
||||
@ -296,10 +297,10 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
}
|
||||
|
||||
public function save(){
|
||||
public function save($final = false){
|
||||
if($this->mapName !== false){
|
||||
file_put_contents($this->mapDir."level.dat", serialize($this->level));
|
||||
$this->map->saveMap();
|
||||
$this->map->saveMap($final);
|
||||
console("[INFO] Saving entities...");
|
||||
foreach($this->entities as $entity){
|
||||
|
||||
@ -307,7 +308,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
}
|
||||
|
||||
public function start(){
|
||||
public function init(){
|
||||
if($this->mapName !== false and $this->map === false){
|
||||
$this->loadMap();
|
||||
$this->loadEntities();
|
||||
@ -333,7 +334,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
|
||||
public function clientID($ip, $port){
|
||||
return md5($pi . $port, true);
|
||||
return md5($ip . $port, true);
|
||||
}
|
||||
|
||||
public function packetHandler($packet){
|
||||
@ -397,9 +398,9 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
$version = $data[1];
|
||||
$size = strlen($data[2]);
|
||||
if($version !== $this->protocol){
|
||||
if($version !== CURRENT_PROTOCOL){
|
||||
$this->send(0x1a, array(
|
||||
$this->protocol,
|
||||
CURRENT_PROTOCOL,
|
||||
MAGIC,
|
||||
$this->serverID,
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
@ -495,7 +496,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
$add = ' unset($this->schedule['.$this->scheduleCnt.']);';
|
||||
}
|
||||
$this->schedule[$this->scheduleCnt] = array($callback, $data, $eventName);
|
||||
$this->action(50000 * $ticks, '$schedule = $this->schedule['.$this->scheduleCnt.'];'.$add.' call_user_func($schedule[0], $schedule[1], $schedule[2]);', (bool) $repeat);
|
||||
$this->action(50000 * $ticks, '$schedule = $this->schedule['.$this->scheduleCnt.'];'.$add.'if(!is_callable($schedule[0])){unset($this->schedule['.$this->scheduleCnt.']);return;} call_user_func($schedule[0], $schedule[1], $schedule[2]);', (bool) $repeat);
|
||||
return $this->scheduleCnt++;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class SerializedPacketHandler{
|
||||
|
||||
$len = ceil(Utils::readShort($this->get(2), false) / 8); //Utils::readShort($this->get(2), false) >> 3;
|
||||
if($pid !== 0x00){
|
||||
$c = Utils::readTriad($this->get(3));
|
||||
$c = Utils::readTriad(strrev($this->get(3)));
|
||||
}
|
||||
if($pid === 0x60 and $i === 0){
|
||||
$this->data["unknown1"] = $this->get(4);
|
||||
|
@ -25,11 +25,12 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
$fp = fopen(dirname(__FILE__)."/../../logs/console.in","wb");
|
||||
while(true){
|
||||
$l = fgets(STDIN);
|
||||
fwrite($fp, $l);
|
||||
if(strtolower(trim($l)) === "stop" and isset($argv[1]) and trim($argv[1]) == "1"){
|
||||
die();
|
||||
class TileEntity extends stdClass{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -41,6 +41,8 @@ abstract class Utils{
|
||||
$uname = strtoupper(php_uname("s"));
|
||||
if(strpos($uname, "WIN") !== false){
|
||||
return "win";
|
||||
}elseif(strpos($uname, "DARWIN") !== false){
|
||||
return "mac";
|
||||
}else{
|
||||
return "linux";
|
||||
}
|
||||
|
@ -25,17 +25,15 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
//Protocol Version: 4
|
||||
define("WINDOW_CHEST", 0);
|
||||
define("WINDOW_WORKBENCH", 1);
|
||||
define("WINDOW_FURNACE", 2);
|
||||
|
||||
class Window{
|
||||
private $server;
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
|
||||
define("MC_KEEP_ALIVE", 0x00);
|
||||
define("MC_CLIENT_CONNECT", 0x09);
|
||||
define("MC_SERVER_HANDSHAKE", 0x10);
|
||||
define("MC_CLIENT_HANDSHAKE", 0x13);
|
||||
define("MC_CLIENT_DISCONNECT", 0x15);
|
||||
define("MC_LOGIN", 0x86);
|
||||
define("MC_LOGIN_STATUS", 0x87);
|
||||
define("MC_READY", 0x88);
|
||||
define("MC_CHAT", 0x89);
|
||||
define("MC_SET_TIME", 0x8a);
|
||||
define("MC_START_GAME", 0x8b);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -34,10 +34,10 @@ ini_set("display_errors", 1);
|
||||
ini_set('default_charset', 'utf-8');
|
||||
define("FILE_PATH", dirname(__FILE__)."/../../");
|
||||
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH . PATH_SEPARATOR . FILE_PATH . "/src/" . PATH_SEPARATOR . FILE_PATH . "/src/classes/");
|
||||
ini_set("memory_limit", "256M");
|
||||
define("CURRENT_PROTOCOL", 5);
|
||||
define("CURRENT_VERSION", 1);
|
||||
ini_set("memory_limit", "512M");
|
||||
define("LOG", true);
|
||||
define("MAGIC", "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78");
|
||||
define("TEST_MD5", "5ca8eced50a5801619f7ae86d631a4e7");
|
||||
define("MAJOR_VERSION", "Alpha_1.0.2");
|
||||
define("MAJOR_VERSION", "Alpha_1.0.5");
|
||||
define("CURRENT_PROTOCOL", 5);
|
||||
define("CURRENT_MINECRAFT_VERSION", "v0.5.0 alpha");
|
@ -25,7 +25,6 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__)."/config.php");
|
||||
require_once("common/functions.php");
|
||||
//set_error_handler("error_handler");
|
||||
@ -35,6 +34,9 @@ $errors = 0;
|
||||
if(version_compare("5.3.3", PHP_VERSION) > 0){
|
||||
console("[ERROR] Use PHP >= 5.3.3", true, true, 0);
|
||||
++$errors;
|
||||
}elseif(version_compare("5.5.0", PHP_VERSION) <= 0){
|
||||
console("[NOTICE] PocketMine-MP hasn't been tested with PHP >= 5.5", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(version_compare("5.4.0", PHP_VERSION) > 0){
|
||||
@ -49,32 +51,39 @@ if(php_sapi_name() !== "cli"){
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(!extension_loaded("sockets")){
|
||||
if(!extension_loaded("sockets") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "sockets." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find Socket extension", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
/*if(!extension_loaded("pthreads")){
|
||||
if(!extension_loaded("pthreads") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "pthreads." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find pthreads extension. [https://github.com/krakjoe/pthreads]", true, true, 0);
|
||||
++$errors;
|
||||
}*/
|
||||
}
|
||||
|
||||
if(!extension_loaded("curl")){
|
||||
if(!extension_loaded("curl") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "curl." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find cURL extension", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(!extension_loaded("sqlite3")){
|
||||
if(!extension_loaded("sqlite3") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "sqlite3." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find SQLite3 extension", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(!extension_loaded("zlib") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "zlib." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find Zlib extension. Compressed worlds won't be loaded", true, true, 0);
|
||||
define("ZLIB_EXTENSION", false);
|
||||
}else{
|
||||
define("ZLIB_EXTENSION", true);
|
||||
}
|
||||
|
||||
if($errors > 0){
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
|
||||
require_once("classes/Async.class.php");
|
||||
require_once("classes/Data.class.php");
|
||||
require_once("classes/Player.class.php");
|
||||
require_once("classes/Generator.class.php");
|
||||
@ -83,6 +92,8 @@ require_once("classes/Utils.class.php");
|
||||
require_once("classes/UDPSocket.class.php");
|
||||
require_once("classes/Packet.class.php");
|
||||
require_once("classes/Entity.class.php");
|
||||
require_once("classes/TileEntity.class.php");
|
||||
require_once("classes/Window.class.php");
|
||||
require_once("classes/ChunkParser.class.php");
|
||||
require_once("classes/NBT.class.php");
|
||||
require_once("classes/Java.class.php");
|
||||
|
@ -26,6 +26,24 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
|
||||
|
||||
function kill($pid){
|
||||
switch(Utils::getOS()){
|
||||
case "win":
|
||||
ob_start();
|
||||
passthru("%WINDIR%\\System32\\taskkill.exe /F /PID ".((int) $pid));
|
||||
ob_end_clean();
|
||||
break;
|
||||
case "mac":
|
||||
case "linux":
|
||||
default:
|
||||
ob_start();
|
||||
passthru("kill -9 ".((int) $pid));
|
||||
ob_end_clean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function require_all($path, &$count = 0){
|
||||
$dir = dir($path."/");
|
||||
while(false !== ($file = $dir->read())){
|
||||
@ -169,10 +187,10 @@ function logg($message, $name, $EOL = true, $level = 2, $close = false){
|
||||
if(!isset($fpointers)){
|
||||
$fpointers = array();
|
||||
}
|
||||
if(!isset($fpointers[$name])){
|
||||
$fpointers[$name] = fopen(FILE_PATH."logs/".$name.".log", "ab");
|
||||
if(!isset($fpointers[$name]) or $fpointers[$name] === false){
|
||||
$fpointers[$name] = @fopen(FILE_PATH."logs/".$name.".log", "ab");
|
||||
}
|
||||
fwrite($fpointers[$name], $message);
|
||||
@fwrite($fpointers[$name], $message);
|
||||
if($close === true){
|
||||
fclose($fpointers[$name]);
|
||||
unset($fpointers[$name]);
|
||||
|
31
src/misc/BlockIterator.php
Normal file
31
src/misc/BlockIterator.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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 BlockIterator implements Iterator{
|
||||
|
||||
|
||||
}*/
|
110
src/misc/math/Vector2.php
Normal file
110
src/misc/math/Vector2.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?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 Vector2{
|
||||
public $x, $y;
|
||||
|
||||
public function __construct($x = 0, $y = 0){
|
||||
if(($x instanceof Vector2) === true){
|
||||
$this->__construct($x->x, $x->y);
|
||||
}else{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
}
|
||||
|
||||
public function getX(){
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
public function getY(){
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
public function getFloorX(){
|
||||
return (int) $this->x;
|
||||
}
|
||||
|
||||
public function getFloorY(){
|
||||
return (int) $this->y;
|
||||
}
|
||||
|
||||
public function add($x = 0, $y = 0){
|
||||
if(($x instanceof Vector2) === true){
|
||||
return $this->add($x->x, $x->y);
|
||||
}else{
|
||||
$this->x += $x;
|
||||
$this->y += $y;
|
||||
return new Vector3($this->x + $x, $this->y + $y);
|
||||
}
|
||||
}
|
||||
|
||||
public function subtract($x = 0, $y = 0){
|
||||
if(($x instanceof Vector2) === true){
|
||||
return $this->add(-$x->x, -$x->y);
|
||||
}else{
|
||||
return $this->add(-$x, -$y);
|
||||
}
|
||||
}
|
||||
|
||||
public function ceil(){
|
||||
return new Vector2((int) ($this->x + 1), (int) ($this->y + 1));
|
||||
}
|
||||
|
||||
public function floor(){
|
||||
return new Vector2((int) $this->x, (int) $this->y);
|
||||
}
|
||||
|
||||
public function round(){
|
||||
return new Vector2(round($this->x), round($this->y));
|
||||
}
|
||||
|
||||
public function abs(){
|
||||
return new Vector2(abs($this->x), abs($this->y));
|
||||
}
|
||||
|
||||
public function distance($x = 0, $y = 0){
|
||||
if(($x instanceof Vector2) === true){
|
||||
return sqrt($this->distanceSquared($x->x, $x->y));
|
||||
}else{
|
||||
return sqrt($this->distanceSquared($x, $y));
|
||||
}
|
||||
}
|
||||
|
||||
public function distanceSquared($x = 0, $y = 0){
|
||||
if(($x instanceof Vector2) === true){
|
||||
return $this->distanceSquared($x->x, $x->y);
|
||||
}else{
|
||||
return pow($this->x - $x, 2) + pow($this->y - $y, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return "Vector2(x=".$this->x.",y=".$this->y.")";
|
||||
}
|
||||
|
||||
}
|
140
src/misc/math/Vector3.php
Normal file
140
src/misc/math/Vector3.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?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 Vector3{
|
||||
public $x, $y, $z;
|
||||
|
||||
public function __construct($x = 0, $y = 0, $z = 0){
|
||||
if(($x instanceof Vector3) === true){
|
||||
$this->__construct($x->x, $x->y, $x->z);
|
||||
}else{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
$this->z = $z;
|
||||
}
|
||||
}
|
||||
|
||||
public function getX(){
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
public function getY(){
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
public function getZ(){
|
||||
return $this->z;
|
||||
}
|
||||
|
||||
public function getFloorX(){
|
||||
return (int) $this->x;
|
||||
}
|
||||
|
||||
public function getFloorY(){
|
||||
return (int) $this->y;
|
||||
}
|
||||
|
||||
public function getFloorZ(){
|
||||
return (int) $this->z;
|
||||
}
|
||||
|
||||
public function getRight(){
|
||||
return $this->getX();
|
||||
}
|
||||
|
||||
public function getUp(){
|
||||
return $this->getY();
|
||||
}
|
||||
|
||||
public function getForward(){
|
||||
return $this->getZ();
|
||||
}
|
||||
|
||||
public function getSouth(){
|
||||
return $this->getX();
|
||||
}
|
||||
|
||||
public function getWest(){
|
||||
return $this->getZ();
|
||||
}
|
||||
|
||||
public function add($x = 0, $y = 0, $z = 0){
|
||||
if(($x instanceof Vector3) === true){
|
||||
return $this->add($x->x, $x->y, $x->z);
|
||||
}else{
|
||||
$this->x += $x;
|
||||
$this->y += $y;
|
||||
$this->z += $z;
|
||||
return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
|
||||
}
|
||||
}
|
||||
|
||||
public function subtract($x = 0, $y = 0, $z = 0){
|
||||
if(($x instanceof Vector3) === true){
|
||||
return $this->add(-$x->x, -$x->y, -$x->z);
|
||||
}else{
|
||||
return $this->add(-$x, -$y, -$z);
|
||||
}
|
||||
}
|
||||
|
||||
public function ceil(){
|
||||
return new Vector3((int) ($this->x + 1), (int) ($this->y + 1), (int) ($this->z + 1));
|
||||
}
|
||||
|
||||
public function floor(){
|
||||
return new Vector3((int) $this->x, (int) $this->y, (int) $this->z);
|
||||
}
|
||||
|
||||
public function round(){
|
||||
return new Vector3(round($this->x), round($this->y), round($this->z));
|
||||
}
|
||||
|
||||
public function abs(){
|
||||
return new Vector3(abs($this->x), abs($this->y), abs($this->z));
|
||||
}
|
||||
|
||||
public function distance($x = 0, $y = 0, $z = 0){
|
||||
if(($x instanceof Vector3) === true){
|
||||
return sqrt($this->distanceSquared($x->x, $x->y, $x->z));
|
||||
}else{
|
||||
return sqrt($this->distanceSquared($x, $y, $z));
|
||||
}
|
||||
}
|
||||
|
||||
public function distanceSquared($x = 0, $y = 0, $z = 0){
|
||||
if(($x instanceof Vector3) === true){
|
||||
return $this->distanceSquared($x->x, $x->y, $x->z);
|
||||
}else{
|
||||
return pow($this->x - $x, 2) + pow($this->y - $y, 2) + pow($this->z - $z, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return "Vector3(x=".$this->x.",y=".$this->y.",z=".$this->z.")";
|
||||
}
|
||||
|
||||
}
|
96
src/misc/utils/VersionString.php
Normal file
96
src/misc/utils/VersionString.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?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 VersionString{
|
||||
public static $stageOrder = array(
|
||||
"alpha" => 0,
|
||||
"beta" => 1,
|
||||
"final" => 2,
|
||||
);
|
||||
private $stage, $major, $release, $minor;
|
||||
public function __construct($version = MAJOR_VERSION){
|
||||
if(is_int($version)){
|
||||
$this->minor = $version & 0x1F;
|
||||
$this->major = ($version >> 5) & 0x0F;
|
||||
$this->generation = ($version >> 9) & 0x0F;
|
||||
$this->stage = array_search(($version >> 13) & 0x0F, VersionString::$stageOrder, true);
|
||||
}else{
|
||||
$version = preg_split("/([A-Za-z]*)[ _\-]([0-9]*)\.([0-9]*)\.{0,1}([0-9]*)/", $version, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$this->stage = strtolower($version[1]); //0-15
|
||||
$this->generation = (int) $version[2]; //0-15
|
||||
$this->major = (int) $version[3]; //0-15
|
||||
$this->minor = (int) $version[4]; //0-31
|
||||
}
|
||||
}
|
||||
|
||||
public function getNumber(){
|
||||
return (int) (VersionString::$stageOrder[$this->stage] << 13) + ($this->generation << 9) + ($this->major << 5) + $this->minor;
|
||||
}
|
||||
|
||||
public function getStage(){
|
||||
return $this->stage;
|
||||
}
|
||||
|
||||
public function getGeneration(){
|
||||
return $this->generation;
|
||||
}
|
||||
|
||||
public function getMajor(){
|
||||
return $this->major;
|
||||
}
|
||||
|
||||
public function getMinor(){
|
||||
return $this->minor;
|
||||
}
|
||||
|
||||
public function getRelease(){
|
||||
return $this->generation . "." . $this->major . "." . $this->minor;
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return ucfirst($this->stage) . "_" . $this->generation . "." . $this->major . "." . $this->minor;
|
||||
}
|
||||
|
||||
public function compare($target, $diff = false){
|
||||
if(($target instanceof VersionString) === false){
|
||||
$target = new VersionString($target);
|
||||
}
|
||||
$number = $this->getNumber();
|
||||
$tNumber = $target->getNumber();
|
||||
if($diff === true){
|
||||
return $tNumber - $number;
|
||||
}
|
||||
if($number > $tNumber){
|
||||
return -1; //Target is older
|
||||
}elseif($number < $tNumber){
|
||||
return 1; //Target is newer
|
||||
}else{
|
||||
return 0; //Same version
|
||||
}
|
||||
}
|
||||
}
|
89
src/misc/world/generator/object/tree/BigTreeObject.php
Normal file
89
src/misc/world/generator/object/tree/BigTreeObject.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
require_once("misc/world/generator/object/tree/TreeObject.php");
|
||||
|
||||
class BigTreeObject extends TreeObject{
|
||||
private $trunkHeightMultiplier = 0.618;
|
||||
private $trunkHeight;
|
||||
private $leafAmount = 1;
|
||||
private $leafDistanceLimit = 5;
|
||||
private $widthScale = 1;
|
||||
private $branchSlope = 0.381;
|
||||
|
||||
private $totalHeight = 6;
|
||||
private $leavesHeight = 3;
|
||||
protected $radiusIncrease = 0;
|
||||
private $addLeavesVines = false;
|
||||
private $addLogVines = false;
|
||||
private $addCocoaPlants = false;
|
||||
|
||||
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function placeObject(LevelAPI $level, $x, $y, $z, $type){
|
||||
|
||||
$this->trunkHeight = (int) ($this->totalHeight * $this->trunkHeightMultiplier);
|
||||
$leaves = $this->getLeafGroupPoints($level, $x, $y, $z);
|
||||
foreach($leaves as $leafGroup){
|
||||
$groupX = $leafGroup->getBlockX();
|
||||
$groupY = $leafGrou->getBlockY();
|
||||
$groupZ = $leafGroup->getBlockZ();
|
||||
for ($yy = $groupY; $yy < $groupY + $this->leafDistanceLimit; ++$yy) {
|
||||
$this->generateGroupLayer($level, $groupX, $yy, $groupZ, $this->getLeafGroupLayerSize($yy - $groupY));
|
||||
}
|
||||
}
|
||||
/*final BlockIterator trunk = new BlockIterator(new Point(w, x, y - 1, z), new Point(w, x, y + trunkHeight, z));
|
||||
while (trunk.hasNext()) {
|
||||
trunk.next().setMaterial(VanillaMaterials.LOG, logMetadata);
|
||||
}
|
||||
generateBranches(w, x, y, z, leaves);
|
||||
|
||||
$level->setBlock($x, $y - 1, $z, 3, 0);
|
||||
$this->totalHeight += mt_rand(-1, 3);
|
||||
$this->leavesHeight += mt_rand(0, 1);
|
||||
for($yy = ($this->totalHeight - $this->leavesHeight); $yy < ($this->totalHeight + 1); ++$yy){
|
||||
$yRadius = ($yy - $this->totalHeight);
|
||||
$xzRadius = (int) (($this->radiusIncrease + 1) - $yRadius / 2);
|
||||
for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){
|
||||
for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){
|
||||
if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){
|
||||
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
|
||||
$level->setBlock($x, $y + $yy, $z, 17, $type);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
}
|
97
src/misc/world/generator/object/tree/PineTreeObject.php
Normal file
97
src/misc/world/generator/object/tree/PineTreeObject.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
require_once("misc/world/generator/object/tree/TreeObject.php");
|
||||
|
||||
class PineTreeObject extends TreeObject{
|
||||
var $type = 1;
|
||||
private $totalHeight = 8;
|
||||
private $leavesSizeY = -1;
|
||||
private $leavesAbsoluteMaxRadius = -1;
|
||||
|
||||
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
|
||||
$this->findRandomLeavesSize();
|
||||
$checkRadius = 0;
|
||||
for($yy = 0; $yy < ($this->totalHeight + 2); ++$yy) {
|
||||
if($yy === $this->leavesSizeY) {
|
||||
$checkRadius = $this->leavesAbsoluteMaxRadius;
|
||||
}
|
||||
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
|
||||
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
|
||||
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
|
||||
if(!isset($this->overridable[$block[0]])){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function findRandomLeavesSize(){
|
||||
$this->totalHeight += mt_rand(-1, 2);
|
||||
$this->leavesSizeY = 1 + mt_rand(0,2);
|
||||
$this->leavesAbsoluteMaxRadius = 2 + mt_rand(0, 2);
|
||||
}
|
||||
|
||||
public function placeObject(LevelAPI $level, $x, $y, $z){
|
||||
if($this->leavesSizeY === -1 or $this->leavesAbsoluteMaxRadius === -1) {
|
||||
$this->findRandomLeavesSize();
|
||||
}
|
||||
$level->setBlock($x, $y - 1, $z, 3, 0);
|
||||
$leavesRadius = mt_rand(0,2);
|
||||
$leavesMaxRadius = 1;
|
||||
$leavesBottomY = $this->totalHeight - $this->leavesSizeY;
|
||||
$firstMaxedRadius = false;
|
||||
for($leavesY = 0; $leavesY < ($leavesBottomY + 1); ++$leavesY) {
|
||||
$yy = $this->totalHeight - $leavesY;
|
||||
for ($xx = -$leavesRadius; $xx < ($leavesRadius + 1); ++$xx) {
|
||||
for ($zz = -$leavesRadius; $zz < ($leavesRadius + 1); ++$zz) {
|
||||
if (abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0) {
|
||||
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($leavesRadius >= $leavesMaxRadius) {
|
||||
$leavesRadius = $firstMaxedRadius ? 1 : 0;
|
||||
$firstMaxedRadius = true;
|
||||
if (++$leavesMaxRadius > $this->leavesAbsoluteMaxRadius) {
|
||||
$leavesMaxRadius = $this->leavesAbsoluteMaxRadius;
|
||||
}
|
||||
}else{
|
||||
++$leavesRadius;
|
||||
}
|
||||
}
|
||||
$trunkHeightReducer = mt_rand(0,3);
|
||||
for($yy = 0; $yy < ($this->totalHeight - $trunkHeightReducer); ++$yy){
|
||||
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -29,6 +29,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
require_once("misc/world/generator/object/tree/TreeObject.php");
|
||||
|
||||
class SmallTreeObject extends TreeObject{
|
||||
var $type = 0;
|
||||
private $totalHeight = 6;
|
||||
private $leavesHeight = 3;
|
||||
protected $radiusIncrease = 0;
|
||||
@ -36,7 +37,25 @@ class SmallTreeObject extends TreeObject{
|
||||
private $addLogVines = false;
|
||||
private $addCocoaPlants = false;
|
||||
|
||||
public function placeObject(LevelAPI $level, $x, $y, $z, $type){
|
||||
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
|
||||
$radiusToCheck = $this->radiusIncrease;
|
||||
for ($yy = 0; $yy < $this->totalHeight + 2; ++$yy) {
|
||||
if ($yy == 1 or $yy === $this->totalHeight - 1) {
|
||||
++$radiusToCheck;
|
||||
}
|
||||
for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){
|
||||
for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){
|
||||
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
|
||||
if(!isset($this->overridable[$block[0]])){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function placeObject(LevelAPI $level, $x, $y, $z){
|
||||
$level->setBlock($x, $y - 1, $z, 3, 0);
|
||||
$this->totalHeight += mt_rand(-1, 3);
|
||||
$this->leavesHeight += mt_rand(0, 1);
|
||||
@ -46,13 +65,13 @@ class SmallTreeObject extends TreeObject{
|
||||
for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){
|
||||
for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){
|
||||
if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){
|
||||
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $type);
|
||||
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
|
||||
$level->setBlock($x, $y + $yy, $z, 17, $type);
|
||||
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
88
src/misc/world/generator/object/tree/SpruceTreeObject.php
Normal file
88
src/misc/world/generator/object/tree/SpruceTreeObject.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
require_once("misc/world/generator/object/tree/TreeObject.php");
|
||||
|
||||
class SpruceTreeObject extends TreeObject{
|
||||
var $type = 1;
|
||||
private $totalHeight = 8;
|
||||
private $leavesBottomY = -1;
|
||||
private $leavesMaxRadius = -1;
|
||||
|
||||
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
|
||||
$this->findRandomLeavesSize();
|
||||
$checkRadius = 0;
|
||||
for($yy = 0; $yy < $this->totalHeight + 2; ++$yy) {
|
||||
if($yy === $this->leavesBottomY) {
|
||||
$checkRadius = $this->leavesMaxRadius;
|
||||
}
|
||||
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
|
||||
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
|
||||
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
|
||||
if(!isset($this->overridable[$block[0]])){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function findRandomLeavesSize(){
|
||||
$this->totalHeight += mt_rand(-1, 2);
|
||||
$this->leavesBottomY = (int) ($this->totalHeight - mt_rand(1,2) - 3);
|
||||
$this->leavesMaxRadius = 1 + mt_rand(0, 1);
|
||||
}
|
||||
|
||||
public function placeObject(LevelAPI $level, $x, $y, $z){
|
||||
if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1) {
|
||||
$this->findRandomLeavesSize();
|
||||
}
|
||||
$level->setBlock($x, $y - 1, $z, 3, 0);
|
||||
$leavesRadius = 0;
|
||||
for($yy = $this->totalHeight; $yy >= $this->leavesBottomY; --$yy){
|
||||
for ($xx = -$leavesRadius; $xx < ($leavesRadius + 1); ++$xx) {
|
||||
for ($zz = -$leavesRadius; $zz < ($leavesRadius + 1); ++$zz) {
|
||||
if (abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0) {
|
||||
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($leavesRadius > 0 and $yy === ($y + $this->leavesBottomY + 1)) {
|
||||
--$leavesRadius;
|
||||
}elseif($leavesRadius < $this->leavesMaxRadius){
|
||||
++$leavesRadius;
|
||||
}
|
||||
}
|
||||
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
|
||||
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -27,14 +27,36 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
|
||||
class TreeObject{
|
||||
|
||||
var $overridable = array(
|
||||
0 => true,
|
||||
6 => true,
|
||||
17 => true,
|
||||
18 => true,
|
||||
);
|
||||
public static function growTree(LevelAPI $level, $block, $type){
|
||||
switch($type){
|
||||
case Sapling::SPRUCE:
|
||||
if(mt_rand(0,1) == 2){
|
||||
$tree = new SpruceTreeObject();
|
||||
}else{
|
||||
$tree = new PineTreeObject();
|
||||
}
|
||||
break;
|
||||
case Sapling::BIRCH:
|
||||
$tree = new SmallTreeObject();
|
||||
$tree->type = Sapling::BIRCH;
|
||||
break;
|
||||
default:
|
||||
case Sapling::OAK:
|
||||
$tree = new SmallTreeObject();
|
||||
if(mt_rand(0,9) === 0){
|
||||
$tree = new BigTreeObject();
|
||||
}else{
|
||||
$tree = new SmallTreeObject();
|
||||
}
|
||||
break;
|
||||
}
|
||||
$tree->placeObject($level, $block[2][0], $block[2][1], $block[2][2], $type);
|
||||
if($tree->canPlaceObject($level, $block[2][0], $block[2][1], $block[2][2])){
|
||||
$tree->placeObject($level, $block[2][0], $block[2][1], $block[2][2]);
|
||||
}
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ $dataName = array(
|
||||
MC_ADD_ENTITY => "AddEntity",
|
||||
MC_REMOVE_ENTITY => "RemoveEntity",
|
||||
MC_ADD_ITEM_ENTITY => "AddItemEntity",
|
||||
MC_TAKE_ITEM_ENTITY => "TakeItemEntity",
|
||||
|
||||
MC_MOVE_ENTITY => "MoveEntity",
|
||||
|
||||
@ -74,6 +75,11 @@ $dataName = array(
|
||||
MC_ANIMATE => "Animate",
|
||||
MC_RESPAWN => "Respawn",
|
||||
|
||||
MC_DROP_ITEM => "DropItem",
|
||||
MC_CONTAINER_OPEN => "ContainerOpen",
|
||||
MC_CONTAINER_CLOSE => "ContainerClose",
|
||||
MC_CONTAINER_SET_SLOT => "ContainerSetSlot",
|
||||
|
||||
MC_CLIENT_MESSAGE => "ClientMessage",
|
||||
MC_SIGN_UPDATE => "SignUpdate",
|
||||
MC_ADVENTURE_SETTINGS => "AdventureSettings",
|
||||
|
@ -50,6 +50,7 @@ define("MC_ADD_PLAYER", 0x89);
|
||||
define("MC_ADD_ENTITY", 0x8c);
|
||||
define("MC_REMOVE_ENTITY", 0x8d);
|
||||
define("MC_ADD_ITEM_ENTITY", 0x8e);
|
||||
define("MC_TAKE_ITEM_ENTITY", 0x8f);
|
||||
|
||||
define("MC_MOVE_ENTITY", 0x90);
|
||||
|
||||
@ -74,6 +75,11 @@ define("MC_SET_SPAWN_POSITION", 0xa6);
|
||||
define("MC_ANIMATE", 0xa7);
|
||||
define("MC_RESPAWN", 0xa8);
|
||||
|
||||
define("MC_DROP_ITEM", 0xaa);
|
||||
define("MC_CONTAINER_OPEN", 0xab);
|
||||
define("MC_CONTAINER_CLOSE", 0xac);
|
||||
define("MC_CONTAINER_SET_SLOT", 0xad);
|
||||
|
||||
define("MC_CLIENT_MESSAGE", 0xb1);
|
||||
define("MC_SIGN_UPDATE", 0xb2);
|
||||
define("MC_ADVENTURE_SETTINGS", 0xb3);
|
@ -26,7 +26,6 @@ if not "%PHPOUTPUT%"=="1" (
|
||||
echo [ERROR] Couldn't find PHP binary in PATH.
|
||||
ping 127.0.0.1 -n 3 -w 1000>nul
|
||||
) else (
|
||||
START /B CMD /C CALL php PocketMine-MP.php
|
||||
START /B /WAIT php src/common/input.php 1
|
||||
ping 127.0.0.1 -n 5 -w 1000>nul
|
||||
START /B /WAIT php -d enable_dl=On PocketMine-MP.php
|
||||
)
|
||||
pause
|
||||
|
Reference in New Issue
Block a user