mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-13 04:45:08 +00:00
Compare commits
133 Commits
Alpha_1.0.
...
Alpha_1.0.
Author | SHA1 | Date | |
---|---|---|---|
c23081e713 | |||
2ba2116498 | |||
07ac028558 | |||
7e4692aaf1 | |||
baec22208f | |||
62a7461bbd | |||
4df7aed15d | |||
d733eb6b4a | |||
e4d71949e3 | |||
4bda101ab8 | |||
b74c089ce7 | |||
02950474af | |||
b398b9daa2 | |||
b2731261e5 | |||
03c8c91b46 | |||
13f4f3285f | |||
8bc115a2ab | |||
2665dffdd8 | |||
ab2b519c2e | |||
6ab08020c3 | |||
107d71f291 | |||
09c2c1b2ee | |||
f3e9d4df31 | |||
d86bf37def | |||
5753db627c | |||
6102efc809 | |||
8d3ad0c5ec | |||
eebbc263b0 | |||
d5d319fb7c | |||
03db7c8738 | |||
2801f18753 | |||
b9b0039cd7 | |||
cd3aaa1b50 | |||
902cee1107 | |||
ab5481a392 | |||
f11bc82b86 | |||
0cd8479026 | |||
90d9099b3c | |||
47e80151e6 | |||
19aa4bd527 | |||
a6ddba8d97 | |||
3a110bf8b6 | |||
18bab3b045 | |||
89c0702a47 | |||
21594d699d | |||
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 | |||
000a0dedd9 | |||
5df48f3b7c | |||
4c34cdaa61 | |||
c959e14718 | |||
470352cd31 | |||
ca54acd09b | |||
8a0c5e4655 | |||
b5c191530a | |||
8abc36acd4 | |||
0b683c6b0e | |||
0c498e96a3 | |||
2034dbfb15 | |||
3409f873be | |||
aefa34187b | |||
2d9b701847 | |||
78c2a06623 | |||
4d3ef98f1f | |||
ca12a5c2ce | |||
ada2662627 |
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
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,11 +1,11 @@
|
||||
data/players/*
|
||||
data/maps/*
|
||||
data/plugins/*
|
||||
players/*
|
||||
worlds/*
|
||||
plugins/*
|
||||
logs/*
|
||||
*.log
|
||||
server.properties
|
||||
white-list.txt
|
||||
banned-ips.txt
|
||||
console.in
|
||||
|
||||
#################
|
||||
## Eclipse
|
||||
|
@ -25,17 +25,12 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
//Protocol Version: 4
|
||||
require_once(dirname(__FILE__)."/src/common/dependencies.php");
|
||||
require_once("classes/PocketMinecraftServer.class.php");
|
||||
require_once("API/ServerAPI.php");
|
||||
|
||||
$server = new ServerAPI();
|
||||
$server->run();//$server->start();
|
||||
//$server->join();
|
||||
|
||||
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);
|
||||
kill(getmypid()); //Fix for segfault
|
94
README.md
94
README.md
@ -1,65 +1,59 @@
|
||||
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.
|
||||
```
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
```
|
||||
|
||||
# PocketMine-MP
|
||||
|
||||
PocketMine-MP is a Server for Minecraft Pocket Edition done in PHP. It has a Plugin API that enables a developer to extend it and add new features, or change default ones.
|
||||
|
||||
The entire server is done in PHP, and has been tested, profiled and optimized to run smoothly.
|
||||
|
||||
[Go to Wiki for more information](https://github.com/shoghicp/PocketMine-MP/wiki)
|
||||
|
||||
[FAQ: Frequently Asked Questions](https://github.com/shoghicp/PocketMine-MP/wiki/Frequently-Asked-Questions)
|
||||
|
||||
|
||||
PocketMine-MP
|
||||
=============
|
||||
Github repo: https://github.com/shoghicp/PocketMine-MP
|
||||
## Current features of the server:
|
||||
|
||||
Server (and client) Minecraft Pocket Edition library written in PHP.
|
||||
Currently a work in progress, and used to document http://www.wiki.vg/Pocket_Minecraft_Protocol
|
||||
|
||||
Check the wiki! https://github.com/shoghicp/PocketMine-MP/wiki
|
||||
|
||||
**Project Status: `ALPHA`**
|
||||
|
||||
**Tested in: `v4.0.0, v5.0.0`**
|
||||
|
||||
|
||||
Current features of the server:
|
||||
-------------------------------
|
||||
* Full Creative mode!
|
||||
* Plugin API
|
||||
* Custom world generation
|
||||
* 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 NBT](https://github.com/TheFrozenFire/PHP-NBT-Decoder-Encoder/blob/master/nbt.class.php)__ by [TheFrozenFire](https://github.com/TheFrozenFire): Class for reading in NBT-format files
|
||||
## Third-party Libraries Used
|
||||
* __[PHP cURL](http://php.net/manual/en/book.curl.php)__
|
||||
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
|
||||
* __[PHP SQLite3](http://php.net/manual/en/book.sqlite3.php)__
|
||||
* __[PHP pthreads](https://github.com/krakjoe/pthreads)__ by _[krakjoe](https://github.com/krakjoe)_: Threading for PHP - Share Nothing, Do Everything
|
||||
* __[PHP NBT](https://github.com/TheFrozenFire/PHP-NBT-Decoder-Encoder/blob/master/nbt.class.php)__ by _[TheFrozenFire](https://github.com/TheFrozenFire)_: Class for reading in NBT-format files (modified to handle Little-Endian files)
|
||||
* __[Math_BigInteger](http://phpseclib.sourceforge.net/math/intro.html)__ by _[phpseclib](http://phpseclib.sourceforge.net/)_: Pure-PHP arbitrary precission integer arithmetic library
|
||||
* __[Spyc](https://github.com/mustangostang/spyc/blob/master/Spyc.php)__ by _[Vlad Andersen](https://github.com/mustangostang)_: A simple YAML loader/dumper class for PHP
|
33
TODO.md
33
TODO.md
@ -1,33 +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 (full Creative)
|
||||
* Done!
|
||||
|
||||
### Alpha v1.1
|
||||
|
||||
|
||||
## Beta (Survival)
|
||||
- Random Chunk Updates
|
||||
- Mob spawning, item pick up
|
||||
- Mob behavior
|
||||
- Placing Paintings
|
||||
- Inventory loading and saving
|
||||
- Entity saving
|
||||
- Wheat growth
|
||||
- Melon growth
|
||||
- Sapling growth
|
||||
- Mob interaction (hitting)
|
||||
- Firing Arrows
|
||||
- Eating
|
||||
- Nether???
|
134
compile_php.sh
Normal file
134
compile_php.sh
Normal file
@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
echo "[PocketMine] PHP installer and compiler for Linux - by @shoghicp v0.3"
|
||||
DIR=`pwd`
|
||||
date > $DIR/install.log
|
||||
uname -a >> $DIR/install.log
|
||||
echo "[INFO] Checking dependecies"
|
||||
type make >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"make\""; exit 1; }
|
||||
type autoconf >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"autoconf\""; exit 1; }
|
||||
type automake >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"automake\""; exit 1; }
|
||||
type gcc >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"gcc\""; exit 1; }
|
||||
type m4 >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"m4\""; exit 1; }
|
||||
rm -r -f install_data/ >> $DIR/install.log 2>&1
|
||||
rm -r -f php5/ >> $DIR/install.log 2>&1
|
||||
mkdir -m 0777 install_data >> $DIR/install.log 2>&1
|
||||
mkdir -m 0777 php5 >> $DIR/install.log 2>&1
|
||||
cd install_data
|
||||
|
||||
#PHP 5
|
||||
echo -n "[PHP5] downloading..."
|
||||
wget http://php.net/get/php-5.4.10.tar.gz/from/this/mirror -O php-5.4.10.tar.gz >> $DIR/install.log 2>&1
|
||||
echo -n " extracting..."
|
||||
tar -zxvf php-5.4.10.tar.gz >> $DIR/install.log 2>&1
|
||||
rm -f php-5.4.10.tar.gz >> $DIR/install.log 2>&1
|
||||
mv php-5.4.10 php
|
||||
echo " done!"
|
||||
|
||||
#zlib
|
||||
echo -n "[zlib] downloading..."
|
||||
wget http://zlib.net/zlib-1.2.7.tar.gz -O zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
|
||||
echo -n " extracting..."
|
||||
tar -zxvf zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
|
||||
rm -f zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
|
||||
mv zlib-1.2.7 zlib
|
||||
echo -n " compiling..."
|
||||
cd zlib
|
||||
./configure --prefix=$DIR/install_data/php/ext/zlib >> $DIR/install.log 2>&1
|
||||
make >> $DIR/install.log 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> $DIR/install.log 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./zlib
|
||||
echo " done!"
|
||||
|
||||
#OpenSSL
|
||||
#echo -n "[OpenSSL] downloading..."
|
||||
#wget ftp://ftp.openssl.org/source/openssl-1.0.1c.tar.gz -O openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
|
||||
#echo -n " extracting..."
|
||||
#tar -zxvf openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
|
||||
#rm -f openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
|
||||
#mv openssl-1.0.1c openssl
|
||||
#echo -n " compiling..."
|
||||
#cd openssl
|
||||
#./config --prefix=$DIR/install_data/php/ext/openssl >> $DIR/install.log 2>&1
|
||||
#make >> $DIR/install.log 2>&1
|
||||
#echo -n " installing..."
|
||||
#make install >> $DIR/install.log 2>&1
|
||||
#echo -n " cleaning..."
|
||||
#cd ..
|
||||
#rm -r -f ./openssl
|
||||
#echo " done!"
|
||||
|
||||
#GMP
|
||||
echo -n "[GMP] downloading..."
|
||||
wget ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.0.tar.bz2 -O gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
|
||||
echo -n " extracting..."
|
||||
tar -jxvf gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
|
||||
rm -f gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
|
||||
mv gmp-5.1.0 gmp
|
||||
echo -n " compiling..."
|
||||
cd gmp
|
||||
./configure --prefix=$DIR/install_data/php/ext/gmp >> $DIR/install.log 2>&1
|
||||
make >> $DIR/install.log 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> $DIR/install.log 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./gmp
|
||||
echo " done!"
|
||||
|
||||
echo -n "[cURL] downloading..."
|
||||
wget https://github.com/bagder/curl/archive/master.tar.gz --no-check-certificate -O curl-master.tar.gz >> $DIR/install.log 2>&1
|
||||
echo -n " extracting..."
|
||||
tar -zxvf curl-master.tar.gz >> $DIR/install.log 2>&1
|
||||
rm -f curl-master.tar.gz >> $DIR/install.log 2>&1
|
||||
mv curl-master curl
|
||||
echo -n " compiling..."
|
||||
cd curl
|
||||
./buildconf >> $DIR/install.log 2>&1
|
||||
./configure --prefix=$DIR/install_data/php/ext/curl >> $DIR/install.log 2>&1
|
||||
make >> $DIR/install.log 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> $DIR/install.log 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./curl
|
||||
echo " done!"
|
||||
|
||||
#pthreads
|
||||
echo -n "[PHP pthreads] downloading..."
|
||||
wget https://github.com/krakjoe/pthreads/archive/master.tar.gz --no-check-certificate -O pthreads-master.tar.gz >> $DIR/install.log 2>&1
|
||||
echo -n " extracting..."
|
||||
tar -zxvf pthreads-master.tar.gz >> $DIR/install.log 2>&1
|
||||
rm -f pthreads-master.tar.gz >> $DIR/install.log 2>&1
|
||||
mv pthreads-master $DIR/install_data/php/ext/pthreads
|
||||
echo " done!"
|
||||
|
||||
#--with-openssl=$DIR/install_data/php/ext/openssl
|
||||
echo -n "[PHP5] compiling..."
|
||||
cd php
|
||||
./buildconf --force >> $DIR/install.log 2>&1
|
||||
./configure --prefix=$DIR/php5 \
|
||||
--exec-prefix=$DIR/php5 \
|
||||
--enable-embedded-mysqli \
|
||||
--enable-bcmath \
|
||||
--with-gmp=$DIR/install_data/php/ext/gmp \
|
||||
--with-curl=$DIR/install_data/php/ext/curl \
|
||||
--with-zlib=$DIR/install_data/php/ext/zlib \
|
||||
--disable-xml \
|
||||
--without-pear \
|
||||
--enable-sockets \
|
||||
--enable-pthreads \
|
||||
--enable-maintainer-zts \
|
||||
--enable-cli >> $DIR/install.log 2>&1
|
||||
make >> $DIR/install.log 2>&1
|
||||
make install >> $DIR/install.log 2>&1
|
||||
echo " done!"
|
||||
cd $DIR
|
||||
echo -n "[INFO] Cleaning up..."
|
||||
rm -r -f install_data/ >> $DIR/install.log 2>&1
|
||||
rmdir install_data/ >> $DIR/install.log 2>&1
|
||||
echo " done!"
|
||||
echo "[PocketMine] You should start the server now using \"./start.sh\""
|
||||
echo "[PocketMine] If it doesn't works, please send the \"install.log\" file to the Bug Tracker"
|
@ -1,2 +0,0 @@
|
||||
To import a Pocket Edition Map, drop to the folder "maps"
|
||||
the chunk.dat, level.dat and entities.dat from the savegame file.
|
@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
__PocketMine Plugin__
|
||||
name=ExamplePlugin
|
||||
version=0.0.1
|
||||
author=shoghicp
|
||||
class=ExamplePlugin
|
||||
*/
|
||||
|
||||
|
||||
class ExamplePlugin implements Plugin{
|
||||
private $api;
|
||||
public function __construct(ServerAPI $api, $server = false){
|
||||
$this->api = $api;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->api->console->register("example", "Example command", array($this, "handleCommand"));
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
|
||||
}
|
||||
|
||||
public function handleCommand($cmd, $arg){
|
||||
switch($cmd){
|
||||
case "example":
|
||||
console("EXAMPLE!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
__PocketMine Plugin__
|
||||
name=ReactorAsWater
|
||||
description=Replaces the Nether Reactor with Water
|
||||
version=0.0.2
|
||||
author=shoghicp
|
||||
class=ReactorAsWater
|
||||
*/
|
||||
|
||||
|
||||
class ReactorAsWater implements Plugin{
|
||||
private $api;
|
||||
public function __construct(ServerAPI $api, $server = false){
|
||||
$this->api = $api;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->api->addHandler("player.block.action", array($this, "handle"), 15); //Priority higher that API
|
||||
$this->api->addHandler("player.equipment.change", array($this, "handle"), 15);
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
|
||||
}
|
||||
|
||||
public function handle(&$data, $event){
|
||||
switch($event){
|
||||
case "player.equipment.change":
|
||||
if($data["block"] === 247){
|
||||
$this->api->player->getByEID($data["eid"])->eventHandler("[ReactorAsWater] Placing water", "server.chat");
|
||||
$data["block"] = 9;
|
||||
$data["meta"] = 0;
|
||||
}
|
||||
break;
|
||||
case "player.block.action":
|
||||
if($data["block"] === 247){ //nether reactor
|
||||
$data["block"] = 9; //water source
|
||||
$data["meta"] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
__PocketMine Plugin__
|
||||
name=SpawnChanger
|
||||
description=Change the spawn coordinates, or make it default for all players!
|
||||
version=0.0.1
|
||||
author=shoghicp
|
||||
class=SpawnChanger
|
||||
*/
|
||||
|
||||
|
||||
class SpawnChanger implements Plugin{
|
||||
private $api, $config, $path;
|
||||
public function __construct(ServerAPI $api, $server = false){
|
||||
$this->api = $api;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$spawn = $this->api->level->getSpawn();
|
||||
$this->path = $this->api->plugin->createConfig($this, array(
|
||||
"spawnX" => $spawn["x"],
|
||||
"spawnY" => $spawn["y"],
|
||||
"spawnZ" => $spawn["z"],
|
||||
"custom-spawn" => false,
|
||||
"force-spawn" => false,
|
||||
));
|
||||
$this->config = $this->api->plugin->readYAML($this->path."config.yml");
|
||||
if($this->config["custom-spawn"] === false){
|
||||
$this->config["spawnX"] = $spawn["x"];
|
||||
$this->config["spawnY"] = $spawn["y"];
|
||||
$this->config["spawnZ"] = $spawn["z"];
|
||||
$this->api->plugin->writeYAML($this->path."config.yml", $this->config);
|
||||
}
|
||||
$this->api->addHandler("api.player.offline.get", array($this, "handle"), 15);
|
||||
$this->api->console->register("spawnchanger", "SpawnChanger init point managing", array($this, "command"));
|
||||
$this->api->console->register("spawn", "Teleports to spawn", array($this, "command"));
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
|
||||
}
|
||||
|
||||
public function command($cmd, $args){
|
||||
switch($cmd){
|
||||
case "spawnchanger":
|
||||
switch(strtolower(array_shift($args))){
|
||||
case "force":
|
||||
$l = array_shift($args);
|
||||
if($l != "0" and $l != "1"){
|
||||
console("[SpawnChanger] Usage: /spawnchanger force <1 | 0>");
|
||||
}else{
|
||||
$this->config["force-spawn"] = $l == "0" ? false:true;
|
||||
if($this->config["force-spawn"] === true){
|
||||
console("[SpawnChanger] Forced spawn point");
|
||||
}else{
|
||||
console("[SpawnChanger] Freed pawn point");
|
||||
}
|
||||
$this->api->plugin->writeYAML($this->path."config.yml", $this->config);
|
||||
}
|
||||
break;
|
||||
case "set":
|
||||
$z = array_pop($args);
|
||||
$y = array_pop($args);
|
||||
$x = array_pop($args);
|
||||
if($x === null or $y === null or $z === null){
|
||||
console("[SpawnChanger] Usage: /spawnchanger set <x> <y> <z>");
|
||||
}else{
|
||||
$this->config["custom-spawn"] = true;
|
||||
$this->config["spawnX"] = (float) $x;
|
||||
$this->config["spawnY"] = (float) $y;
|
||||
$this->config["spawnZ"] = (float) $z;
|
||||
console("[SpawnChanger] Spawn point set at X ".$this->config["spawnX"]." Y ".$this->config["spawnY"]." Z ".$this->config["spawnZ"]);
|
||||
$this->api->plugin->writeYAML($this->path."config.yml", $this->config);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console("[SpawnChanger] Always spawn player in spawn point: /spawnchanger force <1 | 0>");
|
||||
console("[SpawnChanger] Set the spawn point: /spawnchanger set <x> <y> <z>");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "spawn":
|
||||
if($this->api->player->tppos(implode(" ", $args), $this->config["spawnX"], $this->config["spawnY"], $this->config["spawnZ"]) !== false){
|
||||
console("[SpawnChanger] Teleported to spawn!");
|
||||
}else{
|
||||
console("[SpawnChanger] Usage: /spawn <player>");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function handle(&$data, $event){
|
||||
switch($event){
|
||||
case "api.player.offline.get":
|
||||
if($this->config["force-spawn"] === true){
|
||||
$data["spawn"]["x"] = $this->config["spawnX"];
|
||||
$data["spawn"]["y"] = $this->config["spawnY"];
|
||||
$data["spawn"]["z"] = $this->config["spawnZ"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
39
server.php
39
server.php
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
require_once("common/dependencies.php");
|
||||
require_once("classes/PocketMinecraftServer.class.php");
|
||||
require_once("classes/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);
|
||||
}
|
||||
}
|
@ -42,6 +42,53 @@ 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->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;
|
||||
}
|
||||
|
||||
public function blockBreak($data, $event){
|
||||
@ -50,7 +97,7 @@ class BlockAPI{
|
||||
}
|
||||
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
if(isset(Material::$unbreakable[$target[0]])){
|
||||
return false;
|
||||
return $this->cancelAction($target);
|
||||
}
|
||||
$drop = array(
|
||||
$target[0], //Block
|
||||
@ -58,12 +105,29 @@ class BlockAPI{
|
||||
1, //Count
|
||||
);
|
||||
switch($target[0]){
|
||||
case 1:
|
||||
$drop[0] = 4;
|
||||
break;
|
||||
case 16:
|
||||
$drop = array(263, 0, 1);
|
||||
break;
|
||||
case 21:
|
||||
$drop = array(351, 4, mt_rand(4, 8));
|
||||
break;
|
||||
case 62:
|
||||
$drop[0] = 61;
|
||||
case 50: //Drop without metadata
|
||||
case 53:
|
||||
case 54:
|
||||
case 61:
|
||||
case 65:
|
||||
case 67:
|
||||
case 96:
|
||||
case 107:
|
||||
case 108:
|
||||
case 109:
|
||||
$drop[1] = 0;
|
||||
break;
|
||||
case 56:
|
||||
$drop = array(264, 0, 1);
|
||||
break;
|
||||
@ -113,27 +177,37 @@ class BlockAPI{
|
||||
2,
|
||||
);
|
||||
break;
|
||||
case 46: //TNT
|
||||
if(($player = $this->server->api->player->getByEID($data["eid"])) !== false){
|
||||
$player->dataPacket(MC_EXPLOSION, array(
|
||||
"x" => $data["x"],
|
||||
"y" => $data["y"],
|
||||
"z" => $data["z"],
|
||||
"radius" => 2,
|
||||
"records" => array(),
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 60:
|
||||
case 2:
|
||||
$drop = array(3, 0, 1);
|
||||
break;
|
||||
case 64: //Door
|
||||
$drop = array(324, 0, 1);
|
||||
case 64: //Wood Door
|
||||
case 71: //Iron Door
|
||||
$drop = array(($target[0] === 64 ? 324:330), 0, 1);
|
||||
if(($target[1] & 0x08) === 0x08){
|
||||
$down = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
|
||||
if($down[0] === 64){
|
||||
if($down[0] === $target[0]){
|
||||
$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"]);
|
||||
if($up[0] === 64){
|
||||
if($up[0] === $target[0]){
|
||||
$data2 = $data;
|
||||
++$data2["y"];
|
||||
$this->server->trigger("player.block.break", $data2);
|
||||
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -142,7 +216,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;
|
||||
}
|
||||
|
||||
@ -158,10 +231,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){
|
||||
@ -172,9 +251,40 @@ 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:
|
||||
$cancelPlace = true;
|
||||
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:
|
||||
$cancelPlace = true;
|
||||
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);
|
||||
@ -186,24 +296,15 @@ 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:
|
||||
case 105:
|
||||
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
|
||||
switch($target[0]){
|
||||
case 59:
|
||||
case 105:
|
||||
$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);
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
}
|
||||
$data["block"] = $target[0];
|
||||
$data["meta"] = 0x07;
|
||||
$this->server->handle("player.block.place", $data);
|
||||
$cancelPlace = true;
|
||||
}
|
||||
break;
|
||||
@ -220,22 +321,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;
|
||||
@ -243,8 +345,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:
|
||||
@ -282,25 +383,33 @@ class BlockAPI{
|
||||
$block = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
|
||||
if($replace === false and !isset(Material::$replaceable[$block[0]])){
|
||||
return false;
|
||||
return $this->cancelAction($block);
|
||||
}
|
||||
|
||||
if(isset(Material::$placeable[$data["block"]])){
|
||||
$data["block"] = Material::$placeable[$data["block"]] === true ? $data["block"]:Material::$placeable[$data["block"]];
|
||||
}else{
|
||||
return false;
|
||||
return $this->cancelAction($block);
|
||||
}
|
||||
$entity = $this->server->api->entity->get($data["eid"]);
|
||||
if(($entity instanceof Entity) !== true){
|
||||
return $this->cancelAction($block); //No Entity WTF?
|
||||
}
|
||||
|
||||
$direction = $this->server->api->entity->get($data["eid"])->getDirection();
|
||||
if($entity->inBlock($block[2][0], $block[2][1], $block[2][2])){
|
||||
return $this->cancelAction($block); //Entity in block
|
||||
}
|
||||
|
||||
$direction = $entity->getDirection();
|
||||
|
||||
switch($data["block"]){
|
||||
case 6:
|
||||
if($target[0] === 60){
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
@ -379,6 +488,10 @@ class BlockAPI{
|
||||
$data["meta"] = $faces[$direction] & 0x03;
|
||||
break;
|
||||
case 64://Door placing
|
||||
case 71:
|
||||
if($data["face"] !== 1){
|
||||
return false;
|
||||
}
|
||||
$blockUp = $this->server->api->level->getBlock($data["x"], $data["y"] + 1, $data["z"]);
|
||||
$blockDown = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
|
||||
if(!isset(Material::$replaceable[$blockUp[0]]) or isset(Material::$transparent[$blockDown[0]])){
|
||||
@ -387,9 +500,18 @@ class BlockAPI{
|
||||
$data2 = $data;
|
||||
$data2["meta"] = 0x08;
|
||||
$data["meta"] = $direction & 0x03;
|
||||
$face = array(
|
||||
0 => 3,
|
||||
1 => 4,
|
||||
2 => 2,
|
||||
3 => 5,
|
||||
);
|
||||
$next = $this->server->api->level->getBlockFace($block, $face[(($direction + 2) % 4)]);
|
||||
if($next[0] === $data["block"]){ //Door hinge
|
||||
$data2["meta"] = $data2["meta"] | 0x01;
|
||||
}
|
||||
++$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:
|
||||
@ -419,8 +541,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]])){
|
||||
@ -456,9 +577,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;
|
||||
}
|
||||
|
||||
@ -467,7 +586,7 @@ class BlockAPI{
|
||||
}
|
||||
|
||||
public function updateBlockRemote($data, $event){
|
||||
if($event !== "world.block.update"){
|
||||
if($event !== "block.update"){
|
||||
return;
|
||||
}
|
||||
$this->updateBlock($data["x"], $data["y"], $data["z"], isset($data["type"]) ? $data["type"]:BLOCK_UPDATE_RANDOM);
|
||||
@ -493,7 +612,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]])){
|
||||
@ -503,10 +622,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;
|
||||
@ -532,7 +651,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]])){
|
||||
@ -542,10 +661,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;
|
||||
@ -624,7 +743,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(
|
||||
@ -663,7 +782,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -736,7 +855,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(
|
||||
@ -775,7 +894,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -784,14 +903,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,
|
51
src/API/ChatAPI.php
Normal file
51
src/API/ChatAPI.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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 ChatAPI{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
|
||||
}
|
||||
|
||||
public function broadcast($message){
|
||||
$this->send(false, $message);
|
||||
}
|
||||
|
||||
public function send($owner, $text, $whitelist = false, $blacklist = false){
|
||||
$message = "";
|
||||
if($owner !== false){
|
||||
$message = "<".$owner."> ";
|
||||
}
|
||||
$message .= $text;
|
||||
console("[CHAT] ".$message);
|
||||
$this->server->handle("server.chat", new Container($message, $whitelist, $blacklist));
|
||||
}
|
||||
}
|
@ -26,25 +26,34 @@ 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."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){
|
||||
switch($cmd){
|
||||
case "crash": //Crashes the server to generate an report
|
||||
$this->callNotDefinedMethodCrash();
|
||||
$this->server->api->server; //Access a private property
|
||||
callNotExistingFunction();
|
||||
break;
|
||||
case "invisible":
|
||||
$p = strtolower(array_shift($params));
|
||||
switch($p){
|
||||
@ -74,6 +83,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;
|
||||
@ -142,7 +152,7 @@ class ConsoleAPI{
|
||||
console("[INFO] Usage: /say <message>");
|
||||
break;
|
||||
}
|
||||
$this->server->chat(false, $s);
|
||||
$this->server->api->chat->broadcast($s);
|
||||
break;
|
||||
case "whitelist":
|
||||
$p = strtolower(array_shift($params));
|
||||
@ -212,7 +222,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 +231,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);
|
||||
}
|
||||
}
|
@ -31,44 +31,6 @@ class EntityAPI{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
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){
|
||||
switch($event){
|
||||
case "player.death":
|
||||
$message = $data["name"];
|
||||
if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){
|
||||
$e = $this->api->entity->get($data["cause"]);
|
||||
switch($e->class){
|
||||
case ENTITY_PLAYER:
|
||||
$message .= " was killed by ".$e->name;
|
||||
break;
|
||||
default:
|
||||
$message .= " was killed";
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
switch($data["cause"]){
|
||||
default:
|
||||
$message .= " was killed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->server->chat(false, $message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
@ -76,6 +38,10 @@ class EntityAPI{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
|
||||
}
|
||||
|
||||
public function getAll(){
|
||||
return $this->server->entities;
|
||||
}
|
||||
@ -95,6 +61,7 @@ class EntityAPI{
|
||||
public function add($class, $type = 0, $data = array()){
|
||||
$eid = $this->server->eidCnt++;
|
||||
$this->server->entities[$eid] = new Entity($this->server, $eid, $class, $type, $data);
|
||||
$this->server->handle("entity.add", $this->server->entities[$eid]);
|
||||
return $this->server->entities[$eid];
|
||||
}
|
||||
|
||||
@ -126,8 +93,11 @@ class EntityAPI{
|
||||
|
||||
public function remove($eid){
|
||||
if(isset($this->server->entities[$eid])){
|
||||
$this->server->entities[$eid]->close();
|
||||
$entity = $this->server->entities[$eid];
|
||||
unset($this->server->entities[$eid]);
|
||||
$this->server->query("DELETE FROM entities WHERE EID = ".$entity->eid.";");
|
||||
$this->server->api->dhandle("entity.remove", $entity);
|
||||
unset($entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -47,13 +47,12 @@ 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 ".$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);
|
||||
$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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -85,16 +84,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("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){
|
@ -32,7 +32,8 @@ class PlayerAPI{
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->server->event("server.regeneration", array($this, "handle"));
|
||||
$this->server->addHandler("server.regeneration", array($this, "handle"));
|
||||
$this->server->addHandler("player.death", array($this, "handle"), 1);
|
||||
$this->server->api->console->register("list", "Shows connected player list", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("kill", "Kills a player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("tppos", "Teleports a player to a position", array($this, "commandHandler"));
|
||||
@ -42,13 +43,36 @@ 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;
|
||||
case "player.death":
|
||||
$message = $data["name"];
|
||||
if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){
|
||||
$e = $this->api->entity->get($data["cause"]);
|
||||
switch($e->class){
|
||||
case ENTITY_PLAYER:
|
||||
$message .= " was killed by ".$e->name;
|
||||
break;
|
||||
default:
|
||||
$message .= " was killed";
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
switch($data["cause"]){
|
||||
default:
|
||||
$message .= " was killed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->server->chat(false, $message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,18 +202,17 @@ class PlayerAPI{
|
||||
public function remove($CID){
|
||||
if(isset($this->server->clients[$CID])){
|
||||
$player = $this->server->clients[$CID];
|
||||
if(is_object($player->entity)){
|
||||
$player->entity->close();
|
||||
}
|
||||
unset($this->server->clients[$CID]);
|
||||
$player->close();
|
||||
$this->saveOffline($player->username, $player->data);
|
||||
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
|
||||
unset($this->server->entities[$player->eid]);
|
||||
unset($this->server->clients[$player->CID]);
|
||||
$this->server->api->entity->remove($player->eid);
|
||||
unset($player);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOffline($name){
|
||||
if(!file_exists(FILE_PATH."data/players/".$name.".dat")){
|
||||
if(!file_exists(FILE_PATH."players/".$name.".dat")){
|
||||
console("[NOTICE] Player data not found for \"".$name."\", creating new profile");
|
||||
$data = array(
|
||||
"spawn" => array(
|
||||
@ -203,7 +226,7 @@ class PlayerAPI{
|
||||
);
|
||||
$this->saveOffline($name, $data);
|
||||
}else{
|
||||
$data = unserialize(file_get_contents(FILE_PATH."data/players/".$name.".dat"));
|
||||
$data = unserialize(file_get_contents(FILE_PATH."players/".$name.".dat"));
|
||||
}
|
||||
$this->server->handle("api.player.offline.get", $data);
|
||||
return $data;
|
||||
@ -211,6 +234,6 @@ class PlayerAPI{
|
||||
|
||||
public function saveOffline($name, $data){
|
||||
$this->server->handle("api.player.offline.save", $data);
|
||||
file_put_contents(FILE_PATH."data/players/".str_replace("/", "", $name).".dat", serialize($data));
|
||||
file_put_contents(FILE_PATH."players/".str_replace("/", "", $name).".dat", serialize($data));
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ class PluginAPI extends stdClass{
|
||||
if($p === false){
|
||||
return false;
|
||||
}
|
||||
$path = FILE_PATH."data/plugins/".$p[1]["name"]."/";
|
||||
$path = FILE_PATH."plugins/".$p[1]["name"]."/";
|
||||
$this->plugins[$p[1]["class"]][1]["path"] = $path;
|
||||
if(!file_exists($path."config.yml")){
|
||||
@mkdir($path, 0777);
|
||||
@ -155,11 +155,11 @@ class PluginAPI extends stdClass{
|
||||
|
||||
public function loadAll(){
|
||||
console("[INFO] Loading Plugins...");
|
||||
$dir = dir(FILE_PATH."data/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."data/plugins/" . $file);
|
||||
$this->load(FILE_PATH."plugins/" . $file);
|
||||
}
|
||||
}
|
||||
}
|
@ -25,15 +25,24 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class ServerAPI extends stdClass{ //Yay! I can add anything to this class in runtime!
|
||||
class ServerAPI{
|
||||
var $restart = false;
|
||||
private $server, $config, $apiList = array();
|
||||
function __construct(){
|
||||
|
||||
public function run(){
|
||||
$this->load();
|
||||
return $this->init();
|
||||
}
|
||||
|
||||
public function load(){
|
||||
@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."packets.log", "");
|
||||
file_put_contents(FILE_PATH."console.in", "");
|
||||
if(!file_exists(FILE_PATH."test.bin.log") or md5_file(FILE_PATH."test.bin.log") !== TEST_MD5){
|
||||
console("[NOTICE] Executing integrity tests...");
|
||||
file_put_contents(FILE_PATH."logs/packets.log", "");
|
||||
if(!file_exists(FILE_PATH."logs/test.bin.log") or md5_file(FILE_PATH."logs/test.bin.log") !== TEST_MD5){
|
||||
console("[NOTICE] Executing tests...");
|
||||
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
|
||||
console("[INFO] uname -a: ".php_uname("a"));
|
||||
console("[INFO] PHP Version: ".phpversion());
|
||||
@ -56,12 +65,14 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
$test .= Utils::writeLong("-1152921504606846976");
|
||||
$test .= Utils::writeTriad(16777215);
|
||||
$test .= Utils::writeTriad(16777216);
|
||||
$str = new Java_String("THIS_IS_ a TEsT_SEED1_123456789^.,.,\xff\x00\x15");
|
||||
$str = new Java_String("TESTING\x00\n\r\t\xff");
|
||||
$test .= Utils::writeLong($str->hashCode());
|
||||
$test .= Utils::writeDataArray(array("a", "b", "c", "\xff\xff\xff\xff"));
|
||||
$test .= Utils::hexToStr("012334567890");
|
||||
file_put_contents(FILE_PATH."test.bin.log", $test);
|
||||
if(md5($test) !== TEST_MD5){
|
||||
file_put_contents(FILE_PATH."logs/test.bin.log", $test);
|
||||
$md5 = md5($test);
|
||||
console("[INFO] MD5 of test: ".$md5);
|
||||
if($md5 !== TEST_MD5){
|
||||
console("[ERROR] Test error, please send your console.log + test.bin.log to the Github repo");
|
||||
die();
|
||||
}
|
||||
@ -79,19 +90,21 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
|
||||
if(!file_exists(FILE_PATH."server.properties")){
|
||||
console("[NOTICE] No server.properties found, using default settings");
|
||||
copy(FILE_PATH."common/default.properties", FILE_PATH."server.properties");
|
||||
copy(FILE_PATH."src/common/default.properties", FILE_PATH."server.properties");
|
||||
}
|
||||
|
||||
console("[DEBUG] Checking data folders...", true, true, 2);
|
||||
@mkdir(FILE_PATH."data/players/", 0777, true);
|
||||
@mkdir(FILE_PATH."data/maps/", 0777);
|
||||
@mkdir(FILE_PATH."data/plugins/", 0777);
|
||||
|
||||
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"));
|
||||
define("DEBUG", $this->getProperty("debug"));
|
||||
$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("upnp-forwarding") === true){
|
||||
console("[INFO] [UPnP] Trying to port forward...");
|
||||
UPnP_PortForward($this->getProperty("port"));
|
||||
}
|
||||
if(($ip = Utils::getIP()) !== false){
|
||||
console("[INFO] External IP: ".$ip);
|
||||
}
|
||||
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
|
||||
console("[INFO] Checking for new server version");
|
||||
console("[INFO] Last check: ".date("Y-m-d H:i:s", $this->getProperty("last-update")));
|
||||
@ -123,12 +136,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());
|
||||
@ -138,17 +162,17 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
|
||||
}
|
||||
}
|
||||
if(file_exists(FILE_PATH."data/maps/level.dat")){
|
||||
if(file_exists(FILE_PATH."worlds/level.dat")){
|
||||
console("[NOTICE] Detected unimported map data. Importing...");
|
||||
$this->importMap(FILE_PATH."data/maps/", true);
|
||||
$this->importMap(FILE_PATH."worlds/", true);
|
||||
}
|
||||
$this->server->mapName = $this->getProperty("level-name");
|
||||
$this->server->mapDir = FILE_PATH."data/maps/".$this->server->mapName."/";
|
||||
if($this->server->mapName === false or trim($this->server->mapName) === "" or !file_exists($this->server->mapDir."chunks.dat")){
|
||||
$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") and !file_exists($this->server->mapDir."chunks.dat.gz"))){
|
||||
if($this->server->mapName === false or trim($this->server->mapName) === ""){
|
||||
$this->server->mapName = "world";
|
||||
}
|
||||
$this->server->mapDir = FILE_PATH."data/maps/".$this->server->mapName."/";
|
||||
$this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/";
|
||||
$generator = "SuperflatGenerator";
|
||||
if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){
|
||||
$generator = $this->getProperty("generator");
|
||||
@ -168,9 +192,9 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
|
||||
//Autoload all default APIs
|
||||
console("[INFO] Loading default APIs");
|
||||
$dir = dir(FILE_PATH."classes/API/");
|
||||
$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,9 +211,19 @@ 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"]);
|
||||
if($this->getProperty("memory-limit") !== false){
|
||||
@ini_set("memory_limit", $this->getProperty("memory-limit"));
|
||||
}else{
|
||||
$this->config["memory-limit"] = "256M";
|
||||
}
|
||||
@ -197,15 +231,15 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
$this->config["invisible"] = false;
|
||||
}
|
||||
if(is_object($this->server)){
|
||||
$this->server->setType($this->config["server-type"]);
|
||||
$this->server->timePerSecond = $this->config["time-per-second"];
|
||||
$this->server->invisible = $this->config["invisible"];
|
||||
$this->server->maxClients = $this->config["max-players"];
|
||||
$this->server->description = $this->config["description"];
|
||||
$this->server->motd = $this->config["motd"];
|
||||
$this->server->gamemode = $this->config["gamemode"];
|
||||
$this->server->difficulty = $this->config["difficulty"];
|
||||
$this->server->whitelist = $this->config["white-list"];
|
||||
$this->server->setType($this->getProperty("server-type"));
|
||||
$this->server->timePerSecond = $this->getProperty("time-per-second");
|
||||
$this->server->invisible = $this->getProperty("invisible");
|
||||
$this->server->maxClients = $this->getProperty("max-players");
|
||||
$this->server->description = $this->getProperty("description");
|
||||
$this->server->motd = $this->getProperty("motd");
|
||||
$this->server->gamemode = $this->getProperty("gamemode");
|
||||
$this->server->difficulty = $this->getProperty("difficulty");
|
||||
$this->server->whitelist = $this->getProperty("white-list");
|
||||
$this->server->reloadConfig();
|
||||
}
|
||||
}
|
||||
@ -217,6 +251,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
$config = $this->config;
|
||||
$config["white-list"] = $config["white-list"] === true ? "true":"false";
|
||||
$config["invisible"] = $config["invisible"] === true ? "true":"false";
|
||||
$config["upnp-forwarding"] = $config["upnp-forwarding"] === true ? "true":"false";
|
||||
$prop = "#Pocket Minecraft PHP server properties\r\n#".date("D M j H:i:s T Y")."\r\n";
|
||||
foreach($config as $n => $v){
|
||||
$prop .= $n."=".$v."\r\n";
|
||||
@ -273,10 +308,15 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
}
|
||||
}
|
||||
|
||||
public function start(){
|
||||
$this->server->start();
|
||||
public function init(){
|
||||
$this->server->init();
|
||||
unregister_tick_function(array($this->server, "tick"));
|
||||
$this->__destruct();
|
||||
unset($this->server);
|
||||
if($this->getProperty("upnp-forwarding") === true ){
|
||||
console("[INFO] [UPnP] Removing port forward...");
|
||||
UPnP_RemovePortForward($this->getProperty("port"));
|
||||
}
|
||||
return $this->restart;
|
||||
}
|
||||
|
||||
@ -286,6 +326,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);
|
||||
}
|
||||
@ -317,24 +361,24 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2);
|
||||
unset($level["Player"]);
|
||||
$lvName = $level["LevelName"]."/";
|
||||
@mkdir(FILE_PATH."data/maps/".$lvName, 0777);
|
||||
file_put_contents(FILE_PATH."data/maps/".$lvName."level.dat", serialize($level));
|
||||
@mkdir(FILE_PATH."worlds/".$lvName, 0777);
|
||||
file_put_contents(FILE_PATH."worlds/".$lvName."level.dat", serialize($level));
|
||||
$entities = parseNBTData($nbt->loadFile($dir."entities.dat"));
|
||||
file_put_contents(FILE_PATH."data/maps/".$lvName."entities.dat", serialize($entities["Entities"]));
|
||||
file_put_contents(FILE_PATH."worlds/".$lvName."entities.dat", serialize($entities["Entities"]));
|
||||
if(!isset($entities["TileEntities"])){
|
||||
$entities["TileEntities"] = array();
|
||||
}
|
||||
file_put_contents(FILE_PATH."data/maps/".$lvName."tileEntities.dat", serialize($entities["TileEntities"]));
|
||||
file_put_contents(FILE_PATH."worlds/".$lvName."tileEntities.dat", serialize($entities["TileEntities"]));
|
||||
console("[DEBUG] Imported ".count($entities["Entities"])." Entities and ".count($entities["TileEntities"])." TileEntities", true, true, 2);
|
||||
|
||||
if($remove === true){
|
||||
rename($dir."chunks.dat", FILE_PATH."data/maps/".$lvName."chunks.dat");
|
||||
rename($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat");
|
||||
unlink($dir."level.dat");
|
||||
@unlink($dir."level.dat_old");
|
||||
@unlink($dir."player.dat");
|
||||
unlink($dir."entities.dat");
|
||||
}else{
|
||||
copy($dir."chunks.dat", FILE_PATH."data/maps/".$lvName."chunks.dat");
|
||||
copy($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat");
|
||||
}
|
||||
if($this->getProperty("level-name") === false){
|
||||
console("[INFO] Setting default level to \"".$level["LevelName"]."\"");
|
||||
@ -351,7 +395,48 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getProperties(){
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
public function getProperty($name){
|
||||
if(($v = arg($name)) !== false){ //Allow for command-line arguments
|
||||
switch(strtolower(trim($v))){
|
||||
case "on":
|
||||
case "true":
|
||||
case "yes":
|
||||
$v = true;
|
||||
break;
|
||||
case "off":
|
||||
case "false":
|
||||
case "no":
|
||||
$v = false;
|
||||
break;
|
||||
}
|
||||
switch($name){
|
||||
case "last-update":
|
||||
if($v === false){
|
||||
$v = time();
|
||||
}else{
|
||||
$v = (int) $v;
|
||||
}
|
||||
break;
|
||||
case "gamemode":
|
||||
case "max-players":
|
||||
case "port":
|
||||
case "debug":
|
||||
case "difficulty":
|
||||
case "time-per-second":
|
||||
$v = (int) $v;
|
||||
break;
|
||||
case "server-id":
|
||||
if($v !== false){
|
||||
$v = preg_match("/[^0-9\-]/", $v) > 0 ? Utils::readInt(substr(md5($v, true), 0, 4)):$v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
if(isset($this->config[$name])){
|
||||
return $this->config[$name];
|
||||
}
|
||||
@ -370,7 +455,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
|
||||
|
||||
public function loadAPI($name, $class, $dir = false){
|
||||
if($dir === false){
|
||||
$dir = FILE_PATH."classes/API/";
|
||||
$dir = FILE_PATH."src/API/";
|
||||
}
|
||||
$file = $dir.$class.".php";
|
||||
if(!file_exists($file)){
|
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));
|
||||
@ -373,6 +391,31 @@ class CustomPacketHandler{
|
||||
$this->raw .= chr($this->data["meta"]);
|
||||
}
|
||||
break;
|
||||
case MC_EXPLOSION:
|
||||
if($this->c === false){
|
||||
$this->data["x"] = Utils::readFloat($this->get(4));
|
||||
$this->data["y"] = Utils::readFloat($this->get(4));
|
||||
$this->data["z"] = Utils::readFloat($this->get(4));
|
||||
$this->data["radius"] = Utils::readFloat($this->get(4));
|
||||
$this->data["count"] = Utils::readInt($this->get(4));
|
||||
$this->data["records"] = array();
|
||||
for($r = 0; $r < $this->data["count"]; ++$r){
|
||||
$this->data["records"][] = array(Utils::readByte($this->get(1)), Utils::readByte($this->get(1)), Utils::readByte($this->get(1)));
|
||||
}
|
||||
}else{
|
||||
$this->raw .= Utils::writeFloat($this->data["x"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["y"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["z"]);
|
||||
$this->raw .= Utils::writeFloat($this->data["radius"]);
|
||||
$this->data["records"] = (array) $this->data["records"];
|
||||
$this->raw .= Utils::writeInt(count($this->data["records"]));
|
||||
if(count($this->data["records"]) > 0){
|
||||
foreach($this->data["records"] as $record){
|
||||
$this->raw .= Utils::writeByte($record[0]) . Utils::writeByte($record[1]) . Utils::writeByte($record[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MC_REQUEST_CHUNK:
|
||||
if($this->c === false){
|
||||
$this->data["x"] = Utils::readInt($this->get(4));
|
||||
@ -445,9 +488,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 +515,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 +602,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;
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ class Material{
|
||||
6 => true,
|
||||
26 => true,
|
||||
31 => true,
|
||||
46 => true,
|
||||
//46 => true,
|
||||
51 => true,
|
||||
54 => true,
|
||||
58 => true,
|
||||
@ -146,6 +146,7 @@ class Material{
|
||||
61 => true,
|
||||
62 => true,
|
||||
64 => true,
|
||||
71 => true,
|
||||
78 => true,
|
||||
96 => true,
|
||||
105 => true,
|
||||
@ -204,6 +205,7 @@ class Material{
|
||||
324 => 64,
|
||||
65 => true,
|
||||
67 => true,
|
||||
330 => 71,
|
||||
73 => true,
|
||||
79 => true,
|
||||
80 => 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
|
||||
@ -33,8 +33,8 @@ define("ENTITY_ITEM", 3);
|
||||
define("ENTITY_PAINTING", 4);
|
||||
|
||||
class Entity extends stdClass{
|
||||
var $eid, $type, $name, $x, $y, $z, $yaw, $pitch, $dead, $data, $class, $attach, $metadata, $closed, $player;
|
||||
|
||||
var $invincible = false, $eid, $type, $name, $x, $y, $z, $speedX, $speedY, $speedZ, $last = array(0, 0, 0, 0), $yaw, $pitch, $dead, $data, $class, $attach, $metadata, $closed, $player, $onTick;
|
||||
private $server;
|
||||
function __construct($server, $eid, $class, $type = 0, $data = array()){
|
||||
$this->server = $server;
|
||||
$this->eid = (int) $eid;
|
||||
@ -49,10 +49,14 @@ 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->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;
|
||||
$this->z = isset($this->data["z"]) ? $this->data["z"]:0;
|
||||
$this->speedX = isset($this->data["speedX"]) ? $this->data["speedX"]:0;
|
||||
$this->speedY = isset($this->data["speedY"]) ? $this->data["speedY"]:0;
|
||||
$this->speedZ = isset($this->data["speedZ"]) ? $this->data["speedZ"]:0;
|
||||
$this->yaw = isset($this->data["yaw"]) ? $this->data["yaw"]:0;
|
||||
$this->pitch = isset($this->data["pitch"]) ? $this->data["pitch"]:0;
|
||||
$this->position = array("x" => &$this->x, "y" => &$this->y, "z" => &$this->z, "yaw" => &$this->yaw, "pitch" => &$this->pitch);
|
||||
@ -74,6 +78,23 @@ 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.pickup", array(
|
||||
"eid" => $player["EID"],
|
||||
"block" => $this->type,
|
||||
"meta" => $this->meta,
|
||||
"target" => $this->eid
|
||||
)) !== false){
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getDirection(){
|
||||
$rotation = ($this->yaw - 90) % 360;
|
||||
if ($rotation < 0) {
|
||||
@ -145,8 +166,7 @@ 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->api->entity->remove($this->eid);
|
||||
$this->closed = true;
|
||||
}
|
||||
}
|
||||
@ -181,6 +201,8 @@ class Entity extends stdClass{
|
||||
$this->y = $y;
|
||||
$this->z = $z;
|
||||
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE EID = ".$this->eid.";");
|
||||
$this->updateVelocity();
|
||||
$this->server->api->dhandle("entity.move", $this);
|
||||
}
|
||||
|
||||
public function move($x, $y, $z, $yaw = 0, $pitch = 0){
|
||||
@ -192,6 +214,8 @@ class Entity extends stdClass{
|
||||
$this->pitch += $pitch;
|
||||
$this->pitch %= 90;
|
||||
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
|
||||
$this->updateVelocity();
|
||||
$this->server->api->dhandle("entity.move", $this);
|
||||
}
|
||||
|
||||
public function setPosition($x, $y, $z, $yaw, $pitch){
|
||||
@ -201,7 +225,32 @@ class Entity extends stdClass{
|
||||
$this->yaw = $yaw;
|
||||
$this->pitch = $pitch;
|
||||
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
|
||||
return true;
|
||||
$this->updateVelocity();
|
||||
$this->server->api->dhandle("entity.move", $this);
|
||||
}
|
||||
|
||||
public function inBlock($x, $y, $z){
|
||||
$block = new Vector3($x + 0.5, $y, $z + 0.5);
|
||||
$me = new Vector3($this->x, $this->y, $this->z);
|
||||
$up = new Vector3($this->x, $this->y + 1, $this->z);
|
||||
if($block->distance($me) < 0.8 or $block->distance($up) < 0.8){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function updateVelocity(){
|
||||
$diffTime = microtime(true) - $this->last[3];
|
||||
$this->last[3] = microtime(true);
|
||||
$speedX = ($this->x - $this->last[0]) / $diffTime;
|
||||
$this->last[0] = $this->x;
|
||||
$speedY = ($this->y - $this->last[1]) / $diffTime;
|
||||
$this->last[1] = $this->y;
|
||||
$speedZ = ($this->z - $this->last[2]) / $diffTime;
|
||||
$this->last[2] = $this->z;
|
||||
$this->speedX = $speedX;
|
||||
$this->speedY = $speedY;
|
||||
$this->speedZ = $speedZ;
|
||||
}
|
||||
|
||||
public function getPosition($round = false){
|
||||
@ -211,7 +260,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,
|
||||
@ -220,7 +269,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;
|
@ -27,7 +27,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
|
||||
class Player{
|
||||
private $server, $timeout, $connected, $evid, $queue, $buffer;
|
||||
private $server, $timeout, $connected, $queue, $buffer, $evid = array();
|
||||
var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU, $spawned, $equipment;
|
||||
function __construct($server, $clientID, $ip, $port, $MTU){
|
||||
$this->queue = array();
|
||||
@ -42,7 +42,6 @@ class Player{
|
||||
$this->entity = false;
|
||||
$this->port = $port;
|
||||
$this->timeout = microtime(true) + 25;
|
||||
$this->evid = array();
|
||||
$this->equipment = array(1, 0);
|
||||
$this->spawned = false;
|
||||
$this->evid[] = $this->server->event("server.tick", array($this, "onTick"));
|
||||
@ -92,59 +91,67 @@ class Player{
|
||||
}
|
||||
|
||||
public function close($reason = "", $msg = true){
|
||||
$reason = $reason == "" ? "server stop":$reason;
|
||||
$this->save();
|
||||
foreach($this->evid as $ev){
|
||||
$this->server->deleteEvent($ev);
|
||||
}
|
||||
$this->eventHandler("You have been kicked. Reason: ".$reason, "server.chat");
|
||||
$this->dataPacket(MC_LOGIN_STATUS, array(
|
||||
"status" => 1,
|
||||
));
|
||||
$this->dataPacket(MC_DISCONNECT);
|
||||
if($this->connected === true){
|
||||
foreach($this->evid as $ev){
|
||||
$this->server->deleteEvent($ev);
|
||||
}
|
||||
$this->server->api->dhandle("player.quit", $this);
|
||||
$reason = $reason == "" ? "server stop":$reason;
|
||||
$this->save();
|
||||
$this->eventHandler(new Container("You have been kicked. Reason: ".$reason), "server.chat");
|
||||
$this->dataPacket(MC_LOGIN_STATUS, array(
|
||||
"status" => 1,
|
||||
));
|
||||
$this->dataPacket(MC_DISCONNECT);
|
||||
|
||||
$this->connected = false;
|
||||
if($msg === true){
|
||||
$this->server->trigger("server.chat", $this->username." left the game");
|
||||
$this->connected = false;
|
||||
if($msg === true){
|
||||
$this->server->api->chat->broadcast($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);
|
||||
}
|
||||
console("[INFO] Session with ".$this->ip.":".$this->port." Client ID ".$this->clientID." closed due to ".$reason);
|
||||
$this->server->api->player->remove($this->CID);
|
||||
}
|
||||
|
||||
public function eventHandler($data, $event){
|
||||
switch($event){
|
||||
case "player.pickup":
|
||||
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;
|
||||
}
|
||||
$this->dataPacket(MC_PLAYER_EQUIPMENT, $data);
|
||||
break;
|
||||
case "world.block.change":
|
||||
case "block.change":
|
||||
$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":
|
||||
case "server.time":
|
||||
$this->dataPacket(MC_SET_TIME, array(
|
||||
"time" => $data,
|
||||
));
|
||||
@ -159,8 +166,17 @@ class Player{
|
||||
));
|
||||
break;
|
||||
case "server.chat":
|
||||
if(($data instanceof Container) === true){
|
||||
if(!$data->check($this->username)){
|
||||
return;
|
||||
}else{
|
||||
$message = $data->get();
|
||||
}
|
||||
}else{
|
||||
$message = (string) $data;
|
||||
}
|
||||
$this->dataPacket(MC_CHAT, array(
|
||||
"message" => str_replace("@username", $this->username, $data),
|
||||
"message" => str_replace("@username", $this->username, $message),
|
||||
));
|
||||
break;
|
||||
}
|
||||
@ -207,9 +223,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,8 +251,14 @@ 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");
|
||||
break;
|
||||
case MC_CLIENT_CONNECT:
|
||||
@ -238,7 +272,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;
|
||||
@ -256,6 +290,10 @@ class Player{
|
||||
if($c !== false){
|
||||
$c->close("logged in from another location");
|
||||
}
|
||||
if($this->server->api->dhandle("player.join", $this) === false){
|
||||
$this->close();
|
||||
return;
|
||||
}
|
||||
$this->server->api->player->add($this->CID);
|
||||
$this->auth = true;
|
||||
$this->data["lastIP"] = $this->ip;
|
||||
@ -275,35 +313,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.timee", 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.pickup", array($this, "eventHandler"));
|
||||
$this->evid[] = $this->server->event("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(new Container($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("player.move", $this->entity);
|
||||
}
|
||||
break;
|
||||
case MC_PLAYER_EQUIPMENT:
|
||||
@ -330,31 +375,51 @@ 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:
|
||||
if(isset($this->server->entities[$data["target"]]) and Utils::distance($this->entity->position, $this->server->entities[$data["target"]]->position) <= 8){
|
||||
console("[DEBUG] EID ".$this->eid." attacked EID ".$data["target"], true, true, 2);
|
||||
if($this->server->gamemode !== 1 and $this->server->difficulty > 0){
|
||||
$this->server->api->entity->harm($data["target"], $this->server->difficulty, $this->eid);
|
||||
if($this->handle("player.interact", $data) !== false){
|
||||
console("[DEBUG] EID ".$this->eid." attacked EID ".$data["target"], true, true, 2);
|
||||
if($this->server->gamemode !== 1 and $this->server->difficulty > 0){
|
||||
$this->server->api->entity->harm($data["target"], $this->server->difficulty, $this->eid);
|
||||
}
|
||||
}
|
||||
}
|
||||
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->invincible = true;
|
||||
$this->entity->setHealth(20, "respawn");
|
||||
$this->entity->setPosition($data["x"], $data["y"], $data["z"], 0, 0);
|
||||
$this->entity->invincible = false;
|
||||
break;
|
||||
case MC_SET_HEALTH:
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
}
|
||||
//$this->entity->setHealth($data["health"], "client");
|
||||
break;
|
||||
case MC_DROP_ITEM:
|
||||
if($this->server->handle("player.drop", $data) !== false){
|
||||
$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;
|
||||
}
|
@ -25,28 +25,31 @@ 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;
|
||||
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){
|
||||
$this->port = (int) $port; //19132 - 19135
|
||||
console("[INFO] PocketMine-MP ".MAJOR_VERSION." by @shoghicp, LGPL License. http://bit.ly/TbrimG", true, true, 0);
|
||||
class PocketMinecraftServer{
|
||||
var $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $spawn, $entities, $mapDir, $mapName, $map, $levelData, $tileEntities;
|
||||
private $database, $interface, $evCnt, $handCnt, $events, $handlers, $serverType, $lastTick, $ticker;
|
||||
|
||||
private function load(){
|
||||
$this->version = new VersionString();
|
||||
console("[INFO] PocketMine-MP ".MAJOR_VERSION." #".$this->version->getNumber()." by @shoghicp, LGPL License", true, true, 0);
|
||||
console("[DEBUG] Target Minecraft PE: ".CURRENT_MINECRAFT_VERSION.", protocol #".CURRENT_PROTOCOL, 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");
|
||||
}
|
||||
$this->serverID = $this->serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$this->serverID;
|
||||
$this->seed = $this->seed === false ? Utils::readInt(Utils::getRandomBytes(4)):$this->seed;
|
||||
console("[INFO] Loading database...");
|
||||
$this->startDatabase();
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->version = (int) $version;
|
||||
$this->name = $name;
|
||||
$this->doTick = false;
|
||||
$this->api = false;
|
||||
$this->mapDir = false;
|
||||
$this->mapName = false;
|
||||
$this->events = array();
|
||||
$this->handlers = array();
|
||||
$this->map = false;
|
||||
$this->invisible = false;
|
||||
$this->level = false;
|
||||
$this->levelData = false;
|
||||
$this->difficulty = 1;
|
||||
$this->tileEntities = array();
|
||||
$this->entities = array();
|
||||
@ -60,25 +63,29 @@ class PocketMinecraftServer extends stdClass{
|
||||
$this->description = "";
|
||||
$this->whitelist = false;
|
||||
$this->bannedIPs = array();
|
||||
$this->motd = "Welcome to ".$name;
|
||||
$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] Max Clients: ".$this->maxClients);
|
||||
console("[DEBUG] Server GUID: ".$this->serverID, true, true, 2);
|
||||
$this->stop = false;
|
||||
}
|
||||
|
||||
function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $serverID = false){
|
||||
$this->port = (int) $port; //19132 - 19135
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->name = $name;
|
||||
$this->motd = "Welcome to ".$name;
|
||||
$this->serverID = $serverID;
|
||||
$this->seed = $seed;
|
||||
$this->load();
|
||||
}
|
||||
|
||||
public function getTPS(){
|
||||
$v = array_values($this->tickMeasure);
|
||||
$tps = 40 / ($v[39] - $v[0]);
|
||||
@ -86,17 +93,15 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
|
||||
public function loadEvents(){
|
||||
$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->event("player.add", array($this, "eventHandler"));
|
||||
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->api->dhandle("server.time", $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, '$cnt = count($this->clients); if($cnt > 1){$this->api->chat->broadcast("Online (".$cnt."): ".implode(", ",$this->api->player->online()));}');
|
||||
}
|
||||
$this->action(1000000 * 75, '$this->debugInfo(true);');
|
||||
$this->action(1000000 * 120, '$this->debugInfo(true);');
|
||||
}
|
||||
|
||||
public function startDatabase(){
|
||||
@ -112,8 +117,8 @@ class PocketMinecraftServer extends stdClass{
|
||||
$this->query("CREATE TABLE events (ID INTEGER PRIMARY KEY, name TEXT);");
|
||||
$this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);");
|
||||
//$this->query("PRAGMA synchronous = OFF;");
|
||||
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
|
||||
$this->preparedSQL->selectEvents = $this->database->prepare("SELECT ID FROM events WHERE name = :name;");
|
||||
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
|
||||
$this->preparedSQL->selectEvents = $this->database->prepare("SELECT DISTINCT ID FROM events WHERE name = :name;");
|
||||
$this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);");
|
||||
$this->preparedSQL->updateActions = $this->database->prepare("UPDATE actions SET last = :time WHERE last <= (:time - interval);");
|
||||
}
|
||||
@ -146,6 +151,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
$info["actions"] = $this->query("SELECT count(ID) as count FROM actions;", true);
|
||||
$info["actions"] = $info["actions"]["count"];
|
||||
$info["garbage"] = gc_collect_cycles();
|
||||
$this->handle("server.debug", $info);
|
||||
if($console === true){
|
||||
console("[DEBUG] TPS: ".$info["tps"].", Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"]."), Entities: ".$info["entities"].", Events: ".$info["events"].", Actions: ".$info["actions"].", Garbage: ".$info["garbage"], true, true, 2);
|
||||
}
|
||||
@ -154,21 +160,17 @@ class PocketMinecraftServer extends stdClass{
|
||||
|
||||
public function close($reason = "stop"){
|
||||
if($this->stop !== true){
|
||||
$this->chat(false, "Stopping server...");
|
||||
$this->save();
|
||||
$this->api->chat->send(false, "Stopping server...");
|
||||
$this->ticker->stop = true;
|
||||
$this->save(true);
|
||||
$this->stop = true;
|
||||
$this->trigger("server.close");
|
||||
$this->trigger("server.close", $reason);
|
||||
$this->interface->close();
|
||||
}
|
||||
}
|
||||
|
||||
public function chat($owner, $text, $target = true){
|
||||
$message = "";
|
||||
if($owner !== false){
|
||||
$message = "<".$owner."> ";
|
||||
}
|
||||
$message .= $text;
|
||||
$this->trigger("server.chat", $message);
|
||||
public function chat($owner, $text, $target = false){
|
||||
$this->api->chat->send($owner, $text, $target);
|
||||
}
|
||||
|
||||
public function setType($type = "normal"){
|
||||
@ -201,17 +203,27 @@ class PocketMinecraftServer extends stdClass{
|
||||
$handlers = $this->preparedSQL->selectHandlers->execute();
|
||||
$result = true;
|
||||
if($handlers !== false and $handlers !== true){
|
||||
while(false !== ($hn = $handlers->fetchArray(SQLITE3_ASSOC)) and $result !== false){
|
||||
$handler = $this->handlers[(int) $hn["ID"]];
|
||||
if(is_array($handler)){
|
||||
$method = $handler[1];
|
||||
$result = $handler[0]->$method($data, $event);
|
||||
console("[INTERNAL] Handling ".$event, true, true, 3);
|
||||
$call = array();
|
||||
while(($hn = $handlers->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$call[(int) $hn["ID"]] = true;
|
||||
}
|
||||
$handlers->finalize();
|
||||
foreach($call as $hnid => $boolean){
|
||||
if($result !== false){
|
||||
$called[$hnid] = true;
|
||||
$handler = $this->handlers[$hnid];
|
||||
if(is_array($handler)){
|
||||
$method = $handler[1];
|
||||
$result = $handler[0]->$method($data, $event);
|
||||
}else{
|
||||
$result = $handler($data, $event);
|
||||
}
|
||||
}else{
|
||||
$result = $handler($data, $event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$handlers->finalize();
|
||||
if($result !== false){
|
||||
$this->trigger($event, $data);
|
||||
}
|
||||
@ -220,30 +232,27 @@ class PocketMinecraftServer extends stdClass{
|
||||
|
||||
public function eventHandler($data, $event){
|
||||
switch($event){
|
||||
case "player.new":
|
||||
case "player.add":
|
||||
console("[DEBUG] Player \"".$data["username"]."\" EID ".$data["eid"]." spawned at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
|
||||
break;
|
||||
case "server.chat":
|
||||
console("[CHAT] $data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function loadMap(){
|
||||
if($this->mapName !== false and trim($this->mapName) !== ""){
|
||||
$this->level = unserialize(file_get_contents($this->mapDir."level.dat"));
|
||||
console("[INFO] Map: ".$this->level["LevelName"]);
|
||||
$this->time = (int) $this->level["Time"];
|
||||
$this->seed = (int) $this->level["RandomSeed"];
|
||||
if(isset($this->level["SpawnX"])){
|
||||
$this->spawn = array("x" => $this->level["SpawnX"], "y" => $this->level["SpawnY"], "z" => $this->level["SpawnZ"]);
|
||||
$this->levelData = unserialize(file_get_contents($this->mapDir."level.dat"));
|
||||
console("[INFO] Map: ".$this->levelData["LevelName"]);
|
||||
$this->time = (int) $this->levelData["Time"];
|
||||
$this->seed = (int) $this->levelData["RandomSeed"];
|
||||
if(isset($this->levelData["SpawnX"])){
|
||||
$this->spawn = array("x" => $this->levelData["SpawnX"], "y" => $this->levelData["SpawnY"], "z" => $this->levelData["SpawnZ"]);
|
||||
}else{
|
||||
$this->level["SpawnX"] = $this->spawn["x"];
|
||||
$this->level["SpawnY"] = $this->spawn["y"];
|
||||
$this->level["SpawnZ"] = $this->spawn["z"];
|
||||
$this->levelData["SpawnX"] = $this->spawn["x"];
|
||||
$this->levelData["SpawnY"] = $this->spawn["y"];
|
||||
$this->levelData["SpawnZ"] = $this->spawn["z"];
|
||||
}
|
||||
$this->level["Time"] = &$this->time;
|
||||
console("[INFO] Spawn: X ".$this->level["SpawnX"]." Y ".$this->level["SpawnY"]." Z ".$this->level["SpawnZ"]);
|
||||
$this->levelData["Time"] = $this->time;
|
||||
console("[INFO] Spawn: X ".$this->levelData["SpawnX"]." Y ".$this->levelData["SpawnY"]." Z ".$this->levelData["SpawnZ"]);
|
||||
console("[INFO] Time: ".$this->time);
|
||||
console("[INFO] Seed: ".$this->seed);
|
||||
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
|
||||
@ -252,7 +261,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
console("[INFO] Loading map...");
|
||||
$this->map = new ChunkParser();
|
||||
if(!$this->map->loadFile($this->mapDir."chunks.dat")){
|
||||
console("[ERROR] Couldn't load the map \"".$this->level["LevelName"]."\"!", true, true, 0);
|
||||
console("[ERROR] Couldn't load the map \"".$this->levelData["LevelName"]."\"!", true, true, 0);
|
||||
$this->map = false;
|
||||
}else{
|
||||
$this->map->loadMap();
|
||||
@ -292,37 +301,71 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
}
|
||||
console("[DEBUG] Loaded ".count($this->entities)." Entities", true, true, 2);
|
||||
$this->action(1000000 * 60 * 15, '$this->chat(false, "Forcing save...");$this->save();$this->chat(false, "Done");');
|
||||
$this->action(1000000 * 60 * 15, '$this->api->chat->broadcast("Forcing save...");$this->save();');
|
||||
}
|
||||
}
|
||||
|
||||
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->levelData["Time"] = $this->time;
|
||||
file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
|
||||
$this->map->saveMap($final);
|
||||
console("[INFO] Saving entities...");
|
||||
foreach($this->entities as $entity){
|
||||
|
||||
}
|
||||
$this->trigger("server.save", $final);
|
||||
}
|
||||
}
|
||||
|
||||
public function start(){
|
||||
public function init(){
|
||||
if($this->mapName !== false and $this->map === false){
|
||||
$this->loadMap();
|
||||
$this->loadEntities();
|
||||
}
|
||||
console("[INFO] Loading events...");
|
||||
$this->loadEvents();
|
||||
$this->ticker = new TickLoop($this);
|
||||
$this->ticker->start();
|
||||
declare(ticks=15);
|
||||
register_tick_function(array($this, "tick"));
|
||||
register_shutdown_function(array($this, "dumpError"));
|
||||
register_shutdown_function(array($this, "close"));
|
||||
$this->trigger("server.start", microtime(true));
|
||||
console("[INFO] Server started!");
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function dumpError(){
|
||||
console("[ERROR] An Unrecovereable has ocurred and the server has Crashed. Creating an Error Dump");
|
||||
$dump = "# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
|
||||
$dump .= "Error: ".var_export(error_get_last(), true)."\r\n\r\n";
|
||||
$version = new VersionString();
|
||||
$dump .= "PM Version: ".$version." #".$version->getNumber()." [Protocol ".CURRENT_PROTOCOL."]\r\n";
|
||||
$dump .= "uname -a: ".php_uname("a")."\r\n";
|
||||
$dump .= "PHP Version: " .phpversion()."\r\n";
|
||||
$dump .= "Zend version: ".zend_version()."\r\n";
|
||||
$dump .= "OS : " .PHP_OS.", ".Utils::getOS()."\r\n";
|
||||
$dump .= "Debug Info: ".var_export($this->debugInfo(false), true)."\r\n\r\n\r\n";
|
||||
global $arguments;
|
||||
$dump .= "Parameters: ".var_export($arguments, true)."\r\n\r\n\r\n";
|
||||
$dump .= "server.properties: ".var_export($this->api->getProperties(), true)."\r\n\r\n\r\n";
|
||||
$dump .= "Loaded Modules: ".var_export(get_loaded_extensions(), true)."\r\n\r\n";
|
||||
$name = "error_dump_".time();
|
||||
logg($dump, $name, true, 0, true);
|
||||
console("[ERROR] Please submit the \"logs/{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
|
||||
}
|
||||
|
||||
public function tick(){
|
||||
/*if($this->ticker->tick === true and $this->ticker->isWaiting() === true){
|
||||
$this->ticker->tick = false;
|
||||
$time = microtime(true);
|
||||
array_shift($this->tickMeasure);
|
||||
$this->tickMeasure[] = $this->lastTick = $time;
|
||||
$this->tickerFunction($time);
|
||||
$this->trigger("server.tick", $time);
|
||||
$this->ticker->notify();
|
||||
}*/
|
||||
$time = microtime(true);
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
array_shift($this->tickMeasure);
|
||||
@ -333,7 +376,7 @@ class PocketMinecraftServer extends stdClass{
|
||||
}
|
||||
|
||||
public function clientID($ip, $port){
|
||||
return md5($pi . $port, true);
|
||||
return md5($ip . $port, true);
|
||||
}
|
||||
|
||||
public function packetHandler($packet){
|
||||
@ -342,6 +385,9 @@ class PocketMinecraftServer extends stdClass{
|
||||
if(isset($this->clients[$CID])){
|
||||
$this->clients[$CID]->handle($packet["pid"], $data);
|
||||
}else{
|
||||
if($this->handle("server.noauthpacket", $packet) === false){
|
||||
return;
|
||||
}
|
||||
switch($packet["pid"]){
|
||||
case 0x02:
|
||||
if($this->invisible === true){
|
||||
@ -397,9 +443,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"]);
|
||||
@ -464,26 +510,26 @@ class PocketMinecraftServer extends stdClass{
|
||||
if($events === false or $events === true){
|
||||
return;
|
||||
}
|
||||
while(false !== ($evn = $events->fetchArray(SQLITE3_ASSOC))){
|
||||
$ev = $this->events[(int) $evn["ID"]];
|
||||
if(is_array($ev)){
|
||||
$method = $ev[1];
|
||||
$this->responses[(int) $evn["ID"]] = $ev[0]->$method($data, $event);
|
||||
}else{
|
||||
$this->responses[(int) $evn["ID"]] = $ev($data, $event);
|
||||
}
|
||||
$call = array();
|
||||
while(($evn = $events->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$call[(int) $evn["ID"]] = true;
|
||||
}
|
||||
$events->finalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function response($eid){
|
||||
if(isset($this->responses[$eid])){
|
||||
$res = $this->responses[$eid];
|
||||
unset($this->responses[$eid]);
|
||||
return $res;
|
||||
foreach($call as $evid => $boolean){
|
||||
$ev = $this->events[$evid];
|
||||
if(!is_callable($ev)){
|
||||
$this->deleteEvent($evid);
|
||||
continue;
|
||||
}
|
||||
if(is_array($ev)){
|
||||
$method = $ev[1];
|
||||
$ev[0]->$method($data, $event);
|
||||
}else{
|
||||
$ev($data, $event);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function schedule($ticks, $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
|
||||
@ -495,7 +541,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 false;} call_user_func($schedule[0], $schedule[1], $schedule[2]);', (bool) $repeat);
|
||||
return $this->scheduleCnt++;
|
||||
}
|
||||
|
||||
@ -515,8 +561,8 @@ class PocketMinecraftServer extends stdClass{
|
||||
return;
|
||||
}
|
||||
while(false !== ($action = $actions->fetchArray(SQLITE3_ASSOC))){
|
||||
eval(base64_decode($action["code"]));
|
||||
if($action["repeat"] === 0){
|
||||
$return = eval(base64_decode($action["code"]));
|
||||
if($action["repeat"] === 0 or $return === false){
|
||||
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
|
||||
}
|
||||
}
|
@ -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__)."/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){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -30,7 +30,6 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class UDPSocket{
|
||||
private $encrypt;
|
||||
var $buffer, $connected, $errors, $sock, $server;
|
||||
|
||||
function __construct($server, $port, $listen = false, $socket = false){
|
||||
$this->errors = array_fill(88,(125 - 88) + 1, true);
|
||||
$this->server = $server;
|
||||
@ -58,7 +57,7 @@ class UDPSocket{
|
||||
}
|
||||
}
|
||||
|
||||
function listenSocket(){
|
||||
public function listenSocket(){
|
||||
$sock = @socket_accept($this->sock);
|
||||
if($sock !== false){
|
||||
$sock = new Socket(false, false, false, $sock);
|
@ -35,12 +35,33 @@ define("BIG_ENDIAN", 0x00);
|
||||
define("LITTLE_ENDIAN", 0x01);
|
||||
define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? BIG_ENDIAN:LITTLE_ENDIAN));
|
||||
|
||||
abstract class Utils{
|
||||
class Utils extends Thread{
|
||||
|
||||
public function run(){
|
||||
|
||||
}
|
||||
|
||||
public static function getIP(){
|
||||
$ip = trim(Utils::curl_get("http://automation.whatismyip.com/n09230945.asp"));
|
||||
if($ip != ""){
|
||||
return $ip;
|
||||
}else{
|
||||
$ip = trim(Utils::curl_get("http://checkip.dyndns.org/"));
|
||||
$ip = preg_replace("/Current IP Address: (.*)/", '$1', $ip);
|
||||
if($ip != ""){
|
||||
return $ip;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getOS(){
|
||||
$uname = strtoupper(php_uname("s"));
|
||||
if(strpos($uname, "WIN") !== false){
|
||||
return "win";
|
||||
}elseif(strpos($uname, "DARWIN") !== false){
|
||||
return "mac";
|
||||
}else{
|
||||
return "linux";
|
||||
}
|
||||
@ -304,7 +325,7 @@ abstract class Utils{
|
||||
|
||||
public static function curl_get($page){
|
||||
$ch = curl_init($page);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Minecraft PHP Client 2"));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"));
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
@ -322,7 +343,7 @@ abstract class Utils{
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Minecraft PHP Client 2"));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
|
||||
$ret = curl_exec($ch);
|
@ -25,16 +25,15 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
define("WINDOW_CHEST", 0);
|
||||
define("WINDOW_WORKBENCH", 1);
|
||||
define("WINDOW_FURNACE", 2);
|
||||
|
||||
class TreeObject{
|
||||
class Window{
|
||||
private $server;
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
|
||||
public static function growTree(LevelAPI $level, $block, $type){
|
||||
switch($type){
|
||||
default:
|
||||
case Sapling::OAK:
|
||||
$tree = new SmallTreeObject();
|
||||
break;
|
||||
}
|
||||
$tree->placeObject($level, $block[2][0], $block[2][1], $block[2][2], $type);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -32,12 +32,12 @@ error_reporting(E_ALL ^ E_NOTICE);
|
||||
ini_set("allow_url_fopen", 1);
|
||||
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 . "/classes/");
|
||||
ini_set("memory_limit", "256M");
|
||||
define("CURRENT_PROTOCOL", 5);
|
||||
define("CURRENT_VERSION", 1);
|
||||
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", "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.1");
|
||||
define("TEST_MD5", "d0ca3786e53b615bb4fb9f5094d5c9a7");
|
||||
define("MAJOR_VERSION", "Alpha_1.0.6");
|
||||
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,27 +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("curl")){
|
||||
if(!extension_loaded("pthreads") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "pthreads." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find pthreads extension. Use the Installer available in the Homepage", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
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");
|
||||
@ -78,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");
|
||||
@ -85,6 +101,6 @@ require_once("classes/SerializedPacketHandler.class.php");
|
||||
require_once("classes/CustomPacketHandler.class.php");
|
||||
require_once("classes/MinecraftInterface.class.php");
|
||||
require_once("classes/BigInteger.class.php");
|
||||
require_all("misc/");
|
||||
require_all(FILE_PATH . "src/misc/");
|
||||
|
||||
?>
|
@ -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())){
|
||||
@ -89,7 +107,7 @@ function parseNBTData($data){
|
||||
}
|
||||
|
||||
|
||||
function arg($name, $default){
|
||||
function arg($name, $default = false){
|
||||
global $arguments, $argv;
|
||||
if(!isset($arguments)){
|
||||
$arguments = arguments($argv);
|
||||
@ -109,7 +127,7 @@ function arguments ( $args ){
|
||||
array_shift( $args );
|
||||
$args = join( $args, ' ' );
|
||||
|
||||
preg_match_all('/ (--\w+ (?:[= ] [^-]+ [^\s-] )? ) | (-\w+) | (\w+) /x', $args, $match );
|
||||
preg_match_all('/ (--[\w\-]+ (?:[= ] [^-]+ [^\s-] )? ) | (-\w+) | (\w+) /x', $args, $match );
|
||||
$args = array_shift( $match );
|
||||
|
||||
$ret = array(
|
||||
@ -147,7 +165,6 @@ function arguments ( $args ){
|
||||
}
|
||||
|
||||
function console($message, $EOL = true, $log = true, $level = 1){
|
||||
//global $path;
|
||||
if(!defined("DEBUG") or DEBUG >= $level){
|
||||
$message .= $EOL === true ? PHP_EOL:"";
|
||||
$message = date("H:i:s"). " ". $message;
|
||||
@ -169,10 +186,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."/".$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]);
|
@ -24,8 +24,8 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class ChatAPI{
|
||||
/*
|
||||
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.")";
|
||||
}
|
||||
|
||||
}
|
73
src/misc/utils/Container.php
Normal file
73
src/misc/utils/Container.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?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 Container{
|
||||
private $payload = "", $whitelist = false, $blacklist = false;
|
||||
public function __construct($payload = "", $whitelist = false, $blacklist = false){
|
||||
$this->payload = $payload;
|
||||
if(is_array($whitelist)){
|
||||
$this->whitelist = $whitelist;
|
||||
}
|
||||
if(is_array($blacklist)){
|
||||
$this->blacklist = $blacklist;
|
||||
}
|
||||
}
|
||||
|
||||
public function get(){
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
public function check($target){
|
||||
$w = true;
|
||||
$b = false;
|
||||
if($this->whitelist !== false){
|
||||
$w = false;
|
||||
if(in_array($target, $this->whitelist, true)){
|
||||
$w = true;
|
||||
}
|
||||
}else{
|
||||
$w = true;
|
||||
}
|
||||
if($this->blacklist !== false){
|
||||
$b = true;
|
||||
if(in_array($target, $this->blacklist, true)){
|
||||
$b = false;
|
||||
}
|
||||
}else{
|
||||
$b = false;
|
||||
}
|
||||
if($w === false or $b === true){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(){
|
||||
return $this->payload;
|
||||
}
|
||||
}
|
47
src/misc/utils/TickLoop.php
Normal file
47
src/misc/utils/TickLoop.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?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 TickLoop extends Thread{
|
||||
var $tick = false, $stop = false, $lastTick = 0;
|
||||
private $server;
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
}
|
||||
public function run(){
|
||||
while($this->stop !== true){
|
||||
usleep(1);
|
||||
$time = microtime(true);
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
$this->lastTick = $time;
|
||||
$this->tick = true;
|
||||
$this->wait();
|
||||
$this->tick = false;
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
61
src/misc/utils/UPnP.php
Normal file
61
src/misc/utils/UPnP.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
function UPnP_PortForward($port){
|
||||
if(Utils::getOS() != "win" or !class_exists("COM")){
|
||||
return false;
|
||||
}
|
||||
$port = (int) $port;
|
||||
$myLocalIP = gethostbyname(trim(`hostname`));
|
||||
try{
|
||||
$com = new COM("HNetCfg.NATUPnP");
|
||||
if($com === false or !is_object($com->StaticPortMappingCollection)){
|
||||
return false;
|
||||
}
|
||||
$com->StaticPortMappingCollection->Add($port, "UDP", $port, $myLocalIP, true, "PocketMine-MP");
|
||||
}catch(Exception $e){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function UPnP_RemovePortForward($port){
|
||||
if(Utils::getOS() != "win" or !class_exists("COM")){
|
||||
return false;
|
||||
}
|
||||
$port = (int) $port;
|
||||
try{
|
||||
$com = new COM("HNetCfg.NATUPnP") or false;
|
||||
if($com === false or !is_object($com->StaticPortMappingCollection)){
|
||||
return false;
|
||||
}
|
||||
$com->StaticPortMappingCollection->Remove($port, "UDP");
|
||||
}catch(Exception $e){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
62
src/misc/world/generator/object/tree/TreeObject.php
Normal file
62
src/misc/world/generator/object/tree/TreeObject.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?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 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:
|
||||
if(mt_rand(0,9) === 0){
|
||||
$tree = new BigTreeObject();
|
||||
}else{
|
||||
$tree = new SmallTreeObject();
|
||||
}
|
||||
break;
|
||||
}
|
||||
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",
|
||||
|
||||
@ -59,6 +60,8 @@ $dataName = array(
|
||||
MC_REMOVE_BLOCK => "RemoveBlock",
|
||||
MC_UPDATE_BLOCK => "UpdateBlock",
|
||||
|
||||
MC_EXPLOSION => "Explosion",
|
||||
|
||||
MC_REQUEST_CHUNK => "RequestChunk",
|
||||
MC_CHUNK_DATA => "ChunkData",
|
||||
|
||||
@ -74,6 +77,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);
|
||||
|
||||
@ -59,6 +60,8 @@ define("MC_PLACE_BLOCK", 0x95);
|
||||
define("MC_REMOVE_BLOCK", 0x96);
|
||||
define("MC_UPDATE_BLOCK", 0x97);
|
||||
|
||||
define("MC_EXPLOSION", 0x99);
|
||||
|
||||
define("MC_REQUEST_CHUNK", 0x9d);
|
||||
define("MC_CHUNK_DATA", 0x9e);
|
||||
|
||||
@ -74,6 +77,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 server.php
|
||||
START /B /WAIT php 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