Compare commits

..

203 Commits

Author SHA1 Message Date
f0aecabef7 Updated Version 2013-01-31 18:20:31 +01:00
60c57a6330 Correct and new slab placement (upside-down) 2013-01-31 18:20:01 +01:00
ba4fe61cdb Better event handling 2013-01-31 17:23:50 +01:00
a485536716 Fixed protocol errors 2013-01-30 23:38:07 +01:00
9ef2dc6fe1 Small changes, Ellie 2013-01-30 20:49:34 +01:00
d0a08d16e7 Added new packets 2013-01-30 20:21:18 +01:00
0e889b0139 Armor is shown on multiplayer 2013-01-30 19:57:11 +01:00
fe8b4b7aa7 Added Armor 2013-01-30 18:46:06 +01:00
1e8b012a6e Added structure version 2013-01-30 18:09:19 +01:00
5096cdcde8 Added item pickup delay 2013-01-30 18:02:13 +01:00
08b67428a0 Placing signs text 2013-01-30 17:07:43 +01:00
b697f1441e Protocol changes 4 2013-01-30 16:29:00 +01:00
62578d5fc7 Protocol changes 3 2013-01-30 16:25:26 +01:00
c787142346 Protocol changes 2 2013-01-30 16:13:33 +01:00
db38b824b7 Protocol changes 1 2013-01-30 16:00:22 +01:00
a75f8c2737 Updating version & protocol enforcement 2013-01-30 15:35:33 +01:00
9a8850cb9c Added Stonecutter 2013-01-30 12:47:47 +01:00
8d232cf623 Save paintings 2013-01-29 22:44:19 +01:00
a7079fc49b Correctly handle paintings 2013-01-29 22:38:48 +01:00
71b12191b2 Eating 2013-01-29 20:53:43 +01:00
2011d1d339 Void damage 2013-01-29 20:01:33 +01:00
1976e1c6f6 Item movement fix 2013-01-29 19:29:16 +01:00
5a2156c2bf New compile options for speed improvement 2013-01-29 19:05:47 +01:00
a86213dad8 Include Yaw and Pitch in entity tracking 2013-01-29 17:16:20 +01:00
6095432a4f Updated versions 2013-01-29 10:01:46 +01:00
46f7279a26 Fixes #83 #82 2013-01-29 08:40:36 +01:00
da2b800ea8 Changes in item spawning 2013-01-28 23:07:17 +01:00
862947ab6b Entity Motion packet (WiP) 2013-01-28 22:48:18 +01:00
f8179f0f7c Removed var_dump()! 2013-01-28 20:30:31 +01:00
db9625b52f Entity Gravity 2013-01-28 20:26:57 +01:00
fe3be181e8 Sign placing improvement 2013-01-28 19:06:39 +01:00
8a5708f47a Placing Signs 2013-01-28 19:01:41 +01:00
df46e241d3 Added marble block 2013-01-28 18:37:26 +01:00
104817162d Added upside-down stairs 2013-01-28 18:19:16 +01:00
50ae0953ac Allow for command-line arguments to starter scripts 2013-01-28 18:10:43 +01:00
d9e9b9fd22 Updated target version 2013-01-28 16:22:11 +01:00
eeb623cf21 Added new 0.6.0 blocks 2013-01-28 16:21:50 +01:00
1474d8c785 Better Tile selection & player death check and fix 2013-01-27 23:21:08 +01:00
26fb652c5a Added entity dead check for damage 2013-01-27 23:08:30 +01:00
c06ffe3003 TileEntity spawning improvement 2013-01-27 22:58:54 +01:00
2cb7a21b76 Entity and TileEntity saving 2013-01-27 21:33:57 +01:00
5c11f48270 Tile Entities & Signs 2013-01-27 19:36:12 +01:00
3c4888521d Fix for feet suffocation 2013-01-27 19:14:51 +01:00
d54161f5ca Fixed Signs sufocation 2013-01-27 18:46:09 +01:00
67341c6420 Added regeneration fix, item despawn and damage check 2013-01-27 18:23:51 +01:00
2eb93c1676 Entity metadata 2013-01-27 13:32:55 +01:00
d69291e2fa Added logged in checks 2013-01-27 11:34:24 +01:00
0c5826c8ab Water now generates source blocks 2013-01-27 11:29:43 +01:00
880121a83f Fixed a special water & lava case 2013-01-27 00:29:25 +01:00
0082bc9d10 Lava & water flow now creates stone, cobblestona and obsidian 2013-01-27 00:10:34 +01:00
895e001216 Fixed PHP-Powered memory leaks 2013-01-26 22:00:34 +01:00
1f8939da6e Fixed entities memory leak 2013-01-26 21:45:31 +01:00
c77a3c2f87 Added new IP site 2013-01-26 20:57:13 +01:00
f476cf6943 Send optional usage data 2013-01-26 20:50:34 +01:00
8e3efa0b7e Removed unknown Packet 0xa9 2013-01-26 19:01:05 +01:00
81423e6c3d Fixed health not being correctly displayed after reconnect 2013-01-26 18:55:09 +01:00
e1cf3cc25e Entity death status 2013-01-26 18:51:50 +01:00
fe7138b21e Entity moving optimization 2013-01-26 18:44:13 +01:00
234aee9dfa Entity harm sound 2013-01-26 18:24:10 +01:00
88725100a0 Version - Arggghhhhh!!!! 2013-01-26 17:36:34 +01:00
15772bfad4 Version 2013-01-26 17:34:02 +01:00
afbb5fab04 Fixed old & deprecated plugins not being able to create a config file 2013-01-26 17:32:56 +01:00
00c3201580 Fixed suffocating in fences 2013-01-26 17:24:05 +01:00
36fdb10b9e Fixed random suffocation 2013-01-26 17:19:52 +01:00
828b794555 Fixed suffocating in doors 2013-01-26 17:09:00 +01:00
e1ce88c0ef Fixed creative mode damage 2013-01-26 17:06:30 +01:00
4b744d7af3 Fixed server crash releated to inventory spawning 2013-01-26 16:58:10 +01:00
59a95aadd2 Fixed server crash 2013-01-26 16:23:33 +01:00
20035d18cd Updated version 2013-01-26 14:50:20 +01:00
0425b630ca Updated homepage 2013-01-26 14:38:41 +01:00
d3c6c41ad0 Removed irrelevant things 2013-01-26 14:36:39 +01:00
0ae467c33f Bonemeal tall grass and flowers grow 2013-01-26 14:27:56 +01:00
f917111f31 Implemented drowing damage 2013-01-26 13:44:38 +01:00
ac0fab8f0b Made Zlib required 2013-01-26 13:21:58 +01:00
d1d720e9ef Updated compiler to use less instructions & disk usage 2013-01-26 13:15:53 +01:00
2a63699dcc Updated Entity::touchingBlock() 2013-01-26 12:59:22 +01:00
6a0b3c0e9a Kill messages 2013-01-26 12:56:29 +01:00
09385daf60 Better damage handling + cactus damage 2013-01-26 12:53:37 +01:00
061faaa410 Entity closing fix 2013-01-26 12:31:09 +01:00
26da585889 health regeneration cancelled when dead 2013-01-26 12:12:59 +01:00
a0cb4d2698 Fixed item restoration duplication 2013-01-26 11:57:19 +01:00
5101391c29 Lava, fire and suffocation damage 2013-01-26 11:31:38 +01:00
f06f1d81c1 Fixed cURL version 2013-01-25 14:24:00 +01:00
75eb324967 Added inline compiler optimization for big servers 2013-01-24 17:11:30 +01:00
e5bed548b9 Added Kick API 2013-01-24 19:13:48 +10:30
fde7b5ab5d New compiler using variables to handle versions 2013-01-23 22:16:24 +01:00
237ad4eee4 Fixed random entity memory leak + loops 2013-01-23 20:50:01 +01:00
6660a0a771 Changed version to development 2013-01-23 20:20:12 +01:00
de44ef742d Updated to Alpha_1.0.7 2013-01-23 20:16:19 +01:00
386decf268 Updated Threads use the new commit 2013-01-23 19:38:42 +01:00
6cd51dbbf6 Fixed stop crash due to chat API not set 2013-01-23 19:37:28 +01:00
bf5df18170 Added online check 2013-01-22 18:21:41 +01:00
b589b69beb Fixed the Socket error at close 2013-01-22 18:21:22 +01:00
1152c24bdf Updated PHP version in compiler 2013-01-22 17:59:09 +01:00
039011d9bb Added a deprecation Error 2013-01-21 19:01:00 +01:00
ef76138a1c Internal Fixes 2013-01-21 00:20:55 +01:00
c049b5fb72 Added ban reload() 2013-01-19 21:59:33 +09:00
aef32f2012 Entity velocity 2013-01-19 12:41:53 +01:00
0fa3dded89 Fixed gamemode issues 2013-01-19 00:01:38 +01:00
7723e3784f Inventory saving (without checks) 2013-01-18 23:59:51 +01:00
e4bf449198 Added Invalid World Data warning 2013-01-18 16:42:38 +01:00
23600349d1 Revert "Added AutoUpdate Script for linux. (Not Stable)"
This reverts commit 834d6719c7.
2013-01-18 14:56:11 +01:00
8c92bc7c14 Merge branch 'master' of https://github.com/shoghicp/PocketMine-MP 2013-01-18 21:30:40 +09:00
834d6719c7 Added AutoUpdate Script for linux. (Not Stable) 2013-01-18 21:29:45 +09:00
bff4d92bcd Inventory array 2013-01-18 07:55:51 +01:00
937888a655 Merge branch 'master' of https://github.com/shoghicp/PocketMine-MP 2013-01-18 15:17:24 +09:00
08499720f5 Changed parameter name in Ban API 2013-01-18 15:15:22 +09:00
0d3cf74636 Added more Ban APIs. Now you can directly ban 2013-01-18 15:14:39 +09:00
1d9e1fde79 Fixed Description 2013-01-17 23:23:45 +01:00
a24da0e5ad Removed unused commands 2013-01-17 19:02:50 +01:00
a5229cc34e Fixed a typo ;) 2013-01-17 16:37:53 +01:00
ed61111aca Added a way to call custom commands in ConsoleAPI 2013-01-17 16:10:41 +01:00
1409a1f7b5 Added /kick command 2013-01-17 16:10:25 +01:00
78bfe7ce24 Time Issue Fixed fixed #64 fixed #65 2013-01-17 20:20:09 +09:00
a6b9a9baff Fixed a typo on Player.php Typo: server.timee 2013-01-17 18:34:40 +09:00
136fd205f0 BanAPI added (username, IP, whitelist) 2013-01-16 19:52:51 +01:00
aa92e83733 Placing blocks in an Entity fix *again* 2013-01-16 19:30:01 +01:00
4067aff8e1 Link :s 2013-01-16 18:54:16 +01:00
dfa8288ec9 Added IRC 2013-01-16 18:53:13 +01:00
3d1d3e89ea Added Dev tag to Config String 2013-01-16 18:23:22 +01:00
d6ab1a9a87 Fixed events on BlockAPI 2013-01-15 20:58:53 +01:00
fe7595e313 Did some improvements 2013-01-15 19:25:33 +01:00
4ddb8a298b Ooops! 2013-01-15 18:27:05 +01:00
3938db7c4f Fixed placing transparent blocks 2013-01-15 18:26:17 +01:00
475419b693 Fixed Tree spawning 2013-01-15 18:21:55 +01:00
d147caa913 Fixed cactus placement 2013-01-15 17:51:26 +01:00
ea26c32204 Removed PDO dependency & edited a color 2013-01-15 17:38:16 +01:00
f79c6cf2e9 getSide() Vector3 method 2013-01-15 17:18:05 +01:00
cac2a3a6e5 Added pause to start.sh 2013-01-15 16:17:34 +01:00
17161d7cd0 Fixed #62 2013-01-15 15:49:03 +01:00
d988b27b16 New IP methods 2013-01-15 15:44:33 +01:00
fe70af47dc Added Twitter + Mailing List 2013-01-14 21:51:11 +01:00
858cd5cb41 Compile optimizations 2013-01-14 21:10:28 +01:00
d306c8f713 Measure time 2013-01-14 18:58:09 +01:00
310701f7e9 Added stop signal check 2013-01-14 18:34:52 +01:00
8bc40d2d9c Removed a method to get the IP 2013-01-14 18:07:50 +01:00
cd05434853 Added new Compile Options 2013-01-14 18:03:55 +01:00
3b10613f98 Corrected block placement area 2013-01-14 17:13:53 +01:00
f47fa6d5dc Fixed race condition in API schedule() 2013-01-14 16:42:57 +01:00
29cd858622 Fixed race condition in API addHandler() 2013-01-14 16:41:52 +01:00
aa22acee5f Fixed race condition in API event() 2013-01-14 16:40:35 +01:00
2d3580fd22 Updated README.md 2013-01-14 16:37:42 +01:00
d3d2721f84 Added ANSICON to Third-Party list 2013-01-14 16:34:31 +01:00
ce3dcf4cf4 Removed more XML dependencies 2013-01-14 14:41:45 +01:00
3813ef73ea Updated start.cmd 2013-01-14 07:24:18 +01:00
2ddb626edb Added letters 2013-01-13 23:07:07 +01:00
6a97750e06 Updated PluginAPI with a new way of managing configuration 2013-01-13 19:33:28 +01:00
4b1f1cfd44 Added default server.properties 2013-01-13 19:25:12 +01:00
ac570213a5 Configuration Base Class updated! 2013-01-13 18:21:05 +01:00
44e53ccc1b Corrected events 2013-01-13 17:24:22 +01:00
bf1d78d1e4 ANSI Color codes 2013-01-13 17:18:18 +01:00
d0cff39aa3 Added Config base Class 2013-01-13 16:59:42 +01:00
109b44a205 Fix for non-loading plugins 2013-01-13 14:02:57 +01:00
ce7c7efc79 Fixes 2013-01-13 12:18:07 +01:00
dff26611e5 Moving files 2013-01-13 11:31:53 +01:00
6d90249fbd Added slabs to transparent blocks list 2013-01-13 01:57:15 +01:00
74fa32dfa9 Corrected slab placement
* Correct lateral slab placement
* Fixed When placing a block in a slab, it becomes a double one (only
stone)
2013-01-13 01:53:28 +01:00
eacaf139c2 Added handlers to debug info 2013-01-13 01:03:15 +01:00
c23081e713 PEAR compile fix 2013-01-12 18:44:49 +01:00
2ba2116498 Alpha_1.0.6!! 2013-01-12 18:10:58 +01:00
07ac028558 Fixed a mini memory leak 2013-01-12 18:06:31 +01:00
7e4692aaf1 Correct block drop 2013-01-12 17:43:48 +01:00
baec22208f Updated event names 2013-01-12 17:35:32 +01:00
62a7461bbd Fixed #53 correct door hinge placing for double doors 2013-01-12 17:30:26 +01:00
4df7aed15d Fixed some events 2013-01-12 17:15:59 +01:00
d733eb6b4a Added more Events and Handlers 2013-01-12 17:01:20 +01:00
e4d71949e3 Fixed #39 placing blocks inside an entity 2013-01-12 16:47:12 +01:00
4bda101ab8 Added Entity speed, removed falling damage 2013-01-12 16:03:42 +01:00
b74c089ce7 Fixed #24 event duplication
Found 2 PHP bugs with this Commit
2013-01-12 14:22:57 +01:00
02950474af Improved Chat API 2013-01-12 12:25:27 +01:00
b398b9daa2 Deleted documentation 2013-01-12 11:01:34 +01:00
b2731261e5 Merge pull request #51 from sekjun9878/master
Added chat() function in ChatAPI. Also PlayerAPI Documentation
2013-01-12 02:00:22 -08:00
03c8c91b46 Changed info 2013-01-12 10:07:17 +01:00
13f4f3285f Re-fixed #45 and other bugs 2013-01-12 10:05:27 +01:00
8bc115a2ab Remove XML dependency 2013-01-12 00:40:54 +01:00
2665dffdd8 Show External IP 2013-01-11 15:08:02 +01:00
ab2b519c2e Entity despawning memory leak fixed #45 2013-01-11 15:06:24 +01:00
6ab08020c3 Online players broadcast when >= 2 players. fixes #48 2013-01-11 14:19:02 +01:00
107d71f291 Updated TEST_MD5 2013-01-11 14:16:12 +01:00
09c2c1b2ee Changed chat to send. Documentation included 2013-01-11 21:34:21 +09:00
f3e9d4df31 New Documentation for PlayerAPI - Alpha 2013-01-11 11:56:34 +09:00
d86bf37def Added and Fixed chat function in chat API. Tested 2013-01-11 11:25:42 +09:00
5753db627c Added chat API to ChatAPI.php 2013-01-11 11:09:57 +09:00
6102efc809 Fixed Memory Leak 2013-01-11 00:20:13 +01:00
8d3ad0c5ec Changing code parts [Hey! Don't look here!] 2013-01-10 23:59:03 +01:00
eebbc263b0 TickLoop thread 2013-01-10 17:10:15 +01:00
d5d319fb7c Fixed function name 2013-01-09 23:21:37 +01:00
03db7c8738 Compile script without Root access 2013-01-09 20:29:42 +01:00
2801f18753 Fixed entity despawning 2013-01-09 18:05:25 +01:00
b9b0039cd7 More events 2013-01-09 18:05:12 +01:00
cd3aaa1b50 New compile script 2013-01-09 14:44:33 +01:00
902cee1107 Debug event 2013-01-09 14:44:25 +01:00
ab5481a392 UPnP class error fix 2013-01-08 20:55:39 +01:00
f11bc82b86 removed PocketMinecraftServer stdClass 2013-01-08 16:38:35 +01:00
0cd8479026 Fixed #38 Debian install script 2013-01-08 16:38:20 +01:00
90d9099b3c Added Iron Doors 2013-01-07 16:02:23 +01:00
47e80151e6 Removed info 2013-01-07 11:06:39 +01:00
19aa4bd527 Allow console parameters 2013-01-07 01:58:15 +01:00
a6ddba8d97 Fixed "forwading" typo 2013-01-07 00:48:06 +01:00
3a110bf8b6 Error dump 2013-01-06 22:51:17 +01:00
18bab3b045 Fixed placing blocks on TNT 2013-01-06 21:25:09 +01:00
89c0702a47 Added optional Windows UPnP port forwading 2013-01-06 21:19:39 +01:00
21594d699d Fake explosions! 2013-01-06 17:31:28 +01:00
63 changed files with 3533 additions and 1402 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ logs/*
server.properties
white-list.txt
banned-ips.txt
banned.txt
#################
## Eclipse

View File

@ -25,15 +25,11 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("src/common/dependencies.php");
require_once("classes/PocketMinecraftServer.class.php");
require_once(dirname(__FILE__)."/src/common/dependencies.php");
require_once("API/ServerAPI.php");
$server = new ServerAPI();
if($server->start() !== true){
//Stop
}else{
//Restart
}
$server->run();//$server->start();
//$server->join();
kill(getmypid()); //Fix for segfault

View File

@ -1,3 +1,7 @@
![](http://shoghicp.github.com/PocketMine-MP/favicon.png)
# PocketMine-MP
```
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
@ -11,49 +15,35 @@ 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/>.
```
-
/ \
/ \
/ 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.
__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)
### [Homepage](http://www.pocketmine.org/)
[FAQ: Frequently Asked Questions](https://github.com/shoghicp/PocketMine-MP/wiki/Frequently-Asked-Questions)
### [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)
## Current features of the server:
### [Twitter @PocketMine](https://twitter.com/PocketMine)
* Full Creative mode!
* Plugin API
* Custom world generation
* Update Channels!! (stable / dev)
### [Mailing List](https://groups.google.com/forum/#!forum/pocketmine-development) pocketmine-development@googlegroups.com
## 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)
* __[PHP GMP](http://php.net/manual/en/book.gmp.php)__
* __[PHP Zlib](http://php.net/manual/en/book.zlib.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
* __[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.
* __[ANSICON](https://github.com/adoxa/ansicon)__ by _[Jason Hood](https://github.com/adoxa)_: Process ANSI escape sequences for Windows console programs.
## IRC #mcpedevs @ irc.freenode.net
* [WebIRC](http://webchat.freenode.net?channels=mcpedevs&uio=d4)

View File

@ -1,75 +1,166 @@
#!/bin/bash
echo "[INFO] PocketMine-MP PHP compiler for Linux - by @shoghicp v0.1"
if [ "$(whoami)" != 'root' ]; then
echo "[ERROR] You must be root to run this script"
exit 1;
fi
COMPILER_VERSION="0.7"
PHP_VERSION="5.4.11"
ZEND_VM="GOTO"
ZLIB_VERSION="1.2.7"
GMP_VERSION="5.1.0"
PTHREADS_VERSION="e4700122a89bf759a9c3a024bda0c7d025bcb93d"
CURL_VERSION="curl-7_28_1"
#READLINE_VERSION="6.2"
echo "[PocketMine] PHP installer and compiler for Linux - by @shoghicp v$COMPILER_VERSION"
DIR=`pwd`
mkdir -m 0777 install_data
mkdir -m 0777 php5
date > $DIR/install.log 2>&1
uname -a >> $DIR/install.log 2>&1
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
apt-get -f -y install
apt-get -y install \
php5-cli \
php5-common \
php5-curl \
php5-gd \
php5-gmp \
php5-mcrypt \
build-essential \
git-core \
libxml2-dev \
libcurl4-openssl-dev \
libjpeg-dev \
libpng-dev \
libmysqlclient-dev \
libfreetype6-dev \
libmcrypt-dev \
libmhash-dev
wget ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.0.tar.bz2 -O gmp-5.1.0.tar.bz2
tar -jxvf gmp-5.1.0.tar.bz2
cd gmp-5.1.0
./configure
make
make check
make install
wget http://php.net/get/php-5.4.10.tar.gz/from/this/mirror -O php-5.4.10.tar.gz
tar -zxvf php-5.4.10.tar.gz
cd php-5.4.10
cd ext
git clone https://github.com/krakjoe/pthreads.git
cd ../
./buildconf --force
./configure --prefix=$DIR/php5 \
set -e
#PHP 5
echo -n "[PHP5] downloading $PHP_VERSION..."
wget http://php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror -q -O - | tar -zx >> $DIR/install.log 2>&1
mv php-$PHP_VERSION php
echo " done!"
#zlib
echo -n "[zlib] downloading $ZLIB_VERSION..."
wget http://zlib.net/zlib-$ZLIB_VERSION.tar.gz -q -O - | tar -zx >> $DIR/install.log 2>&1
mv zlib-$ZLIB_VERSION zlib
echo -n " checking..."
cd zlib
./configure --prefix=$DIR/install_data/php/ext/zlib \
--static >> $DIR/install.log 2>&1
echo -n " compiling..."
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!"
#Readline
#echo -n "[Readline] downloading $READLINE_VERSION..."
#wget ftp://ftp.cwru.edu/pub/bash/readline-$READLINE_VERSION.tar.gz -q -O - | tar -xz >> $DIR/install.log 2>&1
#mv readline-$READLINE_VERSION readline
#echo -n " checking..."
#cd readline
#./configure --prefix=$DIR/install_data/php/ext/readline \
#--disable-shared >> $DIR/install.log 2>&1
#echo -n " compiling..."
#make >> $DIR/install.log 2>&1
#echo -n " installing..."
#make install >> $DIR/install.log 2>&1
#echo -n " cleaning..."
#cd ..
#rm -r -f ./readine
#echo " done!"
#--with-readline=$DIR/install_data/php/ext/readline
#GMP
echo -n "[GMP] downloading $GMP_VERSION..."
wget ftp://ftp.gmplib.org/pub/gmp-$GMP_VERSION/gmp-$GMP_VERSION.tar.bz2 -q -O - | tar -xj >> $DIR/install.log 2>&1
mv gmp-$GMP_VERSION gmp
echo -n " checking..."
cd gmp
./configure --prefix=$DIR/install_data/php/ext/gmp \
--disable-shared >> $DIR/install.log 2>&1
echo -n " compiling..."
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 $CURL_VERSION..."
wget https://github.com/bagder/curl/archive/$CURL_VERSION.tar.gz --no-check-certificate -q -O - | tar -zx >> $DIR/install.log 2>&1
mv curl-$CURL_VERSION curl
echo -n " checking..."
cd curl
./buildconf >> $DIR/install.log 2>&1
./configure --prefix=$DIR/install_data/php/ext/curl \
--disable-shared >> $DIR/install.log 2>&1
echo -n " compiling..."
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 $PTHREADS_VERSION..."
wget https://github.com/krakjoe/pthreads/archive/$PTHREADS_VERSION.tar.gz --no-check-certificate -q -O - | tar -zx >> $DIR/install.log 2>&1
mv pthreads-$PTHREADS_VERSION $DIR/install_data/php/ext/pthreads
echo " done!"
set +e
echo -n "[PHP5] checking..."
if which free >/dev/null; then
MAX_MEMORY=$(free -m | awk '/^Mem:/{print $2}')
else
MAX_MEMORY=$(top -l 1 | grep PhysMem: | awk '{print $10}' | tr -d 'a-zA-Z')
fi
if [ $MAX_MEMORY -gt 2048 ]
then
echo -n " enabling optimizations..."
OPTIMIZATION="--enable-inline-optimization "
else
OPTIMIZATION=""
fi
set -e
cd php
./buildconf --force >> $DIR/install.log 2>&1
./configure $OPTIMIZATION--prefix=$DIR/php5 \
--exec-prefix=$DIR/php5 \
--enable-embedded-mysqli \
--with-openssl \
--with-mcrypt \
--with-mhash \
--enable-exif \
--with-freetype-dir \
--enable-calendar \
--enable-soap \
--enable-mbstring \
--enable-bcmath \
--enable-gd-native-ttf \
--with-gmp \
--with-curl \
--enable-zip \
--with-gd \
--with-jpeg-dir \
--with-png-dir \
--with-mysql \
--with-mcrypt \
--with-zlib \
--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-libxml \
--disable-xml \
--disable-dom \
--disable-simplexml \
--disable-xmlreader \
--disable-xmlwriter \
--without-pear \
--disable-cgi \
--disable-session \
--enable-ctype \
--without-iconv \
--without-pdo-sqlite \
--enable-sockets \
--enable-shared=no \
--enable-static=yes \
--enable-pcntl \
--enable-pthreads \
--enable-maintainer-zts \
--enable-cli
make
echo "n" | make test
make install
--enable-zend-signals \
--with-zend-vm=$ZEND_VM \
--enable-cli >> $DIR/install.log 2>&1
echo -n " compiling..."
make >> $DIR/install.log 2>&1
echo -n " installing..."
make install >> $DIR/install.log 2>&1
echo " done!"
cd $DIR
rm -r -f install_data/
rmdir install_data/
echo "[INFO] Compilation Completed!"
echo -n "[INFO] Cleaning up..."
rm -r -f install_data/ >> $DIR/install.log 2>&1
date >> $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"

220
src/API/BanAPI.php Normal file
View File

@ -0,0 +1,220 @@
<?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 BanAPI{
private $server;
private $whitelist;
private $banned;
private $bannedIPs;
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function init(){
console("[INFO] Loading authentication lists...");
$this->whitelist = new Config(FILE_PATH."white-list.txt", CONFIG_LIST);
$this->bannedIPs = new Config(FILE_PATH."banned-ips.txt", CONFIG_LIST);
$this->banned = new Config(FILE_PATH."banned.txt", CONFIG_LIST);
$this->server->api->console->register("banip", "Manages IP Banning", array($this, "commandHandler"));
$this->server->api->console->register("ban", "Manages Bannning", array($this, "commandHandler"));
$this->server->api->console->register("kick", "Kicks a player", array($this, "commandHandler"));
$this->server->api->console->register("whitelist", "Manages White-listing", array($this, "commandHandler"));
}
public function commandHandler($cmd, $params){
switch($cmd){
case "kick":
if(!isset($params[0])){
console("[INFO] Usage: /kick <playername> [reason]");
}else{
$name = array_shift($params);
$player = $this->server->api->player->get($name);
if($player === false){
console("[ERROR] Player \"".$name."\" does not exist");
}else{
$reason = implode(" ", $params);
$reason = $reason == "" ? "No reason":$reason;
$player->close("You have been kicked: ".$reason);
console("[INFO] Player \"".$player->username."\" has been kicked: $reason");
}
}
break;
case "whitelist":
$p = strtolower(array_shift($params));
switch($p){
case "remove":
$user = trim(implode(" ", $params));
$this->whitelist->remove($user);
$this->whitelist->save();
console("[INFO] Player \"$user\" removed from white-list");
break;
case "add":
$user = trim(implode(" ", $params));
$this->whitelist->set($user);
$this->whitelist->save();
console("[INFO] Player \"$user\" added to white-list");
break;
case "reload":
$this->whitelist = $this->load(FILE_PATH."white-list.txt", CONFIG_LIST);
break;
case "list":
console("[INFO] White-list: ".implode(", ", $this->whitelist->getAll(true)));
break;
case "on":
case "true":
case "1":
console("[INFO] White-list turned on");
$this->server->api->setProperty("white-list", true);
break;
case "off":
case "false":
case "0":
console("[INFO] White-list turned off");
$this->server->api->setProperty("white-list", false);
break;
default:
console("[INFO] Usage: /whitelist <on | off | add | remove | reload | list> [username]");
break;
}
break;
case "banip":
$p = strtolower(array_shift($params));
switch($p){
case "pardon":
case "remove":
$ip = trim(implode($params));
$this->bannedIPs->remove($ip);
$this->bannedIPs->save();
console("[INFO] IP \"$ip\" removed from ban list");
break;
case "add":
case "ban":
$ip = trim(implode($params));
$this->bannedIPs->set($ip);
$this->bannedIPs->save();
console("[INFO] IP \"$ip\" added to ban list");
break;
case "reload":
$this->bannedIPs = new Config(FILE_PATH."banned-ips.txt", CONFIG_LIST);
break;
case "list":
console("[INFO] IP ban list: ".implode(", ", $this->bannedIPs->getAll(true)));
break;
default:
console("[INFO] Usage: /banip <add | remove | list | reload> [IP]");
break;
}
break;
case "ban":
$p = strtolower(array_shift($params));
switch($p){
case "pardon":
case "remove":
$user = trim(implode($params));
$this->banned->remove($user);
$this->banned->save();
console("[INFO] Player \"$user\" removed from ban list");
break;
case "add":
case "ban":
$user = trim(implode($params));
$this->banned->set($user);
$this->banned->save();
$player = $this->server->api->player->get($user);
if($player !== false){
$player->close("You have been banned");
}
$this->server->api->chat->broadcast("$user has been banned");
console("[INFO] Player \"$user\" added to ban list");
break;
case "reload":
$this->banned = new Config(FILE_PATH."banned.txt", CONFIG_LIST);
break;
case "list":
console("[INFO] Ban list: ".implode(", ", $this->banned->getAll(true)));
break;
default:
console("[INFO] Usage: /ban <add | remove | list | reload> [player]");
break;
}
break;
}
}
public function ban($username){
$this->commandHandler("ban", array("add", $username));
}
public function pardon($username){
$this->commandHandler("ban", array("pardon", $username));
}
public function banIP($ip){
$this->commandHandler("banip", array("add", $ip));
}
public function pardonIP($ip){
$this->commandHandler("banip", array("pardon", $ip));
}
public function kick($username, $reason){
$this->commandHandler("kick", array($username, $reason));
}
public function reload(){
$this->commandHandler("ban", array("reload"));
$this->commandHandler("banip", array("reload"));
$this->commandHandler("whitelist", array("reload"));
}
public function isIPBanned($ip){
if($this->server->api->dhandle("api.ban.ip.check", $ip) === false){
return true;
}elseif($this->bannedIPs->exists($ip)){
return true;
}
return false;
}
public function isBanned($username){
if($this->server->api->dhandle("api.ban.check", $username) === false){
return true;
}elseif($this->banned->exists($username)){
return true;
}
return false;
}
public function inWhitelist($username){
if($this->server->api->dhandle("api.ban.whitelist.check", $ip) === false){
return true;
}elseif($this->whitelist->exists($username)){
return true;
}
return false;
}
}

View File

@ -39,7 +39,7 @@ class BlockAPI{
}
public function init(){
$this->server->addHandler("world.block.update", array($this, "updateBlockRemote"), 1);
$this->server->addHandler("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"));
@ -66,7 +66,7 @@ class BlockAPI{
$amount = (int) $params[2];
}
if(isset($params[3])){
$meta = (int) $params[3];
$meta = ((int) $params[3]) & 0xFFFF;
}
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);
@ -80,7 +80,7 @@ class BlockAPI{
}
private function cancelAction($block){
$this->server->api->dhandle("world.block.change", array(
$this->server->api->dhandle("block.change", array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2],
@ -105,15 +105,39 @@ 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:
case 114:
case 128:
case 156:
$drop[1] = 0;
break;
case 56:
$drop = array(264, 0, 1);
break;
case 63:
case 68:
$drop = array(323, 0, 1);
break;
case 73:
case 74:
$drop = array(351, 4, mt_rand(4, 5));
@ -160,22 +184,34 @@ 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);
}
}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);
@ -209,6 +245,9 @@ class BlockAPI{
$data["stack"] = min(64, $count);
$count -= $data["stack"];
$e = $this->server->api->entity->add(ENTITY_ITEM, $block, $data);
//$e->speedX = mt_rand(-10, 10) / 100;
//$e->speedY = mt_rand(0, 5) / 100;
//$e->speedZ = mt_rand(-10, 10) / 100;
$this->server->api->entity->spawnToAll($e->eid);
}
}
@ -221,6 +260,7 @@ class BlockAPI{
if($data["face"] < 0 or $data["face"] > 5){
return false;
}
$data["original"] = array($data["block"], $data["meta"]);
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
if($target[0] === 0){ //If no block exists
$this->cancelAction($target);
@ -232,6 +272,7 @@ class BlockAPI{
if(isset(Material::$activable[$target[0]])){
switch($target[0]){
case 54:
$cancelPlace = true;
if($this->server->gamemode === 1){
break;
}
@ -244,6 +285,7 @@ class BlockAPI{
break;
case 61:
case 62:
$cancelPlace = true;
if($this->server->gamemode === 1){
break;
}
@ -261,13 +303,37 @@ class BlockAPI{
}
break;
case 2:
if($target[0] === 2 and $data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
for($c = 0; $c < 15; ++$c){
$x = mt_rand($target[2][0] - 2, $target[2][0] + 2);
$z = mt_rand($target[2][2] - 2, $target[2][2] + 2);
$b = $this->server->api->level->getBlock($x, $target[2][1] + 1, $z);
$d = $this->server->api->level->getBlock($x, $target[2][1], $z);
if($b[0] === 0 and $d[0] === 2){
$arr = array(
array(37, 0),
array(38, 0),
array(31, 1),
array(31, 1),
array(31, 1),
array(31, 1),
array(0, 0),
);
$t = $arr[mt_rand(0, count($arr) - 1)];
$this->server->api->level->setBlock($x, $target[2][1] + 1, $z, $t[0], $t[1]);
}
}
$cancelPlace = true;
break;
}
case 3:
if($data["block"] === 292){ //Hoe
$data["block"] = 60;
$data["meta"] = 0;
$this->server->handle("player.block.place", $data);
$this->server->handle("player.block.update", $data);
$cancelPlace = true;
}
break;
case 59:
case 105:
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
@ -328,15 +394,37 @@ class BlockAPI{
}
$replace = false;
switch($target[0]){
switch($data["block"]){
case 44: //Slabs
if($data["face"] !== 1){
break;
}
if(($target[1] & 0x07) === ($data["meta"] & 0x07)){
$replace = true;
$data["block"] = 43;
$data["meta"] = $data["meta"] & 0x07;
if($data["face"] === 0){
if($target[0] === 44 and ($target[1] & 0x08) === 0x08 and ($target[1] & 0x07) === ($data["meta"] & 0x07)){
$replace = true;
$data["block"] = 43;
$data["meta"] = $data["meta"] & 0x07;
}else{
$data["meta"] |= 0x08;
}
}elseif($data["face"] === 1){
if($target[0] === 44 and ($target[1] & 0x08) === 0 and ($target[1] & 0x07) === ($data["meta"] & 0x07)){
$replace = true;
$data["block"] = 43;
$data["meta"] = $data["meta"] & 0x07;
}
}else{
$data2 = $data;
BlockFace::setPosition($data2, $data["face"]);
$b = $this->server->api->level->getBlock($data2["x"], $data2["y"], $data2["z"]);
if($b[0] === 44 and ($b[1] & 0x07) === ($data["meta"] & 0x07)){
$data = $data2;
$replace = true;
$data["block"] = 43;
$data["meta"] = $data["meta"] & 0x07;
}else{
$data["meta"] = $data["meta"] & 0x07;
if($data["fy"] > 0.5){
$data["meta"] |= 0x08;
}
}
}
break;
}
@ -360,8 +448,16 @@ class BlockAPI{
}else{
return $this->cancelAction($block);
}
$entity = $this->server->api->entity->get($data["eid"]);
if(($entity instanceof Entity) !== true){
return $this->cancelAction($block); //No Entity WTF?
}
if(!isset(Material::$transparent[$data["block"]]) and $entity->inBlock($block[2][0], $block[2][1], $block[2][2])){
return $this->cancelAction($block); //Entity in block
}
$direction = $this->server->api->entity->get($data["eid"])->getDirection();
$direction = $entity->getDirection();
switch($data["block"]){
case 6:
@ -416,6 +512,10 @@ class BlockAPI{
case 53://Stairs
case 67:
case 108:
case 109:
case 114:
case 128:
case 156:
$faces = array(
0 => 0,
1 => 2,
@ -423,6 +523,9 @@ class BlockAPI{
3 => 3,
);
$data["meta"] = $faces[$direction] & 0x03;
if(($data["y"] - 1) > $entity->y){
$data["meta"] |= 0x04; //Upside-down stairs
}
break;
case 96: //trapdoor
if(isset(Material::$transparent[$target[0]])){
@ -449,6 +552,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]])){
@ -457,6 +564,16 @@ 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->handle("player.block.place", $data2);
}
@ -523,6 +640,29 @@ class BlockAPI{
return false;
}
break;
case 323: //Signs
$faces = array(
2 => 2,
3 => 3,
4 => 4,
5 => 5,
);
if(!isset($faces[$data["face"]])){
if($data["face"] === 1){
$data["block"] = 63;
$data["meta"] = 0;
$t = $this->server->api->tileentity->addSign($data["x"], $data["y"], $data["z"]);
$t->data["creator"] = $entity->player->username;
}else{
return false;
}
}else{
$data["block"] = 68;
$data["meta"] = $faces[$data["face"]];
$t = $this->server->api->tileentity->addSign($data["x"], $data["y"], $data["z"]);
$t->data["creator"] = $entity->player->username;
}
break;
}
$this->server->handle("player.block.place", $data);
return false;
@ -533,7 +673,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);
@ -562,6 +702,15 @@ class BlockAPI{
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
return true;
}
}elseif($spread[0] === 9 or $spread[0] === 8){
if($source[0] === 11){
$this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 49, 0);
}elseif($face === 0){
$this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 1, 0);
}else{
$this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 4, 0);
}
return true;
}elseif(isset(Material::$flowable[$spread[0]])){
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
@ -578,7 +727,7 @@ class BlockAPI{
return false;
}
public function flowWaterOn($source, $face){
public function flowWaterOn($source, $face, &$spread = null){
$down = 0;
if($face === BlockFace::BOTTOM){
$level = 0;
@ -601,6 +750,14 @@ class BlockAPI{
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
return true;
}
}elseif($spread[0] === 11){
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 49, 0, true);
return true;
}elseif($spread[0] === 10){
if($face === 0 or ($spread[1] & 0x08) === 0){
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 4, 0, true);
return true;
}
}elseif(isset(Material::$flowable[$spread[0]])){
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
@ -624,13 +781,34 @@ class BlockAPI{
switch($block[0]){
case 8:
case 9:
if(!$this->flowWaterOn($block, 0) or $block[0] === 9){
$this->flowWaterOn($block, 2);
$this->flowWaterOn($block, 3);
$this->flowWaterOn($block, 4);
$this->flowWaterOn($block, 5);
$faces = array();
if(!$this->flowWaterOn($block, 0, $floor) or $block[0] === 9){
$this->flowWaterOn($block, 2, $faces[0]);
$this->flowWaterOn($block, 3, $faces[1]);
$this->flowWaterOn($block, 4, $faces[2]);
$this->flowWaterOn($block, 5, $faces[3]);
}
if($block[0] === 8){
//Source creation
if(!isset(Material::$flowable[$floor[0]])){
$sources = 0;
foreach($faces as $i => $b){
if($b[0] === 9){
++$sources;
}
}
if($sources >= 2){
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 9, 0, false);
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
break;
}
}
$drained = true;
$level = $block[1] & 0x07;
$up = $this->server->api->level->getBlockFace($block, BlockFace::UP);

View File

@ -26,6 +26,26 @@ the Free Software Foundation, either version 3 of the License, or
*/
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));
}
}

View File

@ -49,6 +49,11 @@ class ConsoleAPI{
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){
@ -71,6 +76,7 @@ class ConsoleAPI{
break;
case "status":
case "lag":
$this->server->debugInfo(true);
$info = $this->server->debugInfo();
console("[INFO] TPS: ".$info["tps"].", Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"].")");
break;
@ -82,46 +88,6 @@ class ConsoleAPI{
console("[INFO] Stopping the server...");
$this->server->close();
break;
/*case "restart":
console("[INFO] Restarting the server...");
$this->server->api->restart = true;
$this->server->close();
break;*/
case "banip":
$p = strtolower(array_shift($params));
switch($p){
case "pardon":
case "remove":
$ip = trim(implode($params));
$new = array();
foreach(explode("\n", str_replace(array("\r","\t"), "", file_get_contents(FILE_PATH."banned-ips.txt"))) as $i){
if($i == $ip){
console("[INFO] IP \"$ip\" removed from ban list");
continue;
}
$new[$i] = $i;
}
file_put_contents(FILE_PATH."banned-ips.txt", implode("\r\n", $new));
$this->server->reloadConfig();
break;
case "add":
case "ban":
$ip = trim(implode($params));
file_put_contents(FILE_PATH."banned-ips.txt", "\r\n".$ip, FILE_APPEND);
console("[INFO] IP \"$ip\" added to ban list");
$this->server->reloadConfig();
break;
case "reload":
$this->server->reloadConfig();
break;
case "list":
console("[INFO] IP ban list: ".implode(", ", explode("\n", str_replace(array("\t","\r"), "", file_get_contents(FILE_PATH."banned-ips.txt")))));
break;
default:
console("[INFO] Usage: /banip <add | remove | list | reload> [IP]");
break;
}
break;
case "gamemode":
$s = trim(array_shift($params));
if($s == "" or (((int) $s) !== 0 and ((int) $s) !== 1)){
@ -147,62 +113,11 @@ class ConsoleAPI{
console("[INFO] Usage: /say <message>");
break;
}
$this->server->chat(false, $s);
break;
case "whitelist":
$p = strtolower(array_shift($params));
switch($p){
case "remove":
$user = trim(implode(" ", $params));
$new = array();
foreach(explode("\n", str_replace(array("\r","\t"), "", file_get_contents(FILE_PATH."white-list.txt"))) as $u){
if($u == $user){
console("[INFO] Player \"$user\" removed from white-list");
continue;
}
$new[$u] = $u;
}
file_put_contents(FILE_PATH."white-list.txt", implode("\r\n", $new));
$this->server->reloadConfig();
break;
case "add":
$user = trim(implode(" ", $params));
file_put_contents(FILE_PATH."white-list.txt", "\r\n".$user, FILE_APPEND);
console("[INFO] Player \"$user\" added to white-list");
$this->server->reloadConfig();
break;
case "reload":
$this->server->reloadConfig();
break;
case "list":
console("[INFO] White-list: ".implode(", ", explode("\n", str_replace(array("\t","\r"), "", file_get_contents(FILE_PATH."white-list.txt")))));
break;
case "on":
case "true":
case "1":
console("[INFO] White-list turned on");
$this->server->api->setProperty("white-list", true);
break;
case "off":
case "false":
case "0":
console("[INFO] White-list turned off");
$this->server->api->setProperty("white-list", false);
break;
default:
console("[INFO] Usage: /whitelist <on | off | add | remove | reload | list> [username]");
break;
}
$this->server->api->chat->broadcast($s);
break;
case "save-all":
$this->server->save();
break;
case "block":
foreach($this->server->clients as $client){
$b = $this->server->map->getBlock(round($client->entity->position["x"] - 0.5), round($client->entity->position["y"] - 1), round($client->entity->position["z"] - 0.5));
console("[INFO] EID ".$client->eid." is over block ".$b[0].":".$b[1]);
}
break;
case "help":
case "?":
console("[INFO] /help: Show available commands");
@ -212,8 +127,6 @@ class ConsoleAPI{
console("[INFO] /invisible: Manages server visibility");
console("[INFO] /say: Broadcasts mesages");
console("[INFO] /save-all: Saves pending changes");
console("[INFO] /whitelist: Manages whitelisting");
console("[INFO] /banip: Manages IP ban");
console("[INFO] /stop: Stops the server");
//console("[INFO] /restart: Restarts the server");
foreach($this->help as $c => $h){
@ -227,7 +140,11 @@ class ConsoleAPI{
}
public function alias($alias, $cmd){
if(!isset($this->cmds[$cmd])){
return false;
}
$this->cmds[strtolower(trim($alias))] = &$this->cmds[$cmd];
return true;
}
public function register($cmd, $help, $callback){
@ -238,21 +155,25 @@ class ConsoleAPI{
$this->cmds[$cmd] = $callback;
$this->help[$cmd] = $help;
}
public function run($line = ""){
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);
}
}
}
public function handle($time){
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);
}
}
$this->run($line);
}else{
$this->loop->notify();
}
@ -261,7 +182,12 @@ class ConsoleAPI{
}
class ConsoleLoop extends Thread{
var $line = false, $stop = false;
public $line, $stop;
public function __construct(){
$this->line = false;
$this->stop = false;
}
public function run(){
$fp = fopen("php://stdin", "r");
while($this->stop === false and ($line = fgets($fp)) !== false){

View File

@ -31,42 +31,16 @@ class EntityAPI{
$this->server = $server;
}
public function init(){
$this->server->addHandler("player.death", array($this, "handle"), 1);
}
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 get($eid){
if(isset($this->server->entities[$eid])){
return $this->server->entities[$eid];
}
return false;
}
public function init(){
}
public function getAll(){
return $this->server->entities;
@ -76,17 +50,18 @@ class EntityAPI{
$this->harm($eid, -$heal, $cause);
}
public function harm($eid, $attack = 1, $cause){
public function harm($eid, $attack = 1, $cause, $force = false){
$e = $this->get($eid);
if($e === false or $e->dead === true){
return false;
}
$e->setHealth($e->getHealth()-$attack, $cause);
$e->setHealth($e->getHealth() - $attack, $cause, $force);
}
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];
}
@ -118,8 +93,14 @@ class EntityAPI{
public function remove($eid){
if(isset($this->server->entities[$eid])){
$this->server->entities[$eid]->close();
$entity = $this->server->entities[$eid];
$this->server->entities[$eid] = null;
unset($this->server->entities[$eid]);
$entity->closed = true;
$this->server->query("DELETE FROM entities WHERE EID = ".$entity->eid.";");
$this->server->api->dhandle("entity.remove", $entity);
$entity = null;
unset($entity);
}
}
}

View File

@ -49,11 +49,10 @@ class LevelAPI{
case "player.block.break":
$block = $this->getBlock($data["x"], $data["y"], $data["z"]);
console("[DEBUG] EID ".$data["eid"]." broke ".$block[0].":".$block[1]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
if($block[0] === 0){
break;
}
$this->setBlock($data["x"], $data["y"], $data["z"], 0, 0);
$this->setBlock($data["x"], $data["y"], $data["z"], 0, 0, true, true);
break;
}
}
@ -85,21 +84,30 @@ class LevelAPI{
return $this->heightMap[$z][$x];
}
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);
if($this->server->api->dhandle("world.block.change", array(
public function setBlock($x, $y, $z, $block, $meta = 0, $update = true, $tiles = false){
if($x < 0 or $y < 0 or $z < 0){
return false;
}
if($this->server->api->dhandle("block.change", array(
"x" => $x,
"y" => $y,
"z" => $z,
"block" => $block,
"meta" => $meta,
)) !== false){
$this->map->setBlock($x, $y, $z, $block, $meta);
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z);
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);
}
if($tiles === true){
if(($t = $this->server->api->tileentity->get($x, $y, $z)) !== false){
$t[0]->close();
}
}
}
return true;
}
public function getOrderedChunk($X, $Z, $columnsPerPacket = 2){

View File

@ -32,9 +32,11 @@ 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("harm", "Harms a player", array($this, "commandHandler"));
$this->server->api->console->register("tppos", "Teleports a player to a position", array($this, "commandHandler"));
$this->server->api->console->register("tp", "Teleports a player to another player", array($this, "commandHandler"));
}
@ -45,12 +47,57 @@ class PlayerAPI{
$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())){
if(($player = $this->server->api->player->getByEID($player["EID"])) !== false){
$player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration");
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
if($player->dead === true){
continue;
}
$player->setHealth(min(20, $player->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"]){
case "cactus":
$message .= " was pricked to death";
break;
case "lava":
$message .= " tried to swim in lava";
break;
case "fire":
$message .= " went up in flames";
break;
case "burning":
$message .= " burned to death";
break;
case "suffocation":
$message .= " suffocated in a wall";
break;
case "water":
$message .= " drowned";
break;
case "void":
$message .= " fell out of the world";
break;
default:
$message .= " died";
break;
}
}
$this->server->chat(false, $message);
break;
}
}
@ -87,11 +134,20 @@ class PlayerAPI{
case "kill":
$player = $this->get(implode(" ", $params));
if($player !== false){
$this->server->api->entity->harm($player->eid, 20, "console");
$this->server->api->entity->harm($player->eid, 20, "console", true);
}else{
console("[INFO] Usage: /kill <player>");
}
break;
case "harm":
$dmg = (int) array_shift($params);
$player = $this->get(implode(" ", $params));
if($player !== false){
$this->server->api->entity->harm($player->eid, $dmg, "console", true);
}else{
console("[INFO] Usage: /harm <damage> <player>");
}
break;
case "list":
console("[INFO] Player list:");
foreach($this->server->clients as $c){
@ -171,7 +227,7 @@ class PlayerAPI{
public function add($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
console("[INFO] Player \"".$player->username."\" connected from ".$player->ip.":".$player->port);
console("[INFO] Player \"\x1b[33m".$player->username."\x1b[0m\" connected from \x1b[36m".$player->ip.":".$player->port."\x1b[0m");
$player->data = $this->getOffline($player->username);
$this->server->query("INSERT OR REPLACE INTO players (clientID, ip, port, name) VALUES (".$player->clientID.", '".$player->ip."', ".$player->port.", '".$player->username."');");
}
@ -180,13 +236,18 @@ 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();
}
$this->server->clients[$CID] = null;
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]);
if($player->entity instanceof Entity){
$player->entity->player = null;
$player->entity = null;
}
$this->server->api->entity->remove($player->eid);
$player = null;
unset($player);
}
}
@ -199,6 +260,8 @@ class PlayerAPI{
"y" => $this->server->spawn["y"],
"z" => $this->server->spawn["z"],
),
"inventory" => array_fill(0, 36, array(0, 0, 0)),
"armor" => array(0, 0, 0, 0),
"health" => 20,
"lastIP" => "",
"lastID" => 0,
@ -207,6 +270,9 @@ class PlayerAPI{
}else{
$data = unserialize(file_get_contents(FILE_PATH."players/".$name.".dat"));
}
if($this->server->gamemode === 1){
$data["health"] = 20;
}
$this->server->handle("api.player.offline.get", $data);
return $data;
}

View File

@ -26,11 +26,10 @@ the Free Software Foundation, either version 3 of the License, or
*/
class PluginAPI extends stdClass{
private $server, $plugins;
private $server;
private $plugins = array();
public function __construct(PocketMinecraftServer $server){
$this->server = $server;
$this->plugins = array();
require_once("classes/Spyc.class.php"); //YAML parser
}
public function getList(){
@ -77,7 +76,7 @@ class PluginAPI extends stdClass{
if(!isset($info["name"]) or !isset($info["version"]) or !isset($info["class"]) or !isset($info["author"])){
console("[ERROR] [PluginAPI] Failed parsing of ".basename($file));
}
console("[INFO] [PluginAPI] Loading plugin \"".$info["name"]."\" ".$info["version"]." by ".$info["author"]);
console("[INFO] [PluginAPI] Loading plugin \"\x1b[32m".$info["name"]."\x1b[0m\" \x1b[35m".$info["version"]."\x1b[0m by \x1b[36m".$info["author"]."\x1b[0m");
if(class_exists($info["class"])){
console("[ERROR] [PluginAPI] Failed loading plugin: class exists");
}
@ -86,11 +85,11 @@ class PluginAPI extends stdClass{
}
$className = trim($info["class"]);
if(isset($info["api"]) and $info["api"] !== true){
console("[NOTICE] [PluginAPI] Plugin \"".$info["name"]."\" got raw access to Server methods");
console("[NOTICE] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" got raw access to Server methods");
}
$object = new $className($this->server->api, ((isset($info["api"]) and $info["api"] !== true) ? $this->server:false));
if(!($object instanceof Plugin)){
console("[ERROR] [PluginAPI] Plugin \"".$info["name"]."\" doesn't use the Plugin Interface");
console("[ERROR] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" doesn't use the Plugin Interface");
if(method_exists($object, "__destruct")){
$object->__destruct();
}
@ -109,6 +108,16 @@ class PluginAPI extends stdClass{
}
return false;
}
public function configPath(Plugin $plugin){
$p = $this->get($plugin);
if($p === false){
return false;
}
$path = FILE_PATH."plugins/".$p[1]["name"]."/";
$this->plugins[$p[1]["class"]][1]["path"] = $path;
return $path;
}
public function createConfig(Plugin $plugin, $default = array()){
$p = $this->get($plugin);
@ -116,15 +125,10 @@ class PluginAPI extends stdClass{
return false;
}
$path = FILE_PATH."plugins/".$p[1]["name"]."/";
@mkdir($path);
$this->plugins[$p[1]["class"]][1]["path"] = $path;
if(!file_exists($path."config.yml")){
@mkdir($path, 0777);
$this->writeYAML($path."config.yml", $default);
}else{
$data = $this->readYAML($path."config.yml");
$this->fillDefaults($default, $data);
$this->writeYAML($path."config.yml", $data);
}
$cnf = new Config($path."config.yml", CONFIG_YAML, $default);
$cnf->save();
return $path;
}
@ -150,7 +154,8 @@ class PluginAPI extends stdClass{
}
public function init(){
$this->server->event("server.start", array($this, "loadAll"));
$this->server->event("server.start", array($this, "initAll"));
$this->loadAll();
}
public function loadAll(){
@ -163,10 +168,11 @@ class PluginAPI extends stdClass{
}
}
}
}
public function initAll(){
foreach($this->plugins as $p){
if(method_exists($p[0], "init")){
$p[0]->init();
}
$p[0]->init(); //ARGHHH!!! Plugin loading randomly fails!!
}
}
}

View File

@ -25,10 +25,18 @@ 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(){
private $server;
private $config;
private $apiList = array();
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);
@ -36,7 +44,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
console("[INFO] Starting ServerAPI server handler...");
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 integrity tests...");
console("[NOTICE] Executing tests...");
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
console("[INFO] uname -a: ".php_uname("a"));
console("[INFO] PHP Version: ".phpversion());
@ -59,40 +67,58 @@ 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."logs/test.bin.log", $test);
if(md5($test) !== TEST_MD5){
$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();
}
}
if(!file_exists(FILE_PATH."white-list.txt")){
console("[NOTICE] No white-list.txt found, creating blank file");
file_put_contents(FILE_PATH."white-list.txt", "");
}
if(!file_exists(FILE_PATH."banned-ips.txt")){
console("[NOTICE] No banned-ips.txt found, creating blank file");
file_put_contents(FILE_PATH."banned-ips.txt", "");
}
if(!file_exists(FILE_PATH."server.properties")){
console("[NOTICE] No server.properties found, using default settings");
copy(FILE_PATH."src/common/default.properties", FILE_PATH."server.properties");
}
console("[DEBUG] Loading server.properties...", true, true, 2);
$this->config = new Config(FILE_PATH . "server.properties", CONFIG_PROPERTIES, array(
"server-name" => "Minecraft Server",
"description" => "Server made using PocketMine-MP",
"motd" => "Welcome @username to this server!",
"invisible" => false,
"port" => 19132,
"memory-limit" => "256M",
"last-update" => false,
"update-channel" => "stable",
"white-list" => false,
"debug" => 2,
"max-players" => 20,
"server-type" => "normal",
"time-per-second" => 20,
"gamemode" => 1,
"difficulty" => 1,
"generator" => "",
"generator-settings" => "",
"level-name" => false,
"server-id" => false,
"upnp-forwarding" => false,
"send-usage" => true,
));
$this->parseProperties();
define("DEBUG", $this->config["debug"]);
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->setProperty("server-id", $this->server->serverID);
$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")));
console("[INFO] Last check: \x1b[36m".date("Y-m-d H:i:s", $this->getProperty("last-update"))."\x1b[0m");
$channel = "stable";
if($this->getProperty("update-channel") == "dev" or $this->getProperty("update-channel") == "development"){
$channel = "dev";
@ -107,13 +133,13 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
$last = new DateTime($info["updated_at"]);
$last = $last->getTimestamp();
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false){
console("[NOTICE] A new DEVELOPMENT version of PocketMine-MP has been released");
console("[NOTICE] If you want to update, get the latest version at https://github.com/shoghicp/PocketMine-MP/archive/master.zip");
console("[NOTICE] \x1b[33mA new DEVELOPMENT version of PocketMine-MP has been released");
console("[NOTICE] \x1b[36mIf you want to update, get the latest version at https://github.com/shoghicp/PocketMine-MP/archive/master.zip");
console("[NOTICE] This message will dissapear when you issue the command \"/update-done\"");
sleep(3);
}else{
$this->setProperty("last-update", time());
console("[INFO] This is the latest DEVELOPMENT version");
console("[INFO] \x1b[36mThis is the latest DEVELOPMENT version");
}
}
}else{
@ -134,14 +160,14 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
if($newest[0] !== -1){
$target = $info[$newest[0]];
console("[NOTICE] A new STABLE version of PocketMine-MP has been released");
console("[NOTICE] Version \"".(new VersionString($newest[1]))."\" #".$newest[1]." [".substr($target["commit"]["sha"], 0, 10)."]");
console("[NOTICE] \x1b[33mA new STABLE version of PocketMine-MP has been released");
console("[NOTICE] \x1b[36mVersion \"".(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());
console("[INFO] This is the latest STABLE version");
console("[INFO] \x1b[36mThis is the latest STABLE version");
}
}
@ -181,7 +207,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
while(false !== ($file = $dir->read())){
if($file{0} !== "."){ //Hidden and upwards folders
$API = basename($file, ".php");
if(strtolower($API) !== "serverapi"){
if(strtolower($API) !== "serverapi" and strtolower($API) !== "pluginapi"){
$name = strtolower(substr($API, 0, -3));
$this->loadAPI($name, $API);
}
@ -189,12 +215,27 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
}
foreach($this->apiList as $ob){
if(is_callable(array($ob, "init"))){
$ob->init();
$ob->init(); //Fails sometimes!!!
}
}
$this->loadAPI("plugin", "PluginAPI"); //fix :(
$this->plugin->init();
$this->server->loadEntities();
}
public function sendUsage(){
console("[INTERNAL] Sending usage data...", true, true, 3);
Utils::curl_post("http://www.pocketmine.org/usage.php", array(
"serverid" => $this->server->serverID,
"os" => Utils::getOS(),
"version" => MAJOR_VERSION,
"protocol" => CURRENT_PROTOCOL,
"online" => count($this->clients),
"max" => $this->maxClients,
));
}
public function __destruct(){
foreach($this->apiList as $ob){
@ -207,65 +248,39 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
private function loadProperties(){
if(isset($this->config["memory-limit"])){
@ini_set("memory_limit", $this->config["memory-limit"]);
if(($memory = $this->getProperty("memory-limit")) !== false){
$value = array("M" => 1, "G" => 1024);
$real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)];
if($real < 128){
console("[ERROR] PocketMine doesn't work right with less than 128MB of RAM", true, true, 0);
}
@ini_set("memory_limit", $memory);
}else{
$this->config["memory-limit"] = "256M";
$this->setProperty("memory-limit", "256M");
}
if(!isset($this->config["invisible"])){
$this->config["invisible"] = false;
if(!$this->config->exists("invisible")){
$this->config->set("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();
}
}
private function writeProperties(){
if(is_object($this->server)){
$this->config["server-id"] = $this->server->serverID;
}
$config = $this->config;
$config["white-list"] = $config["white-list"] === true ? "true":"false";
$config["invisible"] = $config["invisible"] === 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";
}
file_put_contents(FILE_PATH."server.properties", $prop);
$this->config->save();
}
private function parseProperties(){
$prop = file_get_contents(FILE_PATH."server.properties");
$prop = explode("\n", str_replace("\r", "", $prop));
$this->config = array();
foreach($prop as $line){
if(trim($line) == "" or $line{0} == "#"){
continue;
}
$d = explode("=", $line);
$n = strtolower(array_shift($d));
$v = implode("=", $d);
switch(strtolower(trim($v))){
case "on":
case "true":
case "yes":
$v = true;
break;
case "off":
case "false":
case "no":
$v = false;
break;
}
foreach($this->config->getAll() as $n => $v){
switch($n){
case "last-update":
if($v === false){
@ -288,15 +303,23 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
}
break;
}
$this->config[$n] = $v;
$this->config->set($n, $v);
}
}
public function start(){
public function init(){
if($this->getProperty("send-usage") !== false){
$this->server->schedule(36000, array($this, "sendUsage"), array(), true); //Send usage data every 30 minutes
$this->sendUsage();
}
$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;
}
@ -374,16 +397,54 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
}
return false;
}
public function getProperties(){
return $this->config->getAll();
}
public function getProperty($name){
if(isset($this->config[$name])){
return $this->config[$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;
}
return false;
return $this->config->get($name);
}
public function setProperty($name, $value){
$this->config[$name] = $value;
$this->config->set($name, $value);
$this->writeProperties();
$this->loadProperties();
}
@ -404,7 +465,7 @@ class ServerAPI extends stdClass{ //Yay! I can add anything to this class in run
require_once($file);
$this->$name = new $class($this->server);
$this->apiList[] = $this->$name;
console("[INFO] API ".$name." [".$class."] loaded");
console("[INFO] API \x1b[36m".$name."\x1b[0m [\x1b[30;1m".$class."\x1b[0m] loaded");
}
}

130
src/API/TileEntityAPI.php Normal file
View File

@ -0,0 +1,130 @@
<?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 TileEntityAPI{
private $server;
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function get($x, $y, $z){
$x = (int) $x;
$y = (int) $y;
$z = (int) $z;
$tiles = $this->server->query("SELECT * FROM tileentities WHERE x = $x AND y = $y AND z = $z;");
$ret = array();
if($tiles !== false and $tiles !== true){
while(($t = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){
if(($tile = $this->getByID($t["ID"])) !== false){
if($tile->normal === true){
$ret[] = $tile;
}
}
}
}
if(count($ret) === 0){
return false;
}
return $ret;
}
public function getByID($id){
if($id instanceof TileEntity){
return $id;
}elseif(isset($this->server->tileEntities[$id])){
return $this->server->tileEntities[$id];
}
return false;
}
public function init(){
}
public function getAll(){
return $this->server->tileEntities;
}
public function add($class, $x, $y, $z, $data = array()){
$id = $this->tCnt++;
$this->server->tileEntities[$id] = new TileEntity($this->server, $id, $class, $x, $y, $z, $data);
$this->spawnToAll($id);
return $this->server->tileEntities[$id];
}
public function addSign($x, $y, $z, $lines = array("", "", "", "")){
return $this->add(TILE_SIGN, $x, $y, $z, $data = array(
"id" => "Sign",
"x" => $x,
"y" => $y,
"z" => $z,
"Text1" => $lines[0],
"Text2" => $lines[1],
"Text3" => $lines[2],
"Text4" => $lines[3],
));
}
public function spawnTo($id, $player, $queue = false){
$t = $this->getByID($id);
if($t === false){
return false;
}
$t->spawn($player, $queue);
}
public function spawnToAll($id){
$t = $this->getByID($id);
if($t === false){
return false;
}
foreach($this->server->api->player->getAll() as $player){
if($player->eid !== false){
$t->spawn($player);
}
}
}
public function spawnAll($player){
foreach($this->getAll() as $t){
$t->spawn($player);
}
}
public function remove($id){
if(isset($this->server->tileEntities[$id])){
$t = $this->server->tileEntities[$eid];
$this->server->tileEntities[$id] = null;
unset($this->server->tileEntities[$id]);
$t->closed = true;
$t->close();
$this->server->query("DELETE FROM tileentities WHERE ID = ".$id.";");
$t = null;
unset($t);
}
}
}

View File

@ -104,23 +104,32 @@ class Material{
38 => true,
39 => true,
40 => true,
44 => true,
46 => true,
50 => true,
51 => true,
53 => true,
59 => true,
63 => true,
64 => true,
65 => true,
67 => true,
68 => true,
71 => true,
78 => true,
79 => true,
81 => true,
83 => true,
85 => true,
89 => true,
96 => true,
102 => true,
105 => true,
107 => true,
108 => true,
109 => true,
114 => true,
128 => true,
156 => true,
);
static $replaceable = array(
0 => true,
@ -138,7 +147,7 @@ class Material{
6 => true,
26 => true,
31 => true,
46 => true,
//46 => true,
51 => true,
54 => true,
58 => true,
@ -146,10 +155,12 @@ class Material{
61 => true,
62 => true,
64 => true,
71 => true,
78 => true,
96 => true,
105 => true,
107 => true,
245 => true,
247 => true,
);
static $placeable = array(
@ -204,6 +215,7 @@ class Material{
324 => 64,
65 => true,
67 => true,
330 => 71,
73 => true,
79 => true,
80 => true,
@ -223,8 +235,16 @@ class Material{
362 => 105,
107 => true,
108 => true,
109 => true,
112 => true,
114 => true,
128 => true,
155 => true,
156 => true,
245 => true,
246 => true,
247 => true,
323 => true, //Special case of signs
);
static $blocks = array(
0 => "Air",

View File

@ -25,12 +25,11 @@ the Free Software Foundation, either version 3 of the License, or
*/
class TileEntity extends stdClass{
private $server;
function __construct(PocketMinecraftServer $server){
}
class Deprecation{
public static $events = array(
"world.block.change" => "block.change",
);
}
?>
}

View File

@ -1,255 +0,0 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
define("ENTITY_PLAYER", 0);
define("ENTITY_MOB", 1);
define("ENTITY_OBJECT", 2);
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, $onTick;
private $server;
function __construct($server, $eid, $class, $type = 0, $data = array()){
$this->server = $server;
$this->eid = (int) $eid;
$this->type = (int) $type;
$this->class = (int) $class;
$this->player = false;
$this->attach = false;
$this->data = $data;
$this->status = 0;
$this->health = 20;
$this->dead = false;
$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->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);
switch($this->class){
case ENTITY_PLAYER:
$this->player = $this->data["player"];
$this->health = &$this->player->data["health"];
break;
case ENTITY_ITEM:
$this->meta = (int) $this->data["meta"];
$this->stack = (int) $this->data["stack"];
break;
case ENTITY_MOB:
//$this->setName((isset($mobs[$this->type]) ? $mobs[$this->type]:$this->type));
break;
case ENTITY_OBJECT:
//$this->setName((isset($objects[$this->type]) ? $objects[$this->type]:$this->type));
break;
}
}
public function update(){
if($this->class === ENTITY_ITEM and $this->closed === false){
$this->server->api->dhandle("entity.move", $this);
$player = $this->server->query("SELECT EID FROM entities WHERE class == ".ENTITY_PLAYER." AND abs(x - {$this->x}) <= 1.5 AND abs(y - {$this->y}) <= 1.5 AND abs(z - {$this->z}) <= 1.5 LIMIT 1;", true);
if($player !== true and $player !== false){
if($this->server->api->dhandle("player.item.pick", array(
"eid" => $player["EID"],
"block" => $this->type,
"meta" => $this->meta,
"target" => $this->eid
)) !== false){
$this->close();
}
}
}
}
public function getDirection(){
$rotation = ($this->yaw - 90) % 360;
if ($rotation < 0) {
$rotation += 360.0;
}
if(0 <= $rotation && $rotation < 45) {
return 2;
}elseif(45 <= $rotation && $rotation < 135) {
return 3;
}elseif(135 <= $rotation && $rotation < 225) {
return 0;
}elseif(225 <= $rotation && $rotation < 315) {
return 1;
}elseif(315 <= $rotation && $rotation < 360) {
return 2;
}else{
return null;
}
}
public function spawn($player){
if(!is_object($player)){
$player = $this->server->api->player->get($player);
}
if($player->eid === $this->eid){
return false;
}
switch($this->class){
case ENTITY_PLAYER:
$player->dataPacket(MC_ADD_PLAYER, array(
"clientID" => $this->player->clientID,
"username" => $this->player->username,
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
));
$player->dataPacket(MC_PLAYER_EQUIPMENT, array(
"eid" => $this->eid,
"block" => $this->player->equipment[0],
"meta" => $this->player->equipment[1],
));
break;
case ENTITY_ITEM:
$player->dataPacket(MC_ADD_ITEM_ENTITY, array(
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
"block" => $this->type,
"meta" => $this->meta,
"stack" => $this->stack,
));
break;
case ENTITY_MOB:
$player->dataPacket(MC_ADD_MOB, array(
"type" => $this->type,
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
));
break;
case ENTITY_OBJECT:
//$this->setName((isset($objects[$this->type]) ? $objects[$this->type]:$this->type));
break;
}
}
public function close(){
if($this->closed === false){
$this->server->query("DELETE FROM entities WHERE EID = ".$this->eid.";");
$this->server->api->dhandle("entity.remove", $this);
$this->closed = true;
$this->__destruct();
}
}
public function __destruct(){
$this->close();
}
public function getEID(){
return $this->eid;
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
$this->server->query("UPDATE entities SET name = '".str_replace("'", "", $this->name)."' WHERE EID = ".$this->eid.";");
}
public function look($pos2){
$pos = $this->getPosition();
$angle = Utils::angle3D($pos2, $pos);
$this->yaw = $angle["yaw"];
$this->pitch = $angle["pitch"];
$this->server->query("UPDATE entities SET pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
}
public function setCoords($x, $y, $z){
$this->x = $x;
$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.";");
}
public function move($x, $y, $z, $yaw = 0, $pitch = 0){
$this->x += $x;
$this->y += $y;
$this->z += $z;
$this->yaw += $yaw;
$this->yaw %= 360;
$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.";");
}
public function setPosition($x, $y, $z, $yaw, $pitch){
$this->x = $x;
$this->y = $y;
$this->z = $z;
$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;
}
public function getPosition($round = false){
return !isset($this->position) ? false:($round === true ? array_map("floor", $this->position):$this->position);
}
public function setHealth($health, $cause = ""){
$this->health = (int) $health;
$this->server->query("UPDATE entities SET health = ".$this->health." WHERE EID = ".$this->eid.";");
$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,
));
}
if($this->health <= 0 and $this->dead === false){
$this->dead = true;
if($this->player !== false){
$this->server->api->dhandle("player.death", array("name" => $this->name, "cause" => $cause));
}
}elseif($this->health > 0){
$this->dead = false;
}
}
public function getHealth(){
return $this->health;
}
}
?>

View File

@ -1,440 +0,0 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class Player{
private $server, $timeout, $connected, $evid, $queue, $buffer;
var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU, $spawned, $equipment;
function __construct($server, $clientID, $ip, $port, $MTU){
$this->queue = array();
$this->buffer = array();
$this->MTU = $MTU;
$this->server = $server;
$this->clientID = $clientID;
$this->CID = $this->server->clientID($ip, $port);
$this->eid = false;
$this->data = array();
$this->ip = $ip;
$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"));
$this->evid[] = $this->server->event("server.close", array($this, "close"));
console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2);
$this->connected = true;
$this->auth = false;
$this->counter = array(0, 0, 0);
}
public function onTick($time, $event){
if($event !== "server.tick"){
return;
}
if($time > $this->timeout){
$this->close("timeout");
}else{
if(!empty($this->queue)){
$cnt = 0;
while($cnt < 4){
$p = array_shift($this->queue);
if($p === null){
break;
}
switch($p[0]){
case 0:
$this->dataPacket($p[1], $p[2], false, $p[3]);
break;
case 1:
eval($p[1]);
break;
}
++$cnt;
}
}
}
}
public function save(){
if(is_object($this->entity)){
$this->data["spawn"] = array(
"x" => $this->entity->x,
"y" => $this->entity->y,
"z" => $this->entity->z,
);
}
}
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);
$this->connected = false;
if($msg === true){
$this->server->api->dhandle("server.chat", $this->username." left the game");
}
console("[INFO] Session with ".$this->ip.":".$this->port." Client ID ".$this->clientID." closed due to ".$reason);
$this->server->api->player->remove($this->CID);
}
public function eventHandler($data, $event){
switch($event){
case "player.item.pick":
if($data["eid"] === $this->eid){
$data["eid"] = 0;
}
$this->dataPacket(MC_TAKE_ITEM_ENTITY, $data);
break;
case "player.equipment.change":
if($data["eid"] === $this->eid){
break;
}
$this->dataPacket(MC_PLAYER_EQUIPMENT, $data);
break;
case "world.block.change":
$this->dataPacket(MC_UPDATE_BLOCK, $data);
break;
case "entity.move":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_MOVE_ENTITY_POSROT, array(
"eid" => $data->eid,
"x" => $data->x,
"y" => $data->y,
"z" => $data->z,
"yaw" => $data->yaw,
"pitch" => $data->pitch,
));
break;
case "entity.remove":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_REMOVE_ENTITY, array(
"eid" => $data->eid,
));
break;
case "server.time.change":
$this->dataPacket(MC_SET_TIME, array(
"time" => $data,
));
break;
case "entity.animate":
if($data["eid"] === $this->eid){
break;
}
$this->dataPacket(MC_ANIMATE, array(
"eid" => $data["eid"],
"action" => $data["action"],
));
break;
case "server.chat":
$this->dataPacket(MC_CHAT, array(
"message" => str_replace("@username", $this->username, $data),
));
break;
}
}
public function handle($pid, $data){
if($this->connected === true){
$this->timeout = microtime(true) + 25;
switch($pid){
case 0xa0: //NACK
if(isset($this->buffer[$data[2]])){
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
}
if(isset($data[3])){
if(isset($this->buffer[$data[3]])){
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
}
}
break;
case 0xc0: //ACK
$diff = $data[2] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
}
$this->counter[2] = $data[2];
unset($this->buffer[$data[2]]);
if(isset($data[3])){
$diff = $data[3] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
}
$this->counter[2] = $data[3];
unset($this->buffer[$data[3]]);
}
break;
case 0x07:
$this->send(0x08, array(
MAGIC,
$this->server->serverID,
$this->port,
$data[3],
0,
));
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
for($i = $this->counter[1]; $i < $data[0]; ++$i){
$this->send(0xa0, array(1, true, $i));
}
$this->counter[1] = $data[0];
}elseif($diff === 1){
$this->counter[1] = $data[0];
}
$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:
$this->dataPacket(MC_SERVER_HANDSHAKE, array(
"port" => $this->port,
"session" => $data["session"],
"session2" => Utils::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9"),
));
break;
case MC_CLIENT_HANDSHAKE:
break;
case MC_LOGIN:
$this->username = str_replace(array("\x00", "/", " ", "\r", "\n"), array("", "-", "_", "", ""), $data["username"]);
if($this->username == ""){
$this->close("bad username", false);
break;
}
$o = $this->server->api->player->getOffline($this->username);
if($this->server->whitelist !== false and (!in_array($this->username, $this->server->whitelist)/* or ($o["lastID"] != 0 and $o["lastID"] != $this->clientID)*/)){
$this->close("\"".$this->username."\" not being on white-list", false);
break;
}
$u = $this->server->api->player->get($this->username);
$c = $this->server->api->player->getByClientID($this->clientID);
if($u !== false){
$u->close("logged in from another location");
}
if($c !== false){
$c->close("logged in from another location");
}
$this->server->api->player->add($this->CID);
$this->auth = true;
$this->data["lastIP"] = $this->ip;
$this->data["lastID"] = $this->clientID;
$this->server->api->player->saveOffline($this->username, $this->data);
$this->dataPacket(MC_LOGIN_STATUS, array(
"status" => 0,
));
$this->dataPacket(MC_START_GAME, array(
"seed" => $this->server->seed,
"x" => $this->data["spawn"]["x"],
"y" => $this->data["spawn"]["y"],
"z" => $this->data["spawn"]["z"],
"unknown1" => 0,
"gamemode" => $this->server->gamemode,
"eid" => 0,
));
break;
case MC_READY:
switch($data["status"]){
case 1:
if($this->spawned !== false){
break;
}
$this->spawned = true;
$this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this));
$this->eid = $this->entity->eid;
$this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";");
$this->entity->setName($this->username);
$this->entity->data["clientID"] = $this->clientID;
$this->server->api->entity->spawnAll($this);
$this->server->api->entity->spawnToAll($this->eid);
$this->evid[] = $this->server->event("server.time.change", array($this, "eventHandler"));
$this->evid[] = $this->server->event("server.chat", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.remove", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.move", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.equipment.change", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.item.pick", array($this, "eventHandler"));
$this->evid[] = $this->server->event("world.block.change", array($this, "eventHandler"));
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
$this->eventHandler($this->server->motd, "server.chat");
if($this->MTU <= 548){
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "server.chat");
}
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->api->dhandle("entity.move", $this->entity);
}
break;
case MC_PLAYER_EQUIPMENT:
$data["eid"] = $this->eid;
if($this->server->handle("player.equipment.change", $data) !== false){
$this->equipment[0] = $data["block"];
$this->equipment[1] = $data["meta"];
console("[DEBUG] EID ".$this->eid." has now ".$data["block"].":".$data["meta"]." in their hands!", true, true, 2);
}
break;
case MC_REQUEST_CHUNK:
$this->actionQueue('
$max = max(1, floor(($this->MTU - 16 - 255) / 192));
$chunk = $this->server->api->level->getOrderedChunk('.$data["x"].', '.$data["z"].', $max);
foreach($chunk as $d){
$this->dataPacket(MC_CHUNK_DATA, array(
"x" => '.$data["x"].',
"z" => '.$data["z"].',
"data" => $d,
), true);
}
');
console("[INTERNAL] Chunk X ".$data["x"]." Z ".$data["z"]." requested", true, true, 3);
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_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);
}
}
break;
case MC_ANIMATE:
$this->server->api->dhandle("entity.animate", array("eid" => $this->eid, "action" => $data["action"]));
break;
case MC_RESPAWN:
$this->entity->setHealth(20, "respawn");
$this->entity->setPosition($data["x"], $data["y"], $data["z"], 0, 0);
break;
case MC_SET_HEALTH:
if($this->server->gamemode === 1){
break;
}
$this->entity->setHealth($data["health"], "client");
break;
case MC_DROP_ITEM:
$this->server->api->block->drop($this->entity->x, $this->entity->y, $this->entity->z, $data["block"], $data["meta"], $data["stack"]);
break;
default:
console("[DEBUG] Unhandled 0x".dechex($data["id"])." Data Packet for Client ID ".$this->clientID.": ".print_r($data, true), true, true, 2);
break;
}
break;
}
}
}
public function send($pid, $data = array(), $raw = false){
if($this->connected === true){
$this->server->send($pid, $data, $raw, $this->ip, $this->port);
}
}
public function actionQueue($code){
$this->queue[] = array(1, $code);
}
public function dataPacket($id, $data = array(), $queue = false, $count = false){
if($queue === true){
$this->queue[] = array(0, $id, $data, $count);
}else{
if($count === false){
$count = $this->counter[0];
++$this->counter[0];
if(count($this->buffer) >= 512){
array_shift($this->buffer);
}
$this->buffer[$count] = array($id, $data);
}
$data["id"] = $id;
$this->send(0x80, array(
$count,
0x00,
$data,
));
}
}
}

694
src/classes/Player.php Normal file
View File

@ -0,0 +1,694 @@
<?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 Player{
private $server;
private $queue = array();
private $buffer = array();
private $evid = array();
var $timeout;
var $connected = true;
var $clientID;
var $ip;
var $port;
var $counter = array(0, 0, 0);
var $username;
var $eid = false;
var $data = array();
var $entity = false;
var $auth = false;
var $CID;
var $MTU;
var $spawned = false;
var $inventory;
var $equipment = array(1, 0);
var $armor = array(0, 0, 0, 0);
var $loggedIn = false;
function __construct(PocketMinecraftServer $server, $clientID, $ip, $port, $MTU){
$this->MTU = $MTU;
$this->server = $server;
$this->clientID = $clientID;
$this->CID = $this->server->clientID($ip, $port);
$this->ip = $ip;
$this->port = $port;
$this->timeout = microtime(true) + 20;
$this->inventory = array_fill(0, 36, array(0, 0, 0));
$this->evid[] = $this->server->event("server.tick", array($this, "onTick"));
$this->evid[] = $this->server->event("server.close", array($this, "close"));
console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2);
}
public function onTick($time, $event){
if($event !== "server.tick"){ //WTF??
return;
}
if($time > $this->timeout){
$this->close("timeout");
}else{
if(!empty($this->queue)){
$cnt = 0;
while($cnt < 4){
$p = array_shift($this->queue);
if($p === null){
break;
}
switch($p[0]){
case 0:
$this->dataPacket($p[1], $p[2], false, $p[3]);
break;
case 1:
eval($p[1]);
break;
}
++$cnt;
}
}
}
}
public function save(){
if($this->entity instanceof Entity){
$this->data["spawn"] = array(
"x" => $this->entity->x,
"y" => $this->entity->y,
"z" => $this->entity->z,
);
}
}
public function close($reason = "", $msg = true){
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->buffer = null;
unset($this->buffer);
$this->queue = null;
unset($this->queue);
$this->connected = false;
if($msg === true){
$this->server->api->chat->broadcast($this->username." left the game");
}
console("[INFO] Session with \x1b[36m".$this->ip.":".$this->port."\x1b[0m Client ID ".$this->clientID." closed due to ".$reason);
$this->server->api->player->remove($this->CID);
}
}
public function addItem($type, $damage, $count){
while($count > 0){
$add = 0;
foreach($this->inventory as $s => $data){
if($data[0] === 0){
$add = min(64, $count);
$this->inventory[$s] = array($type, $damage, $add);
break;
}elseif($data[0] === $type and $data[1] === $damage){
$add = min(64 - $data[2], $count);
if($add <= 0){
continue;
}
$this->inventory[$s] = array($type, $damage, $data[2] + $add);
break;
}
}
if($add === 0){
return false;
}
$count -= $add;
}
return true;
}
public function removeItem($type, $damage, $count){
while($count > 0){
$remove = 0;
foreach($this->inventory as $s => $data){
if($data[0] === $type and $data[1] === $damage){
$remove = min($count, $data[2]);
if($remove < $data[2]){
$this->inventory[$s][2] -= $remove;
}else{
$this->inventory[$s] = array(0, 0, 0);
}
break;
}
}
if($remove === 0){
return false;
}
$count -= $remove;
}
return true;
}
public function hasItem($type, $damage = false){
if($type === 0){
return true;
}
foreach($this->inventory as $s => $data){
if($data[0] === $type and ($data[1] === $damage or $damage === false) and $data[2] > 0){
return true;
}
}
return false;
}
public function eventHandler($data, $event){
switch($event){
case "player.armor":
if($data["eid"] === $this->eid){
$data["eid"] = 0;
$this->armor = array($data["slot0"], $data["slot1"], $data["slot2"], $data["slot3"]);
$this->dataPacket(MC_PLAYER_ARMOR_EQUIPMENT, $data);
}else{
$this->dataPacket(MC_PLAYER_ARMOR_EQUIPMENT, $data);
}
break;
case "player.block.place":
if($data["eid"] === $this->eid and $this->server->gamemode === 0){
$this->removeItem($data["original"][0], $data["original"][1], 1);
}
break;
case "player.pickup":
if($data["eid"] === $this->eid){
$data["eid"] = 0;
if($this->server->gamemode === 0){
$this->addItem($data["entity"]->type, $data["entity"]->meta, $data["entity"]->stack);
}
}
$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 "block.change":
$this->dataPacket(MC_UPDATE_BLOCK, $data);
break;
case "entity.move":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_MOVE_ENTITY_POSROT, array(
"eid" => $data->eid,
"x" => $data->x,
"y" => $data->y,
"z" => $data->z,
"yaw" => $data->yaw,
"pitch" => $data->pitch,
));
break;
case "entity.motion":
/*if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_SET_ENTITY_MOTION, array(
"eid" => $data->eid,
"speedX" => (int) ($data->speedX * 32000),
"speedY" => (int) ($data->speedY * 32000),
"speedZ" => (int) ($data->speedZ * 32000),
));
break;*/
case "entity.remove":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_REMOVE_ENTITY, array(
"eid" => $data->eid,
));
break;
case "server.time":
$this->dataPacket(MC_SET_TIME, array(
"time" => $data,
));
break;
case "entity.animate":
if($data["eid"] === $this->eid){
break;
}
$this->dataPacket(MC_ANIMATE, array(
"eid" => $data["eid"],
"action" => $data["action"],
));
break;
case "entity.metadata":
if($data->eid === $this->eid){
$eid = 0;
}else{
$eid = $data->eid;
}
$this->dataPacket(MC_SET_ENTITY_DATA, array(
"eid" => $eid,
"metadata" => $data->getMetadata(),
));
break;
case "entity.event":
if($data["entity"]->eid === $this->eid){
$eid = 0;
}else{
$eid = $data["entity"]->eid;
}
$this->dataPacket(MC_ENTITY_EVENT, array(
"eid" => $eid,
"event" => $data["event"],
));
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, $message),
));
break;
}
}
public function handle($pid, $data){
if($this->connected === true){
$this->timeout = microtime(true) + 20;
switch($pid){
case 0xa0: //NACK
if(isset($this->buffer[$data[2]])){
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
}
if(isset($data[3])){
if(isset($this->buffer[$data[3]])){
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
}
}
break;
case 0xc0: //ACK
$diff = $data[2] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
}
$this->counter[2] = $data[2];
$this->buffer[$data[2]] = null;
unset($this->buffer[$data[2]]);
if(isset($data[3])){
$diff = $data[3] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
}
$this->counter[2] = $data[3];
$this->buffer[$data[3]] = null;
unset($this->buffer[$data[3]]);
}
break;
case 0x07:
if($this->loggedIn === true){
break;
}
$this->send(0x08, array(
MAGIC,
$this->server->serverID,
$this->port,
$data[3],
0,
));
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
for($i = $this->counter[1]; $i < $data[0]; ++$i){
$this->send(0xa0, array(1, true, $i));
}
$this->counter[1] = $data[0];
}elseif($diff === 1){
$this->counter[1] = $data[0];
}
$this->send(0xc0, array(1, true, $data[0]));
}
if(!isset($data["id"])){
break;
}
switch($data["id"]){
case MC_KEEP_ALIVE:
break;
case 0x03:
break;
case MC_DISCONNECT:
$this->close("client disconnect");
break;
case MC_CLIENT_CONNECT:
if($this->loggedIn === true){
break;
}
$this->dataPacket(MC_SERVER_HANDSHAKE, array(
"port" => $this->port,
"session" => $data["session"],
"session2" => Utils::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9"),
));
break;
case MC_CLIENT_HANDSHAKE:
if($this->loggedIn === true){
break;
}
break;
case MC_LOGIN:
if($this->loggedIn === true){
break;
}
if($data["protocol1"] !== CURRENT_PROTOCOL){
$this->close("protocol", false);
break;
}
$this->loggedIn = true;
$this->username = str_replace(array("\x00", "/", " ", "\r", "\n", '"', "'"), array("", "-", "_", "", "", "", ""), $data["username"]);
if($this->username == ""){
$this->close("bad username", false);
break;
}
$o = $this->server->api->player->getOffline($this->username);
if($this->server->whitelist === true and !$this->server->api->ban->inWhitelist($this->username)){
$this->close("\"\x1b[33m".$this->username."\x1b[0m\" not being on white-list", false);
break;
}elseif($this->server->api->ban->isBanned($this->username) or $this->server->api->ban->isIPBanned($this->ip)){
$this->close("\"\x1b[33m".$this->username."\x1b[0m\" is banned!", false);
}
$u = $this->server->api->player->get($this->username);
$c = $this->server->api->player->getByClientID($this->clientID);
if($u !== false){
$u->close("logged in from another location");
}
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;
if(!isset($this->data["inventory"]) or $this->server->gamemode === 1){
$this->data["inventory"] = $this->inventory;
}
$this->inventory = &$this->data["inventory"];
$this->armor = &$this->data["armor"];
$this->data["lastIP"] = $this->ip;
$this->data["lastID"] = $this->clientID;
$this->server->api->player->saveOffline($this->username, $this->data);
$this->dataPacket(MC_LOGIN_STATUS, array(
"status" => 0,
));
$this->dataPacket(MC_START_GAME, array(
"seed" => $this->server->seed,
"x" => $this->data["spawn"]["x"],
"y" => $this->data["spawn"]["y"],
"z" => $this->data["spawn"]["z"],
"unknown1" => 0,
"gamemode" => $this->server->gamemode,
"eid" => 0,
));
break;
case MC_READY:
switch($data["status"]){
case 1: //Spawn!!
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->x = $this->data["spawn"]["x"];
$this->entity->y = $this->data["spawn"]["y"];
$this->entity->z = $this->data["spawn"]["z"];
$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", 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.motion", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.event", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.metadata", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.equipment.change", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.armor", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.pickup", array($this, "eventHandler"));
$this->evid[] = $this->server->event("block.change", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.block.place", array($this, "eventHandler"));
$this->server->api->dhandle("player.armor", array("eid" => $this->eid, "slot0" => $this->armor[0], "slot1" => $this->armor[1], "slot2" => $this->armor[2], "slot3" => $this->armor[3]));
console("[DEBUG] Player \"".$this->username."\" EID ".$this->eid." spawned at X ".$this->entity->x." Y ".$this->entity->y." Z ".$this->entity->z, true, true, 2);
$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");
}
foreach($this->inventory as $s => $data){
if($data[0] > 0 and $data[2] >= 0){
$e = $this->server->api->entity->add(ENTITY_ITEM, $data[0], array(
"x" => $this->entity->x + 0.5,
"y" => $this->entity->y + 0.19,
"z" => $this->entity->z + 0.5,
"meta" => $data[1],
"stack" => $data[2],
));
$this->server->api->entity->spawnTo($e->eid, $this);
}
$this->inventory[$s] = array(0, 0, 0);
}
$this->entity->setPosition($this->entity->x, $this->entity->y, $this->entity->z, 0, 0);
break;
case 2://Chunk loaded?
break;
}
break;
case MC_MOVE_PLAYER:
if($this->entity instanceof Entity){
$this->entity->setPosition($data["x"], $data["y"], $data["z"], $data["yaw"], $data["pitch"]);
$this->server->api->dhandle("player.move", $this->entity);
}
break;
case MC_PLAYER_EQUIPMENT:
$data["eid"] = $this->eid;
if($this->server->handle("player.equipment.change", $data) !== false){
$this->equipment[0] = $data["block"];
$this->equipment[1] = $data["meta"];
console("[DEBUG] EID ".$this->eid." has now ".$data["block"].":".$data["meta"]." in their hands!", true, true, 2);
}
break;
case MC_REQUEST_CHUNK:
$x = $data["x"] * 16;
$z = $data["z"] * 16;
/*
$max = max(1, floor(($this->MTU - 16 - 255) / 192));
$chunk = $this->server->api->level->getOrderedChunk('.$data["x"].', '.$data["z"].', $max);
foreach($chunk as $d){
$this->dataPacket(MC_CHUNK_DATA, array(
"x" => '.$data["x"].',
"z" => '.$data["z"].',
"data" => $d,
), true);
}
$tiles = $this->server->query("SELECT * FROM tileentities WHERE spawnable = 1 AND x >= '.$x.' AND x < '.($x + 16).' AND z >= '.$z.' AND z < '.($z + 16).';");
if($tiles !== false and $tiles !== true){
while(($tile = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){
$this->server->api->tileentity->spawnTo($tile["ID"], "'.$this->username.'", true);
}
}
*/
$this->actionQueue('$max = max(1, floor(($this->MTU - 16 - 255) / 192));$chunk = $this->server->api->level->getOrderedChunk('.$data["x"].', '.$data["z"].', $max);foreach($chunk as $d){$this->dataPacket(MC_CHUNK_DATA, array("x" => '.$data["x"].',"z" => '.$data["z"].',"data" => $d,), true);}$tiles = $this->server->query("SELECT * FROM tileentities WHERE spawnable = 1 AND x >= '.$x.' AND x < '.($x + 16).' AND z >= '.$z.' AND z < '.($z + 16).';");if($tiles !== false and $tiles !== true){while(($tile = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){$this->server->api->tileentity->spawnTo($tile["ID"], "'.$this->username.'", true);}}');
console("[INTERNAL] Chunk X ".$data["x"]." Z ".$data["z"]." requested", true, true, 3);
break;
case MC_USE_ITEM:
$data["eid"] = $this->eid;
if(Utils::distance($this->entity->position, $data) > 10){
break;
}elseif($this->server->gamemode === 0 and !$this->hasItem($data["block"], $data["meta"])){
console("[DEBUG] Player \"".$this->username."\" tried to place not got block (or crafted block)", true, true, 2);
//break;
}
$this->server->handle("player.block.action", $data);
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_PLAYER_ARMOR_EQUIPMENT:
$data["eid"] = $this->eid;
$this->server->handle("player.armor", $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){
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->api->dhandle("entity.animate", array("eid" => $this->eid, "action" => $data["action"]));
break;
case MC_RESPAWN:
if($this->entity->dead === false){
break;
}
$this->entity->fire = 0;
$this->entity->air = 300;
$this->entity->setPosition($data["x"], $data["y"], $data["z"], 0, 0);
$this->entity->setHealth(20, "respawn");
$this->entity->updateMetadata();
break;
case MC_SET_HEALTH:
if($this->server->gamemode === 1){
break;
}
//$this->entity->setHealth($data["health"], "client");
break;
case MC_ENTITY_EVENT:
$data["eid"] = $this->eid;
switch($data["event"]){
case 9: //Eating
$items = array(
260 => 2, //Apples
282 => 10, //Stew
297 => 5, //Bread
319 => 3,
320 => 8,
363 => 3,
364 => 8,
);
if(isset($items[$this->equipment[0]])){
$this->removeItem($this->equipment[0], 0, 1);
$this->dataPacket(MC_ENTITY_EVENT, array(
"eid" => 0,
"event" => 9,
));
$this->entity->heal($items[$this->equipment[0]], "eating");
}
break;
}
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;
case MC_SIGN_UPDATE:
$t = $this->server->api->tileentity->get($data["x"], $data["y"], $data["z"]);
if(($t[0] instanceof TileEntity) and $t[0]->class === TILE_SIGN){
$t = $t[0];
if($t->data["creator"] !== $this->username){
$t->spawn($this);
}else{
$t->data["Text1"] = $data["line0"];
$t->data["Text2"] = $data["line1"];
$t->data["Text3"] = $data["line2"];
$t->data["Text4"] = $data["line3"];
$this->server->api->tileentity->spawnToAll($t);
}
}
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;
}
}
}
public function send($pid, $data = array(), $raw = false){
if($this->connected === true){
$this->server->send($pid, $data, $raw, $this->ip, $this->port);
}
}
public function actionQueue($code){
$this->queue[] = array(1, $code);
}
public function dataPacket($id, $data = array(), $queue = false, $count = false){
if($queue === true){
$this->queue[] = array(0, $id, $data, $count);
}else{
if($count === false){
$count = $this->counter[0];
++$this->counter[0];
if(count($this->buffer) >= 512){
array_shift($this->buffer);
}
$this->buffer[$count] = array($id, $data);
}
$data["id"] = $id;
$this->send(0x80, array(
$count,
0x00,
$data,
));
}
}
}

View File

@ -25,46 +25,49 @@ the Free Software Foundation, either version 3 of the License, or
*/
class PocketMinecraftServer extends stdClass{
var $invisible, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities, $mapDir, $mapName, $map, $level, $tileEntities;
private $database, $interface, $evCnt, $handCnt, $events, $handlers, $version, $serverType, $lastTick;
function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $serverID = false){
$this->port = (int) $port; //19132 - 19135
$vNumber = new VersionString();
$vNumber = $vNumber->getNumber();
console("[INFO] PocketMine-MP ".MAJOR_VERSION." #".$vNumber." by @shoghicp, LGPL License", true, true, 0);
console("[DEBUG] Target Minecraft PE: ".CURRENT_MINECRAFT_VERSION, true, true, 2);
class PocketMinecraftServer{
public $tCnt;
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, $eventsID, $handlers, $serverType, $lastTick, $ticker;
private function load(){
$this->version = new VersionString();
console("[INFO] \x1b[33;1mPocketMine-MP ".MAJOR_VERSION." #".$this->version->getNumber()." by @shoghicp, LGPL License", true, true, 0);
console("[INFO] Target Minecraft PE: \x1b[36;1m".CURRENT_MINECRAFT_VERSION."\x1b[0m, protocol #".CURRENT_PROTOCOL, true, true, 0);
if($this->version->isDev()){
console("[INFO] \x1b[31;1mThis is a Development version");
}
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->name = $name;
$this->doTick = false;
$this->api = false;
$this->tCnt = 1;
$this->mapDir = false;
$this->mapName = false;
$this->events = array();
$this->eventsID = 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();
$this->custom = array();
$this->evCnt = 0;
$this->handCnt = 0;
$this->evCnt = 1;
$this->handCnt = 1;
$this->eidCnt = 1;
$this->maxClients = 20;
$this->schedule = array();
$this->scheduleCnt = 0;
$this->scheduleCnt = 1;
$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->spawn = array("x" => 128.5,"y" => 100,"z" => 128.5);
$this->time = 0;
@ -73,11 +76,19 @@ class PocketMinecraftServer extends stdClass{
$this->setType("normal");
$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: ".CURRENT_PROTOCOL);
console("[INFO] Max Clients: ".$this->maxClients);
$this->stop = false;
console("[INFO] Server Name: \x1b[36m".$this->name."\x1b[0m");
console("[DEBUG] Server ID: ".$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(){
@ -87,15 +98,12 @@ 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->api->dhandle("server.time.change", $this->time);');
$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, "Online (".count($this->clients)."): ".implode(", ",$this->api->player->online()));');
if($this->api instanceof ServerAPI){
$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 * 120, '$this->debugInfo(true);');
}
@ -108,13 +116,11 @@ class PocketMinecraftServer extends stdClass{
//$this->query("PRAGMA secure_delete = OFF;");
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE);");
$this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);");
$this->query("CREATE TABLE metadata (EID INTEGER PRIMARY KEY, name TEXT, value TEXT);");
$this->query("CREATE TABLE tileentities (ID INTEGER PRIMARY KEY, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);");
$this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);");
$this->query("CREATE TABLE 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->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);");
}
@ -129,10 +135,7 @@ class PocketMinecraftServer extends stdClass{
}
public function reloadConfig(){
if($this->whitelist === true or is_array($this->whitelist)){
$this->whitelist = explode("\n", str_replace(array("\t","\r"), "", file_get_contents(FILE_PATH."white-list.txt")));
}
$this->bannedIPs = explode("\n", str_replace(array(" ","\t","\r"), "", file_get_contents(FILE_PATH."banned-ips.txt")));
}
public function debugInfo($console = false){
@ -142,20 +145,30 @@ class PocketMinecraftServer extends stdClass{
$info["memory_peak_usage"] = round((memory_get_peak_usage(true) / 1024) / 1024, 2)."MB";
$info["entities"] = $this->query("SELECT count(EID) as count FROM entities;", true);
$info["entities"] = $info["entities"]["count"];
$info["events"] = $this->query("SELECT count(ID) as count FROM events;", true);
$info["events"] = $info["events"]["count"];
$info["events"] = count($this->eventsID);
$info["handlers"] = $this->query("SELECT count(ID) as count FROM handlers;", true);
$info["handlers"] = $info["handlers"]["count"];
$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);
console("[DEBUG] TPS: ".$info["tps"].", Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"]."), Entities: ".$info["entities"].", Events: ".$info["events"].", Handlers: ".$info["handlers"].", Actions: ".$info["actions"].", Garbage: ".$info["garbage"], true, true, 2);
}
return $info;
}
public function close($reason = "stop"){
if($this->stop !== true){
$this->chat(false, "Stopping server...");
if(is_int($reason)){
$reason = "signal stop";
}
if(($this->api instanceof ServerAPI) === true){
if(($this->api->chat instanceof ChatAPI) === true){
$this->api->chat->send(false, "Stopping server...");
}
}
//$this->ticker->stop = true;
$this->save(true);
$this->stop = true;
$this->trigger("server.close", $reason);
@ -163,13 +176,8 @@ class PocketMinecraftServer extends stdClass{
}
}
public function chat($owner, $text, $target = true){
$message = "";
if($owner !== false){
$message = "<".$owner."> ";
}
$message .= $text;
$this->handle("server.chat", $message);
public function chat($owner, $text, $target = false){
$this->api->chat->send($owner, $text, $target);
}
public function setType($type = "normal"){
@ -187,12 +195,19 @@ class PocketMinecraftServer extends stdClass{
public function addHandler($event, $callable, $priority = 5){
if(!is_callable($callable)){
return false;
}elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"".Deprecation::$events[$event]."\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Adding handle to ".(is_array($callable) ? get_class($callable[0])."::".$callable[1]:$callable)."]");
}
$priority = (int) $priority;
$this->handlers[$this->handCnt] = $callable;
$this->query("INSERT INTO handlers (ID, name, priority) VALUES (".$this->handCnt.", '".str_replace("'", "\\'", $event)."', ".$priority.");");
console("[INTERNAL] New handler ".(is_array($callable) ? get_class($callable[0])."::".$callable[1]:$callable)." to special event ".$event." (ID ".$this->handCnt.")", true, true, 3);
return $this->handCnt++;
$hnid = $this->handCnt++;
$this->handlers[$hnid] = $callable;
$this->query("INSERT INTO handlers (ID, name, priority) VALUES (".$hnid.", '".str_replace("'", "\\'", $event)."', ".$priority.");");
console("[INTERNAL] New handler ".(is_array($callable) ? get_class($callable[0])."::".$callable[1]:$callable)." to special event ".$event." (ID ".$hnid.")", true, true, 3);
return $hnid;
}
public function handle($event, &$data){
@ -202,17 +217,34 @@ 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;
}
}
}elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"".Deprecation::$events[$event]."\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Handler]");
}
$handlers->finalize();
if($result !== false){
$this->trigger($event, $data);
}
@ -221,47 +253,46 @@ class PocketMinecraftServer extends stdClass{
public function eventHandler($data, $event){
switch($event){
case "player.new":
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"]);
}else{
$this->level["SpawnX"] = $this->spawn["x"];
$this->level["SpawnY"] = $this->spawn["y"];
$this->level["SpawnZ"] = $this->spawn["z"];
$this->levelData = unserialize(file_get_contents($this->mapDir."level.dat"));
if($this->levelData === false){
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
$this->close("invalid world data");
}
$this->level["Time"] = &$this->time;
console("[INFO] Spawn: X ".$this->level["SpawnX"]." Y ".$this->level["SpawnY"]." Z ".$this->level["SpawnZ"]);
console("[INFO] Time: ".$this->time);
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
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->levelData["SpawnX"] = $this->spawn["x"];
$this->levelData["SpawnY"] = $this->spawn["y"];
$this->levelData["SpawnZ"] = $this->spawn["z"];
}
$this->levelData["Time"] = $this->time;
console("[INFO] Spawn: X \x1b[36m".$this->levelData["SpawnX"]."\x1b[0m Y \x1b[36m".$this->levelData["SpawnY"]."\x1b[0m Z \x1b[36m".$this->levelData["SpawnZ"]."\x1b[0m");
console("[INFO] Time: \x1b[36m".$this->time."\x1b[0m");
console("[INFO] Seed: \x1b[36m".$this->seed."\x1b[0m");
console("[INFO] Gamemode: \x1b[36m".($this->gamemode === 0 ? "survival":"creative")."\x1b[0m");
$d = array(0 => "peaceful", 1 => "easy", 2 => "normal", 3 => "hard");
console("[INFO] Difficulty: ".$d[$this->difficulty]);
console("[INFO] Difficulty: \x1b[36m".$d[$this->difficulty]."\x1b[0m");
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 \"\x1b[32m".$this->levelData["LevelName"]."\x1b[0m\"!", true, true, 0);
$this->map = false;
}else{
$this->map->loadMap();
}
}else{
console("[INFO] Time: ".$this->time);
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
console("[INFO] Time: \x1b[36m".$this->time."\x1b[0m");
console("[INFO] Seed: \x1b[36m".$this->seed."\x1b[0m");
console("[INFO] Gamemode: \x1b[36m".($this->gamemode === 0 ? "survival":"creative")."\x1b[0m");
}
}
@ -269,6 +300,10 @@ class PocketMinecraftServer extends stdClass{
if($this->map !== false){
console("[INFO] Loading entities...");
$entities = unserialize(file_get_contents($this->mapDir."entities.dat"));
if($entities === false or !is_array($entities)){
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
$this->close("invalid world data");
}
foreach($entities as $entity){
if(!isset($entity["id"])){
break;
@ -284,26 +319,83 @@ class PocketMinecraftServer extends stdClass{
"yaw" => $entity["Rotation"][0],
"pitch" => $entity["Rotation"][1],
));
}else{
$e = $this->api->entity->add(ENTITY_MOB, $entity["id"]);
}elseif($entity["id"] === 83){ //Painting
$e = $this->api->entity->add(ENTITY_OBJECT, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}else{
$e = $this->api->entity->add(ENTITY_MOB, $entity["id"], $entity);
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
$e->setHealth($entity["Health"]);
}
}
}
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");');
$tiles = unserialize(file_get_contents($this->mapDir."tileEntities.dat"));
foreach($tiles as $tile){
if(!isset($tile["id"])){
break;
}
$t = $this->api->tileentity->add($tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
}
$this->action(1000000 * 60 * 15, '$this->api->chat->broadcast("Forcing save...");$this->save();');
}
}
public function save($final = false){
if($this->mapName !== false){
file_put_contents($this->mapDir."level.dat", serialize($this->level));
$this->levelData["Time"] = $this->time;
file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
$this->map->saveMap($final);
$this->trigger("server.save", $final);
console("[INFO] Saving entities...");
foreach($this->entities as $entity){
if(count($this->entities) > 0){
$entities = array();
foreach($this->entities as $entity){
if($entity->class === ENTITY_MOB or $entity->class === ENTITY_OBJECT){
$entities[] = array(
"id" => $entity->type,
"Color" => @$entity->data["Color"],
"Sheared" => @$entity->data["Sheared"],
"Health" => $entity->health,
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => $entity->yaw,
1 => $entity->pitch,
),
);
}elseif($entity->class === ENTITY_ITEM){
$entities[] = array(
"id" => 64,
"Item" => array(
"id" => $entity->type,
"Damage" => $entity->meta,
"Count" => $entity->stack,
),
"Health" => $entity->health,
"Pos" => array(
0 => $entity->x,
1 => $entity->y,
2 => $entity->z,
),
"Rotation" => array(
0 => 0,
1 => 0,
),
);
}
}
file_put_contents($this->mapDir."entities.dat", serialize($entities));
}
if(count($this->tileEntities) > 0){
$tiles = array();
foreach($this->tileEntities as $tile){
$tiles[] = $tile->data;
}
file_put_contents($this->mapDir."tileEntities.dat", serialize($tiles));
}
}
}
@ -315,15 +407,54 @@ class PocketMinecraftServer extends stdClass{
}
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"));
if(function_exists("pcntl_signal")){
pcntl_signal(SIGTERM, array($this, "close"));
pcntl_signal(SIGINT, array($this, "close"));
pcntl_signal(SIGHUP, 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";
global $lasttrace;
$dump .= "Last Backtrace: ".$lasttrace."\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);
@ -343,6 +474,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){
@ -354,7 +488,7 @@ class PocketMinecraftServer extends stdClass{
), false, $packet["ip"], $packet["port"]);
break;
}
if(in_array($packet["ip"], $this->bannedIPs)){
if($this->api->ban->isIPBanned($packet["ip"])){
$this->send(0x1c, array(
$data[0],
$this->serverID,
@ -367,6 +501,7 @@ class PocketMinecraftServer extends stdClass{
$this->custom["times_".$CID] = 0;
}
$ln = 15;
$this->description .= " ";
$txt = substr($this->description, $this->custom["times_".$CID], $ln);
$txt .= substr($this->description, 0, $ln - strlen($txt));
$this->send(0x1c, array(
@ -378,7 +513,7 @@ class PocketMinecraftServer extends stdClass{
$this->custom["times_".$CID] = ($this->custom["times_".$CID] + 1) % strlen($this->description);
break;
case 0x05:
if(in_array($packet["ip"], $this->bannedIPs) or count($this->clients) >= $this->maxClients){
if($this->api->ban->isIPBanned($packet["ip"]) or count($this->clients) >= $this->maxClients){
$this->send(0x80, array(
0,
0x00,
@ -398,9 +533,10 @@ class PocketMinecraftServer extends stdClass{
}
$version = $data[1];
$size = strlen($data[2]);
if($version !== CURRENT_PROTOCOL){
if($version !== CURRENT_STRUCTURE){
console("[DEBUG] Incorrect structure #$version from ".$packet["ip"].":".$packet["port"], true, true, 2);
$this->send(0x1a, array(
CURRENT_PROTOCOL,
CURRENT_STRUCTURE,
MAGIC,
$this->serverID,
), false, $packet["ip"], $packet["port"]);
@ -414,7 +550,7 @@ class PocketMinecraftServer extends stdClass{
}
break;
case 0x07:
if(in_array($packet["ip"], $this->bannedIPs) or count($this->clients) >= $this->maxClients){
if($this->api->ban->isIPBanned($packet["ip"]) or count($this->clients) >= $this->maxClients){
$this->send(0x80, array(
0,
0x00,
@ -435,7 +571,7 @@ class PocketMinecraftServer extends stdClass{
$port = $data[2];
$MTU = $data[3];
$clientID = $data[4];
$this->clients[$CID] = new Player($this, $clientID, $packet["ip"], $packet["port"], $MTU);
$this->clients[$CID] = new Player($this, $clientID, $packet["ip"], $packet["port"], $MTU); //New Session!
$this->clients[$CID]->handle(0x07, $data);
break;
}
@ -448,7 +584,7 @@ class PocketMinecraftServer extends stdClass{
public function process(){
while($this->stop === false){
$packet = @$this->interface->readPacket();
$packet = $this->interface->readPacket();
if($packet !== false){
$this->packetHandler($packet);
}else{
@ -458,33 +594,26 @@ class PocketMinecraftServer extends stdClass{
}
public function trigger($event, $data = ""){
$this->preparedSQL->selectEvents->reset();
$this->preparedSQL->selectEvents->clear();
$this->preparedSQL->selectEvents->bindValue(":name", $event, SQLITE3_TEXT);
$events = $this->preparedSQL->selectEvents->execute();
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);
if(isset($this->events[$event])){
foreach($this->events[$event] as $evid => $ev){
if(!is_callable($ev)){
$this->deleteEvent($evid);
continue;
}
if(is_array($ev)){
$method = $ev[1];
$ev[0]->$method($data, $event);
}else{
$ev($data, $event);
}
}
}elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"".Deprecation::$events[$event]."\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Trigger]");
}
$events->finalize();
return true;
}
public function response($eid){
if(isset($this->responses[$eid])){
$res = $this->responses[$eid];
unset($this->responses[$eid]);
return $res;
}
return false;
}
public function schedule($ticks, $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
@ -492,15 +621,16 @@ class PocketMinecraftServer extends stdClass{
return false;
}
$add = "";
$chcnt = $this->scheduleCnt++;
if($repeat === false){
$add = ' unset($this->schedule['.$this->scheduleCnt.']);';
$add = '$this->schedule['.$chcnt.']=null;unset($this->schedule['.$chcnt.']);';
}
$this->schedule[$this->scheduleCnt] = array($callback, $data, $eventName);
$this->action(50000 * $ticks, '$schedule = $this->schedule['.$this->scheduleCnt.'];'.$add.'if(!is_callable($schedule[0])){unset($this->schedule['.$this->scheduleCnt.']);return;} call_user_func($schedule[0], $schedule[1], $schedule[2]);', (bool) $repeat);
return $this->scheduleCnt++;
$this->schedule[$chcnt] = array($callback, $data, $eventName);
$this->action(50000 * $ticks, '$schedule=$this->schedule['.$chcnt.'];'.$add.'if(!is_callable($schedule[0])){$this->schedule['.$chcnt.']=null;unset($this->schedule['.$chcnt.']);return false;}return call_user_func($schedule[0],$schedule[1],$schedule[2]);', (bool) $repeat);
return $chcnt;
}
public function action($microseconds, $code, $repeat = true){
public function action($microseconds, $code, $repeat = true){
$this->query("INSERT INTO actions (interval, last, code, repeat) VALUES(".($microseconds / 1000000).", ".microtime(true).", '".base64_encode($code)."', ".($repeat === true ? 1:0).");");
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
}
@ -515,9 +645,9 @@ class PocketMinecraftServer extends stdClass{
if($actions === false or $actions === true){
return;
}
while(false !== ($action = $actions->fetchArray(SQLITE3_ASSOC))){
eval(base64_decode($action["code"]));
if($action["repeat"] === 0){
while(($action = $actions->fetchArray(SQLITE3_ASSOC)) !== false){
$return = eval(base64_decode($action["code"]));
if($action["repeat"] === 0 or $return === false){
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
}
}
@ -531,17 +661,35 @@ class PocketMinecraftServer extends stdClass{
public function event($event, $func){
if(!is_callable($func)){
return false;
}elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"".Deprecation::$events[$event]."\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Attach to ".(is_array($func) ? get_class($func[0])."::".$func[1]:$func)."]");
}
$this->events[$this->evCnt] = $func;
$this->query("INSERT INTO events (ID, name) VALUES (".$this->evCnt.", '".str_replace("'", "\\'", $event)."');");
console("[INTERNAL] Attached ".(is_array($func) ? get_class($func[0])."::".$func[1]:$func)." to event ".$event." (ID ".$this->evCnt.")", true, true, 3);
return $this->evCnt++;
$evid = $this->evCnt++;
if(!isset($this->events[$event])){
$this->events[$event] = array();
}
$this->events[$event][$evid] = $func;
$this->eventsID[$evid] = $event;
console("[INTERNAL] Attached ".(is_array($func) ? get_class($func[0])."::".$func[1]:$func)." to event ".$event." (ID ".$evid.")", true, true, 3);
return $evid;
}
public function deleteEvent($id){
$id = (int) $id;
unset($this->events[$id]);
$this->query("DELETE FROM events WHERE ID = ".$id.";");
if(isset($this->eventsID[$id])){
$ev = $this->eventsID[$id];
$this->eventsID[$id] = null;
unset($this->eventsID[$id]);
$this->events[$ev][$id] = null;
unset($this->events[$ev][$id]);
if(count($this->events[$ev]) === 0){
unset($this->events[$ev]);
}
}
}
}

View File

@ -0,0 +1,49 @@
<?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 Item{
public $id;
protected $maxStackSize = 64;
private $durability = 0;
private $name = "Unknown";
public function __construct($id){
$this->id = (int) $id;
}
public function setMaxStackSize($size = 64){
$this->maxStackSize = (int) $size;
}
public function getDestroySpeed(Item $item, Entity $entity){
return 1;
}
public function getMaxStackSize(){
return $this->maxStackSize;
}
}

View File

@ -116,6 +116,25 @@ class Vector3{
public function abs(){
return new Vector3(abs($this->x), abs($this->y), abs($this->z));
}
public function getSide($side){
switch((int) $side){
case 0:
return new Vector3($this->x, $this->y - 1, $this->z);
case 1:
return new Vector3($this->x, $this->y + 1, $this->z);
case 2:
return new Vector3($this->x, $this->y, $this->z - 1);
case 3:
return new Vector3($this->x, $this->y, $this->z + 1);
case 4:
return new Vector3($this->x - 1, $this->y, $this->z);
case 5:
return new Vector3($this->x + 1, $this->y, $this->z);
default:
return $this;
}
}
public function distance($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
@ -132,6 +151,14 @@ class Vector3{
return pow($this->x - $x, 2) + pow($this->y - $y, 2) + pow($this->z - $z, 2);
}
}
public function maxPlainDistance($x = 0, $z = 0){
if(($x instanceof Vector3) === true){
return $this->maxPlainDistance($x->x, $x->z);
}else{
return max(abs($this->x - $x), abs($this->z - $z));
}
}
public function __toString(){
return "Vector3(x=".$this->x.",y=".$this->y.",z=".$this->z.")";

View File

@ -91,7 +91,7 @@ class CustomPacketHandler{
$this->raw .= "\xcd";
$this->raw .= Utils::writeShort($this->data["port"]);
$this->raw .= Utils::writeDataArray(array(
"\xff\xff\xff\xff",
"\xf5\xff\xff\xf5",
"\xff\xff\xff\xff",
"\xff\xff\xff\xff",
"\xff\xff\xff\xff",
@ -133,17 +133,14 @@ class CustomPacketHandler{
case MC_DISCONNECT:
//null
break;
case 0x18:
//null
break;
case MC_LOGIN:
if($this->c === false){
$this->data["username"] = $this->get(Utils::readShort($this->get(2), false));
$this->data["maxX"] = Utils::readInt($this->get(4));
$this->data["maxY"] = Utils::readInt($this->get(4));
$this->data["protocol1"] = Utils::readInt($this->get(4));
$this->data["protocol2"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeShort(strlen($this->data["username"])).$this->data["username"];
$this->raw .= "\x00\x00\x00\x08\x00\x00\x00\x08";
$this->raw .= Utils::writeInt(CURRENT_PROTOCOL).Utils::writeInt(CURRENT_PROTOCOL);
}
break;
case MC_LOGIN_STATUS:
@ -207,11 +204,7 @@ class CustomPacketHandler{
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
$this->raw .= Utils::writeMetadata(array(
1 => array("type" => 1, "value" => 300),
16 => array("type" => 0, "value" => 0),
17 => array("type" => 6, "value" => array(0, 0, 0)),
));
$this->raw .= Utils::writeMetadata($this->data["metadata"]);
}
break;
case MC_ADD_PLAYER:
@ -230,11 +223,7 @@ class CustomPacketHandler{
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
$this->raw .= Utils::writeMetadata(array(
1 => array("type" => 1, "value" => 300),
16 => array("type" => 0, "value" => 0),
17 => array("type" => 6, "value" => array(0, 0, 0)),
));
$this->raw .= Utils::writeMetadata($this->data["metadata"]);
}
break;
case MC_ADD_ENTITY:
@ -391,6 +380,40 @@ 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_ENTITY_EVENT:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["event"] = ord($this->get(1));
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= chr($this->data["event"]);
}
break;
case MC_REQUEST_CHUNK:
if($this->c === false){
$this->data["x"] = Utils::readInt($this->get(4));
@ -422,6 +445,21 @@ class CustomPacketHandler{
$this->raw .= Utils::writeShort($this->data["meta"]);
}
break;
case MC_PLAYER_ARMOR_EQUIPMENT:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["slot0"] = ord($this->get(1));
$this->data["slot1"] = ord($this->get(1));
$this->data["slot2"] = ord($this->get(1));
$this->data["slot3"] = ord($this->get(1));
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= chr($this->data["slot0"]);
$this->raw .= chr($this->data["slot1"]);
$this->raw .= chr($this->data["slot2"]);
$this->raw .= chr($this->data["slot3"]);
}
break;
case MC_INTERACT:
if($this->c === false){
$this->data["action"] = Utils::readByte($this->get(1));
@ -451,14 +489,36 @@ class CustomPacketHandler{
$this->raw .= Utils::writeInt($this->data["target"]);*/
}
break;
case MC_PLAYER_ACTION:
//TODO
break;
case MC_SET_ENTITY_DATA:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["metadata"] = Utils::readMetadata($this->get(true));
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeMetadata(array(
));
$this->raw .= Utils::writeMetadata($this->data["metadata"]);
}
break;
case MC_SET_ENTITY_MOTION:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["speedX"] = Utils::readShort($this->get(2));
$this->data["speedY"] = Utils::readShort($this->get(2));
$this->data["speedZ"] = Utils::readShort($this->get(2));
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeShort($this->data["speedX"]);
$this->raw .= Utils::writeShort($this->data["speedY"]);
$this->raw .= Utils::writeShort($this->data["speedZ"]);
}
break;
case MC_HURT_ARMOR:
if($this->c === false){
$this->data["health"] = Utils::readByte($this->get(1));
}else{
$this->raw .= Utils::writeByte($this->data["health"]);
}
break;
case MC_SET_HEALTH:
@ -468,6 +528,17 @@ class CustomPacketHandler{
$this->raw .= Utils::writeByte($this->data["health"]);
}
break;
case MC_SET_SPAWN_POSITION:
if($this->c === false){
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
$this->data["y"] = ord($this->get(1));
}else{
$this->raw .= Utils::writeInt($this->data["x"]);
$this->raw .= Utils::writeInt($this->data["z"]);
$this->raw .= chr($this->data["y"]);
}
break;
case MC_ANIMATE:
if($this->c === false){
$this->data["action"] = Utils::readByte($this->get(1));
@ -573,8 +644,7 @@ class CustomPacketHandler{
$this->data["line$i"] = $this->get(Utils::readLShort($this->get(2), false));
}
}else{
$this->raw .= $this->data["unknown1"];
$this->raw .= $this->data["unknown2"];
$this->raw .= "\xff";
}
break;
default:

View File

@ -26,24 +26,27 @@ the Free Software Foundation, either version 3 of the License, or
*/
class MinecraftInterface{
var $pstruct, $name, $client, $dataName;
private $socket, $data;
var $pstruct;
var $name;
var $client;
var $dataName;
private $socket;
private $data;
function __construct($server, $port = 25565, $listen = false, $client = true){
$this->socket = new UDPSocket($server, $port, (bool) $listen);
require("pstruct/RakNet.php");
require("pstruct/packetName.php");
require("pstruct/protocol.php");
require("pstruct/dataName.php");
require("protocol/RakNet.php");
require("protocol/packetName.php");
require("protocol/current.php");
require("protocol/dataName.php");
$this->pstruct = $pstruct;
$this->name = $packetName;
$this->dataName = $dataName;
$this->buffer = array();
$this->client = (bool) $client;
$this->start = microtime(true);
}
public function close(){
return $this->socket->close();
return $this->socket->close(false);
}
protected function getStruct($pid){
@ -92,7 +95,7 @@ class MinecraftInterface{
}
$packet = new Packet($pid, $struct, $data[0]);
$packet->parse();
@$packet->parse();
$this->data[] = array($pid, $packet->data, $data[0], $data[1], $data[2]);
return $this->popPacket();
}
@ -118,7 +121,7 @@ class MinecraftInterface{
if($raw === false){
$packet = new Packet($pid, $struct);
$packet->data = $data;
$packet->create();
@$packet->create();
$write = $this->socket->write($packet->raw, $dest, $port);
$this->writeDump($pid, $packet->raw, $data, "client", $dest, $port);
}else{

View File

@ -30,35 +30,27 @@ 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){
function __construct($server, $port, $listen = false){
$this->errors = array_fill(88,(125 - 88) + 1, true);
$this->server = $server;
$this->port = $port;
if($socket !== false){
$this->sock = $socket;
$this->sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($this->sock, SOL_SOCKET, SO_BROADCAST, 1); //Allow sending broadcast messages
if($listen !== true){
$this->connected = true;
$this->buffer = array();
$this->unblock();
}else{
$this->sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($this->sock, SOL_SOCKET, SO_BROADCAST, 1);
if($listen !== true){
$this->connected = true;
$this->buffer = array();
if(socket_bind($this->sock, "0.0.0.0", $port) === true){
$this->unblock();
}else{
if(socket_bind($this->sock, "0.0.0.0", $port) === true){
$this->unblock();
}else{
console("[ERROR] Couldn't bind to 0.0.0.0:".$port, true, true, 0);
die();
}
console("[ERROR] Couldn't bind to 0.0.0.0:".$port, true, true, 0);
die();
}
}
}
function listenSocket(){
public function listenSocket(){
$sock = @socket_accept($this->sock);
if($sock !== false){
$sock = new Socket(false, false, false, $sock);
@ -70,9 +62,7 @@ class UDPSocket{
public function close($error = 125){
$this->connected = false;
if($error === false){
console("[ERROR] [Socket] Socket closed, Error: End of Stream");
}else{
if($error !== false){
console("[ERROR] [Socket] Socket closed, Error $error: ".socket_strerror($error));
}
return @socket_close($this->sock);

View File

@ -0,0 +1,231 @@
<?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.
*/
define("CONFIG_DETECT", -1); //Detect by file extension
define("CONFIG_PROPERTIES", 0); // .properties
define("CONFIG_CNF", CONFIG_PROPERTIES); // .cnf
define("CONFIG_JSON", 1); // .js, .json
define("CONFIG_YAML", 2); // .yml, .yaml
//define("CONFIG_EXPORT", 3); // .export, .xport
define("CONFIG_SERIALIZED", 4); // .sl
define("CONFIG_LIST", 5); // .txt, .list
class Config{
private $config;
private $file;
private $correct;
private $type = CONFIG_DETECT;
public static $formats = array(
"properties" => CONFIG_PROPERTIES,
"cnf" => CONFIG_CNF,
"conf" => CONFIG_CNF,
"config" => CONFIG_CNF,
"json" => CONFIG_JSON,
"js" => CONFIG_JSON,
"yml" => CONFIG_YAML,
"yaml" => CONFIG_YAML,
//"export" => CONFIG_EXPORT,
//"xport" => CONFIG_EXPORT,
"sl" => CONFIG_SERIALIZED,
"serialize" => CONFIG_SERIALIZED,
"txt" => CONFIG_LIST,
"list" => CONFIG_LIST,
);
public function __construct($file, $type = CONFIG_DETECT, $default = array(), &$correct = null){
$this->load($file, $type, $default);
$correct = $this->check();
}
public function load($file, $type = CONFIG_DETECT, $default = array()){
$this->correct = true;
$this->type = (int) $type;
$this->file = $file;
if(!is_array($default)){
$default = array();
}
if(!file_exists($file)){
$this->config = $default;
}else{
if($this->type === CONFIG_DETECT){
$extension = explode(".", basename($this->file));
$extension = strtolower(trim(array_pop($extension)));
if(isset(Config::$formats[$extension])){
$this->type = Config::$formats[$extension];
}else{
$this->correct = false;
}
}
if($this->correct === true){
$content = @file_get_contents($this->file);
switch($this->type){
case CONFIG_PROPERTIES:
case CONFIG_CNF:
$this->parseProperties($content);
break;
case CONFIG_JSON:
$this->config = @json_decode($content, true);
break;
case CONFIG_YAML:
$this->config = Spyc::YAMLLoad($content);
break;
case CONFIG_SERIALIZED:
$this->config = @unserialize($content);
break;
case CONFIG_LIST:
$this->parseList($content);
break;
default:
$this->correct = false;
return false;
break;
}
if(!is_array($this->config)){
$this->config = $default;
}
$this->fillDefaults($default, $this->config);
}else{
return false;
}
}
return true;
}
public function check(){
return $this->correct === true;
}
public function save(){
if($this->correct === true){
switch($this->type){
case CONFIG_PROPERTIES:
case CONFIG_CNF:
$content = $this->writeProperties();
break;
case CONFIG_JSON:
$content = json_encode($this->config);
break;
case CONFIG_YAML:
$content = Spyc::YAMLDump($this->config);
break;
case CONFIG_SERIALIZED:
$content = @serialize($this->config);
break;
case CONFIG_LIST:
$content = implode("\r\n", array_keys($this->config));
break;
}
@file_put_contents($this->file, $content, LOCK_EX);
return true;
}else{
return false;
}
}
public function get($k){
if($this->correct === false or !isset($this->config[$k])){
return false;
}
return ($this->config[$k]);
}
public function set($k, $v = true){
$this->config[$k] = $v;
}
public function exists($k){
return isset($this->config[$k]);
}
public function remove($k){
unset($this->config[$k]);
}
public function getAll($keys = false){
return ($keys === true ? array_keys($this->config):$this->config);
}
private function fillDefaults($default, &$data){
foreach($default as $k => $v){
if(is_array($v)){
if(!isset($data[$k]) or !is_array($data[$k])){
$data[$k] = array();
}
$this->fillDefaults($v, $data[$k]);
}elseif(!isset($data[$k])){
$data[$k] = $v;
}
}
}
private function parseList($content){
foreach(explode("\n", trim(str_replace("\r", "", $content))) as $v){
$v = trim($v);
if($v == ""){
continue;
}
$this->config[$v] = true;
}
}
private function writeProperties(){
$content = "#Properties Config file\r\n#".date("D M j H:i:s T Y")."\r\n";
foreach($this->config as $k => $v){
if(is_bool($v) === true){
$v = $v === true ? "on":"off";
}elseif(is_array($v)){
$v = implode(";", $v);
}
$content .= $k."=".$v."\r\n";
}
return $content;
}
private function parseProperties($content){
if(preg_match_all('/([a-zA-Z0-9\-_]*)=([^\r\n]*)/u', $content, $matches) > 0){ //false or 0 matches
foreach($matches[1] as $i => $k){
$v = trim($matches[2][$i]);
switch(strtolower($v)){
case "on":
case "true":
case "yes":
$v = true;
break;
case "off":
case "false":
case "no":
$v = false;
break;
}
if(isset($this->config[$k])){
console("[NOTICE] [Config] Repeated property ".$k." on file ".$this->file, true, true, 2);
}
$this->config[$k] = $v;
}
}
}
}

View 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;
}
}

View File

@ -0,0 +1,49 @@
<?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{
public $tick, $stop, $lastTic;
private $server;
public function __construct(PocketMinecraftServer $server){
$this->tick = false;
$this->lastTick = 0;
$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);
}
}

View File

@ -0,0 +1,67 @@
<?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::$online === false){
return false;
}
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::$online === false){
return false;
}
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;
}

View File

@ -35,7 +35,43 @@ 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 static $online = true;
public function run(){
}
public static function isOnline(){
return (checkdnsrr("google.com", "ANY") && checkdnsrr("yahoo.com", "ANY") && checkdnsrr("microsoft.com", "ANY"));
}
public static function getIP(){
if(Utils::$online === false){
return false;
}
$ip = trim(strip_tags(Utils::curl_get("http://checkip.dyndns.org/")));
if(preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
return $matches[1];
}else{
$ip = Utils::curl_get("http://www.checkip.org/");
if(preg_match('#">([0-9a-fA-F\:\.]*)</span>#', $ip, $matches) > 0){
return $matches[1];
}else{
$ip = Utils::curl_get("http://checkmyip.org/");
if(preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){
return $matches[1];
}else{
$ip = trim(Utils::curl_get("http://ifconfig.me/ip"));
if($ip != ""){
return $ip;
}else{
return false;
}
}
}
}
}
public static function getOS(){
$uname = strtoupper(php_uname("s"));
@ -60,6 +96,9 @@ abstract class Utils{
}
public static function printable($str){
if(!is_string($str)){
return gettype($str);
}
return preg_replace('#([^\x20-\x7E])#', '.', $str);
}
@ -145,7 +184,7 @@ abstract class Utils{
$r = array();
$r[] = Utils::readLShort(substr($value, $offset, 2));
$offset += 2;
$r[] = Utils::readByte($value{$offset});
$r[] = ord($value{$offset});
++$offset;
$r[] = Utils::readLShort(substr($value, $offset, 2));
$offset += 2;
@ -219,7 +258,6 @@ abstract class Utils{
(string) mt_rand(),
(string) rand(),
function_exists("zend_thread_id") ? ((string) zend_thread_id()):microtime(),
var_export(@get_browser(), true),
function_exists("sys_getloadavg") ? implode(";", sys_getloadavg()):microtime(),
serialize(get_loaded_extensions()),
sys_get_temp_dir(),
@ -305,8 +343,11 @@ abstract class Utils{
}
public static function curl_get($page){
if(Utils::$online === false){
return false;
}
$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);
@ -319,12 +360,15 @@ abstract class Utils{
}
public static function curl_post($page, $args, $timeout = 10){
if(Utils::$online === false){
return false;
}
$ch = curl_init($page);
curl_setopt($ch, CURLOPT_POST, 1);
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);
@ -489,4 +533,8 @@ abstract class Utils{
return strrev(str_pad($long->toBytes(true), 8, "\x00", STR_PAD_LEFT));
}
}
if(Utils::isOnline() === false){
Utils::$online = false;
}

View File

@ -25,14 +25,20 @@ the Free Software Foundation, either version 3 of the License, or
*/
class VersionString{
public static $stageOrder = array(
"alpha" => 0,
"a" => 0,
"beta" => 1,
"b" => 1,
"final" => 2,
"f" => 2,
);
private $stage, $major, $release, $minor;
private $stage;
private $major;
private $release;
private $minor;
private $development = false;
public function __construct($version = MAJOR_VERSION){
if(is_int($version)){
$this->minor = $version & 0x1F;
@ -40,11 +46,12 @@ class VersionString{
$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);
$version = preg_split("/([A-Za-z]*)[ _\-]([0-9]*)\.([0-9]*)\.{0,1}([0-9]*)(dev|)/", $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
$this->development = $version[5] === "dev" ? true:false;
}
}
@ -71,9 +78,17 @@ class VersionString{
public function getRelease(){
return $this->generation . "." . $this->major . "." . $this->minor;
}
public function isDev(){
return $this->development === true;
}
public function get(){
return ucfirst($this->stage) . "_" . $this->getRelease() . ($this->development === true ? "dev":"");
}
public function __toString(){
return ucfirst($this->stage) . "_" . $this->generation . "." . $this->major . "." . $this->minor;
return $this->get();
}
public function compare($target, $diff = false){

View File

@ -59,7 +59,7 @@ class ChunkParser{
}
public function loadFile($file){
if(ZLIB_EXTENSION === true and file_exists($file.".gz")){
if(file_exists($file.".gz")){
$this->raw = gzinflate(file_get_contents($file.".gz"));
$r = @gzinflate($this->raw);
if($r !== false and $r != ""){
@ -169,14 +169,12 @@ 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);
}
$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);
}
}

View File

@ -0,0 +1,531 @@
<?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.
*/
define("ENTITY_PLAYER", 0);
define("ENTITY_MOB", 1);
define("MOB_CHICKEN", 10);
define("MOB_COW", 11);
define("MOB_PIG", 12);
define("MOB_SHEEP", 13);
define("MOB_ZOMBIE", 32);
define("MOB_CREEPER", 33);
define("MOB_SKELETON", 34);
define("MOB_SPIDER", 35);
define("MOB_PIGMAN", 36);
define("ENTITY_OBJECT", 2);
define("OBJECT_PAINTING", 83);
define("ENTITY_ITEM", 3);
class Entity extends stdClass{
public $invincible;
public $age;
public $air;
public $spawntime;
public $dmgcounter;
public $eid;
public $type;
public $name;
public $x;
public $y;
public $z;
public $speedX;
public $speedY;
public $speedZ;
public $speed;
public $last = array(0, 0, 0, 0, 0, 0);
public $yaw;
public $pitch;
public $dead;
public $data;
public $class;
public $attach;
public $closed;
public $player;
private $tickCounter;
private $server;
function __construct(PocketMinecraftServer $server, $eid, $class, $type = 0, $data = array()){
$this->server = $server;
$this->eid = (int) $eid;
$this->type = (int) $type;
$this->class = (int) $class;
$this->player = false;
$this->attach = false;
$this->data = $data;
$this->status = 0;
$this->health = 20;
$this->dmgcounter = array(0, 0, 0);
$this->air = 300;
$this->onground = true;
$this->fire = 0;
$this->crouched = false;
$this->invincible = false;
$this->spawntime = microtime(true);
$this->dead = false;
$this->closed = false;
$this->name = "";
$this->tickCounter = 0;
$this->server->query("INSERT OR REPLACE INTO entities (EID, type, class, health) VALUES (".$this->eid.", ".$this->type.", ".$this->class.", ".$this->health.");");
$this->server->schedule(5, array($this, "update"), array(), true);
$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->speed = 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);
switch($this->class){
case ENTITY_PLAYER:
$this->player = $this->data["player"];
$this->health = &$this->player->data["health"];
$this->setHealth($this->health, "generic");
break;
case ENTITY_ITEM:
$this->meta = (int) $this->data["meta"];
$this->stack = (int) $this->data["stack"];
$this->setHealth(5, "generic");
break;
case ENTITY_MOB:
$this->setHealth($this->data["Health"], "generic");
//$this->setName((isset($mobs[$this->type]) ? $mobs[$this->type]:$this->type));
break;
case ENTITY_OBJECT:
//$this->setName((isset($objects[$this->type]) ? $objects[$this->type]:$this->type));
break;
case ENTITY_PAINTING:
break;
}
}
public function environmentUpdate(){
if($this->class === ENTITY_ITEM){
$time = microtime(true);
if(($time - $this->spawntime) >= 300){
$this->close(); //Despawn timer
return false;
}
if($this->server->gamemode === 0 and ($time - $this->spawntime) >= 2){
$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"],
"entity" => $this,
"block" => $this->type,
"meta" => $this->meta,
"target" => $this->eid
)) !== false){
$this->close();
return false;
}
}
}
}
if($this->dead === true){
$this->fire = 0;
$this->air = 300;
return;
}
if($this->y < -16){
$this->harm(8, "void", true);
}
if($this->fire > 0){
if(($this->fire % 20) === 0){
$this->harm(1, "burning");
}
$this->fire -= 10;
if($this->fire <= 0){
$this->fire = 0;
$this->updateMetadata();
}
}
$startX = (int) (round($this->x - 0.5) - 1);
$startY = (int) (round($this->y) - 1);
$startZ = (int) (round($this->z - 0.5) - 1);
$endX = $startX + 2;
$endY = $startY + 2;
$endZ = $startZ + 2;
for($y = $startY; $y <= $endY; ++$y){
for($x = $startX; $x <= $endX; ++$x){
for($z = $startZ; $z <= $endZ; ++$z){
$b = $this->server->api->level->getBlock($x, $y, $z);
switch($b[0]){
case 8:
case 9: //Drowing
if($this->fire > 0 and $this->inBlock($x, $y, $z)){
$this->fire = 0;
$this->updateMetadata();
}
if($this->air <= 0){
$this->harm(2, "water");
}elseif($x == ($endX - 1) and $y == $endY and $z == ($endZ - 1) and ($this->class === ENTITY_MOB or $this->class === ENTITY_PLAYER)){
$this->air -= 10;
$this->updateMetadata();
}
break;
case 10: //Lava damage
case 11:
if($this->inBlock($x, $y, $z)){
$this->harm(5, "lava");
$this->fire = 300;
$this->updateMetadata();
}
break;
case 51: //Fire block damage
if($this->inBlock($x, $y, $z)){
$this->harm(1, "fire");
$this->fire = 300;
$this->updateMetadata();
}
break;
case 81: //Cactus damage
if($this->touchingBlock($x, $y, $z)){
$this->harm(1, "cactus");
}
break;
default:
if($this->inBlock($x, $y, $z, 0.7) and $y == $endY and !isset(Material::$transparent[$b[0]]) and ($this->class === ENTITY_MOB or $this->class === ENTITY_PLAYER)){
$this->harm(1, "suffocation"); //Suffocation
}elseif($x == ($endX - 1) and $y == $endY and $z == ($endZ - 1)){
$this->air = 300; //Breathing
}
break;
}
}
}
}
}
public function update(){
if($this->closed === true){
return false;
}
if($this->tickCounter === 0){
$this->tickCounter = 1;
$this->environmentUpdate();
}else{
$this->tickCounter = 0;
}
if($this->class === ENTITY_ITEM or $this->class === ENTITY_MOB){
$x = (int) round($this->x - 0.5);
$y = (int) round($this->y - 1);
$z = (int) round($this->z - 0.5);
if($this->speedX != 0){
$this->x += $this->speedX * 5;
}
if($this->speedY != 0){
$this->y += $this->speedY * 5;
}
if($this->speedZ != 0){
$this->z += $this->speedZ * 5;
}
$b = $this->server->api->level->getBlock($x, $y, $z);
if(isset(Material::$transparent[$b[0]])){
$this->speedY -= 0.04 * 5;
//$this->server->api->handle("entity.motion", $this);
}elseif($this->speedY < 0){
$this->y = $y + 1;
$this->speedX = 0;
$this->speedY = 0;
$this->speedZ = 0;
//$this->server->api->handle("entity.motion", $this);
}
}
if($this->last[0] != $this->x or $this->last[1] != $this->y or $this->last[2] != $this->z or $this->last[3] != $this->yaw or $this->last[4] != $this->pitch){
$this->server->api->dhandle("entity.move", $this);
if($this->class === ENTITY_PLAYER){
$this->calculateVelocity();
}
$this->updateLast();
}
}
public function getDirection(){
$rotation = ($this->yaw - 90) % 360;
if ($rotation < 0) {
$rotation += 360.0;
}
if(0 <= $rotation && $rotation < 45) {
return 2;
}elseif(45 <= $rotation && $rotation < 135) {
return 3;
}elseif(135 <= $rotation && $rotation < 225) {
return 0;
}elseif(225 <= $rotation && $rotation < 315) {
return 1;
}elseif(315 <= $rotation && $rotation < 360) {
return 2;
}else{
return null;
}
}
public function getMetadata(){
$flags = 0;
$flags |= $this->fire > 0 ? 1:0;
$flags |= ($this->crouched === true ? 1:0) << 1;
$d = array(
0 => array("type" => 0, "value" => $flags),
1 => array("type" => 1, "value" => $this->air),
16 => array("type" => 0, "value" => 0),
17 => array("type" => 6, "value" => array(0, 0, 0)),
);
if($this->class === ENTITY_MOB and $this->type === MOB_SHEEP){
$d[16]["value"] = (($this->data["Sheared"] == 1 ? 1:0) << 5) | ($this->data["Color"] & 0x0F);
}
return $d;
}
public function updateMetadata(){
$this->server->api->dhandle("entity.metadata", $this);
}
public function spawn($player){
if(!($player instanceof Player)){
$player = $this->server->api->player->get($player);
}
if($player->eid === $this->eid){
return false;
}
switch($this->class){
case ENTITY_PLAYER:
$player->dataPacket(MC_ADD_PLAYER, array(
"clientID" => $this->player->clientID,
"username" => $this->player->username,
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
"metadata" => $this->getMetadata(),
));
$player->dataPacket(MC_PLAYER_EQUIPMENT, array(
"eid" => $this->eid,
"block" => $this->player->equipment[0],
"meta" => $this->player->equipment[1],
));
break;
case ENTITY_ITEM:
$player->dataPacket(MC_ADD_ITEM_ENTITY, array(
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
"block" => $this->type,
"meta" => $this->meta,
"stack" => $this->stack,
));
break;
case ENTITY_MOB:
$player->dataPacket(MC_ADD_MOB, array(
"type" => $this->type,
"eid" => $this->eid,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
"metadata" => $this->getMetadata(),
));
break;
case ENTITY_OBJECT:
//$this->setName((isset($objects[$this->type]) ? $objects[$this->type]:$this->type));
break;
}
}
public function close(){
if($this->closed === false){
$this->closed = true;
$this->server->api->entity->remove($this->eid);
}
}
public function __destruct(){
$this->close();
}
public function getEID(){
return $this->eid;
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
$this->server->query("UPDATE entities SET name = '".str_replace("'", "", $this->name)."' WHERE EID = ".$this->eid.";");
}
public function look($pos2){
$pos = $this->getPosition();
$angle = Utils::angle3D($pos2, $pos);
$this->yaw = $angle["yaw"];
$this->pitch = $angle["pitch"];
$this->server->query("UPDATE entities SET pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
}
public function setCoords($x, $y, $z){
$this->x = $x;
$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.";");
}
public function move($x, $y, $z, $yaw = 0, $pitch = 0){
$this->x += $x;
$this->y += $y;
$this->z += $z;
$this->yaw += $yaw;
$this->yaw %= 360;
$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.";");
}
public function setPosition($x, $y, $z, $yaw, $pitch){
$this->x = $x;
$this->y = $y;
$this->z = $z;
$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.";");
}
public function inBlock($x, $y, $z, $radius = 0.8){
$block = new Vector3($x, $y, $z);
$me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5);
if(($y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){
return true;
}
return false;
}
public function touchingBlock($x, $y, $z, $radius = 0.9){
$block = new Vector3($x, $y, $z);
$me = new Vector3($this->x - 0.5, $this->y, $this->z - 0.5);
if(($y == (((int) $this->y) - 1) or $y == ((int) $this->y) or $y == (((int) $this->y) + 1)) and $block->maxPlainDistance($me) < $radius){
return true;
}
return false;
}
public function calculateVelocity(){
$diffTime = microtime(true) - $this->last[5];
$origin = new Vector3($this->last[0], $this->last[1], $this->last[2]);
$final = new Vector3($this->x, $this->y, $this->z);
$speedX = ($this->last[0] - $this->x) / $diffTime;
$speedY = ($this->last[1] - $this->y) / $diffTime;
$speedZ = ($this->last[2] - $this->z) / $diffTime;
$this->speedX = $speedX;
$this->speedY = $speedY;
$this->speedZ = $speedZ;
$this->speed = $origin->distance($final) / $diffTime;
}
public function updateLast(){
$this->last[0] = $this->x;
$this->last[1] = $this->y;
$this->last[2] = $this->z;
$this->last[3] = $this->yaw;
$this->last[4] = $this->pitch;
$this->last[5] = microtime(true);
}
public function getPosition($round = false){
return !isset($this->position) ? false:($round === true ? array_map("floor", $this->position):$this->position);
}
public function harm($dmg, $cause = "generic", $force = false){
return $this->setHealth($this->getHealth() - ((int) $dmg), $cause, $force);
}
public function heal($health, $cause = "generic"){
return $this->setHealth(min(20, $this->getHealth() + ((int) $health)), $cause);
}
public function setHealth($health, $cause = "generic", $force = false){
$health = (int) $health;
$harm = false;
if($health < $this->health){
$harm = true;
$dmg = $this->health - $health;
if(($this->server->gamemode === 0 or $force === true) and ($this->dmgcounter[0] < microtime(true) or $this->dmgcounter[1] < $dmg) and !$this->dead){
$this->dmgcounter[0] = microtime(true) + 0.5;
$this->dmgcounter[1] = $dmg;
}else{
return false; //Entity inmunity
}
}elseif($health === $this->health){
return false;
}
if($this->server->api->dhandle("entity.health.change", array("entity" => $this, "eid" => $this->eid, "health" => $health, "cause" => $cause)) !== false){
$this->health = min(127, max(-127, $health));
$this->server->query("UPDATE entities SET health = ".$this->health." WHERE EID = ".$this->eid.";");
if($harm === true){
$this->server->api->dhandle("entity.event", array("entity" => $this, "event" => 2)); //Ouch! sound
}
if($this->player instanceof Player){
$this->player->dataPacket(MC_SET_HEALTH, array(
"health" => $this->health,
));
}
if($this->health <= 0 and $this->dead === false){
$this->air = 300;
$this->fire = 0;
$this->crouched = false;
$this->updateMetadata();
$this->dead = true;
if($this->player instanceof Player){
$this->server->api->dhandle("player.death", array("name" => $this->name, "cause" => $cause));
}
$this->server->api->dhandle("entity.event", array("entity" => $this, "event" => 3)); //Entity dead
}elseif($this->health > 0){
$this->dead = false;
}
return true;
}
return false;
}
public function getHealth(){
return $this->health;
}
}

View File

@ -0,0 +1,123 @@
<?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.
*/
define("TILE_SIGN", "Sign");
class TileEntity extends stdClass{
public $name;
public $normal;
public $id;
public $x;
public $y;
public $z;
public $data;
public $class;
public $attach;
public $metadata;
public $closed;
private $server;
function __construct(PocketMinecraftServer $server, $id, $class, $x, $y, $z, $data = array()){
$this->server = $server;
$this->normal = true;
$this->class = $class;
$this->data = $data;
$this->closed = false;
if($class === false){
$this->closed = true;
}
$this->name = "";
$this->id = (int) $id;
$this->x = (int) $x;
$this->y = (int) $y;
$this->z = (int) $z;
$this->server->query("INSERT OR REPLACE INTO tileentities (ID, class, x, y, z) VALUES (".$this->id.", '".$this->class."', ".$this->x.", ".$this->y.", ".$this->z.");");
switch($this->class){
case TILE_SIGN:
$this->server->query("UPDATE tileentities SET spawnable = 1 WHERE ID = ".$this->id.";");
break;
}
}
public function update(){
if($this->closed === true){
return false;
}
}
public function spawn($player, $queue = false){
if($this->closed){
return false;
}
if(!($player instanceof Player)){
$player = $this->server->api->player->get($player);
}
switch($this->class){
case TILE_SIGN:
$player->dataPacket(MC_SIGN_UPDATE, array(
"x" => $this->x,
"y" => $this->y,
"z" => $this->z,
"line0" => $this->data["Text1"],
"line1" => $this->data["Text2"],
"line2" => $this->data["Text3"],
"line3" => $this->data["Text4"],
), $queue);
break;
}
}
public function close(){
if($this->closed === false){
$this->closed = true;
$this->server->api->entity->remove($this->eid);
}
}
public function __destruct(){
$this->close();
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
$this->server->query("UPDATE entities SET name = '".str_replace("'", "", $this->name)."' WHERE EID = ".$this->eid.";");
}
public function setPosition($x, $y, $z){
$this->x = (int) $x;
$this->y = (int) $y;
$this->z = (int) $z;
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z." WHERE EID = ".$this->eid.";");
}
}

View File

@ -26,7 +26,7 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
require_once("classes/world/generator/object/tree/TreeObject.php");
class BigTreeObject extends TreeObject{
private $trunkHeightMultiplier = 0.618;

View File

@ -26,7 +26,7 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
require_once("classes/world/generator/object/tree/TreeObject.php");
class PineTreeObject extends TreeObject{
var $type = 1;
@ -37,7 +37,7 @@ class PineTreeObject extends TreeObject{
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
$this->findRandomLeavesSize();
$checkRadius = 0;
for($yy = 0; $yy < ($this->totalHeight + 2); ++$yy) {
for($yy = 0; $yy < $this->totalHeight; ++$yy) {
if($yy === $this->leavesSizeY) {
$checkRadius = $this->leavesAbsoluteMaxRadius;
}

View File

@ -26,7 +26,7 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
require_once("classes/world/generator/object/tree/TreeObject.php");
class SmallTreeObject extends TreeObject{
var $type = 0;

View File

@ -26,7 +26,7 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
require_once("classes/world/generator/object/tree/TreeObject.php");
class SpruceTreeObject extends TreeObject{
var $type = 1;

View File

@ -36,7 +36,7 @@ class TreeObject{
public static function growTree(LevelAPI $level, $block, $type){
switch($type){
case Sapling::SPRUCE:
if(mt_rand(0,1) == 2){
if(mt_rand(0,1) == 1){
$tree = new SpruceTreeObject();
}else{
$tree = new PineTreeObject();

View File

@ -34,10 +34,11 @@ ini_set("display_errors", 1);
ini_set('default_charset', 'utf-8');
define("FILE_PATH", dirname(__FILE__)."/../../");
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH . PATH_SEPARATOR . FILE_PATH . "/src/" . PATH_SEPARATOR . FILE_PATH . "/src/classes/");
ini_set("memory_limit", "512M");
ini_set("memory_limit", "256M");
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.5");
define("CURRENT_PROTOCOL", 5);
define("CURRENT_MINECRAFT_VERSION", "v0.5.0 alpha");
define("TEST_MD5", "d0ca3786e53b615bb4fb9f5094d5c9a7");
define("MAJOR_VERSION", "Alpha_1.1");
define("CURRENT_STRUCTURE", 5);
define("CURRENT_PROTOCOL", 9);
define("CURRENT_MINECRAFT_VERSION", "v0.6.0 alpha");

View File

@ -1,20 +0,0 @@
#PocketMine-MP default server properties
server-name=A Minecraft Server
description=Server made using PocketMine-MP
motd=Welcome @username to this server!
invisible=false
port=19132
memory-limit=512M
last-update=false
update-channel=stable
white-list=false
debug=2
max-players=20
server-type=normal
time-per-second=20
gamemode=1
difficulty=1
generator=
generator-settings=
level-name=false
server-id=false

View File

@ -27,27 +27,26 @@ 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");
if(strpos(strtoupper(php_uname("s")), "WIN") === false or arg("enable-ansi", false) === true){
define("ENABLE_ANSI", true);
}else{
define("ENABLE_ANSI", false);
}
set_error_handler("fatal_handler", E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_DEPRECATED);
$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);
if(version_compare("5.4.0", PHP_VERSION) > 0){
console("[ERROR] Use PHP >= 5.4.0", true, true, 0);
++$errors;
}
if(version_compare("5.4.0", PHP_VERSION) > 0){
console("[NOTICE] Use PHP >= 5.4.0 to increase performance", true, true, 0);
define("HEX2BIN", false);
}else{
define("HEX2BIN", true);
if(version_compare("5.5.0", PHP_VERSION) <= 0){
console("[NOTICE] PocketMine-MP hasn't been tested with PHP >= 5.5", true, true, 0);
}
if(php_sapi_name() !== "cli"){
console("[ERROR] Use PHP-CLI to execute the library or create your own", true, true, 0);
console("[ERROR] Use PHP-CLI to execute the server or create your own", true, true, 0);
++$errors;
}
@ -57,7 +56,7 @@ if(!extension_loaded("sockets") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"")
}
if(!extension_loaded("pthreads") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "pthreads." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find pthreads extension. [https://github.com/krakjoe/pthreads]", true, true, 0);
console("[ERROR] Unable to find pthreads extension. Use the Installer available in the Homepage", true, true, 0);
++$errors;
}
@ -72,35 +71,14 @@ if(!extension_loaded("sqlite3") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"")
}
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);
console("[ERROR] Unable to find Zlib extension", true, true, 0);
++$errors;
}
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");
require_once("classes/SuperflatGenerator.class.php");
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");
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(FILE_PATH . "src/misc/");
require_all(FILE_PATH . "src/classes/");
?>

View File

@ -107,7 +107,7 @@ function parseNBTData($data){
}
function arg($name, $default){
function arg($name, $default = false){
global $arguments, $argv;
if(!isset($arguments)){
$arguments = arguments($argv);
@ -127,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(
@ -165,19 +165,52 @@ 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;
$time = (ENABLE_ANSI === true ? "\x1b[36m".date("H:i:s")."\x1b[0m":date("H:i:s")) . " ";
$replaced = preg_replace('/\x1b\[[0-9;]*m/', "", $time . $message);
if($log === true and (!defined("LOG") or LOG === true)){
logg($message, "console", false, $level);
logg($replaced, "console", false, $level);
}
if(ENABLE_ANSI === true){
if(preg_match("/\[([a-zA-Z0-9]*)\]/", $message, $matches) > 0){
$add = "\x1b";
switch($matches[1]){
case "ERROR":
$add .= "[31;1m";
break;
case "INTERNAL":
case "DEBUG":
$add .= "[30;1m";
break;
case "WARNING":
$add .= "[33;1m";
break;
case "NOTICE":
$add .= "[37;1m";
break;
default:
$add = "";
break;
}
$message = $time . $add . $message . "\x1b[0m";
}
}else{
$message = $replaced;
}
echo $message;
}
}
function error_handler($errno, $errstr, $errfile, $errline){
function fatal_handler($errno, $errstr, $errfile, $errline){
global $lasttrace;
console("[ERROR] A level ".$errno." error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0);
ob_start();
debug_print_backtrace();
$lasttrace = ob_get_contents();
ob_end_clean();
console("[ERROR] [Backtrace] $lasttrace", true, true, 0);
return false;
}
function logg($message, $name, $EOL = true, $level = 2, $close = false){

View File

@ -25,8 +25,6 @@ the Free Software Foundation, either version 3 of the License, or
*/
//Protocol Version: 5
define("MC_KEEP_ALIVE", 0x00);
@ -43,15 +41,14 @@ define("MC_READY", 0x84);
define("MC_CHAT", 0x85);
define("MC_SET_TIME", 0x86);
define("MC_START_GAME", 0x87);
define("MC_ADD_MOB", 0x88);
define("MC_ADD_PLAYER", 0x89);
//define("MC_REMOVE_PLAYER", 0x8a);
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);
define("MC_MOVE_ENTITY_POSROT", 0x93);
@ -59,27 +56,34 @@ define("MC_MOVE_PLAYER", 0x94);
define("MC_PLACE_BLOCK", 0x95);
define("MC_REMOVE_BLOCK", 0x96);
define("MC_UPDATE_BLOCK", 0x97);
//define("MC_ADD_PAINTING", 0x98);
define("MC_EXPLOSION", 0x99);
define("MC_LEVEL_EVENT", 0x9a);
//define("MC_TILE_EVENT", 0x9b);
define("MC_ENTITY_EVENT", 0x9c);
define("MC_REQUEST_CHUNK", 0x9d);
define("MC_CHUNK_DATA", 0x9e);
define("MC_PLAYER_EQUIPMENT", 0x9f);
define("MC_PLAYER_ARMOR_EQUIPMENT", 0xa0);
define("MC_INTERACT", 0xa1);
define("MC_USE_ITEM", 0xa2);
define("MC_PLAYER_ACTION", 0xa3);
define("MC_INTERACT", 0xa0);
define("MC_USE_ITEM", 0xa1);
define("MC_PLAYER_ACTION", 0xa2);
define("MC_SET_ENTITY_DATA", 0xa3);
define("MC_SET_ENTITY_MOTION", 0xa4);
define("MC_SET_HEALTH", 0xa5);
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);
define("MC_HURT_ARMOR", 0xa5);
define("MC_SET_ENTITY_DATA", 0xa6);
define("MC_SET_ENTITY_MOTION", 0xa7);
define("MC_SET_HEALTH", 0xa8);
define("MC_SET_SPAWN_POSITION", 0xa9);
define("MC_ANIMATE", 0xaa);
define("MC_RESPAWN", 0xab);
//define("MC_SEND_INVENTORY", 0xac);
define("MC_DROP_ITEM", 0xad);
define("MC_CONTAINER_OPEN", 0xae);
define("MC_CONTAINER_CLOSE", 0xaf);
define("MC_CONTAINER_SET_SLOT", 0xb0);
//define("MC_CONTAINER_SET_DATA", 0xb1);
//define("MC_CONTAINER_SET_CONTENT", 0xb2);
//define("MC_CONTAINER_ACK", 0xb3);
define("MC_CLIENT_MESSAGE", 0xb4);
define("MC_SIGN_UPDATE", 0xb5);
define("MC_ADVENTURE_SETTINGS", 0xb6);

View File

@ -59,17 +59,23 @@ $dataName = array(
MC_PLACE_BLOCK => "PlaceBlock",
MC_REMOVE_BLOCK => "RemoveBlock",
MC_UPDATE_BLOCK => "UpdateBlock",
MC_EXPLOSION => "Explosion",
MC_LEVEL_EVENT => "LevelEvent",
MC_ENTITY_EVENT => "EntityEvent",
MC_REQUEST_CHUNK => "RequestChunk",
MC_CHUNK_DATA => "ChunkData",
MC_PLAYER_EQUIPMENT => "PlayerEquipment",
MC_PLAYER_ARMOR_EQUIPMENT => "PlayerArmorEquipment",
MC_INTERACT => "Interact",
MC_USE_ITEM => "UseItem",
MC_PLAYER_ACTION => "PlayerAction",
MC_SET_ENTITY_DATA => "SetEntityData",
MC_SET_ENTITY_MOTION => "SetEntityMotion",
MC_HURT_ARMOR => "HurtArmor",
MC_SET_HEALTH => "SetHealth",
MC_SET_SPAWN_POSITION => "SetSpawnPosition",
MC_ANIMATE => "Animate",

View File

@ -1,6 +1,6 @@
@echo off
TITLE PocketMine-MP Server - by @shoghicp
COLOR F0
COLOR 0F
mode con: cols=90
echo.
@ -26,6 +26,18 @@ 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 /WAIT php -d enable_dl=On PocketMine-MP.php
if exist php.cmd (
if exist bin\ansicon.exe (
bin\ansicon.exe php.cmd -d enable_dl=On PocketMine-MP.php --enable-ansi %*
) else (
php.cmd -d enable_dl=On PocketMine-MP.php %*
)
) else (
if exist bin\ansicon.exe (
bin\ansicon.exe php -d enable_dl=On PocketMine-MP.php --enable-ansi %*
) else (
php -d enable_dl=On PocketMine-MP.php %*
)
)
)
pause

View File

@ -2,7 +2,10 @@
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
if [ -f php5/bin/php ]; then
./php5/bin/php -d enable_dl=On PocketMine-MP.php
./php5/bin/php -d enable_dl=On PocketMine-MP.php $@
read -p "Press [Enter] to continue..."
exit 0
fi
php -d enable_dl=On PocketMine-MP.php
php -d enable_dl=On PocketMine-MP.php $@
read -p "Press [Enter] to continue..."
exit 0