Compare commits

..

229 Commits

Author SHA1 Message Date
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
b1b16bc366 Alpha 1.0.5 2013-01-06 14:05:57 +01:00
aa1a39adfc Fixed TABS 2013-01-06 13:38:28 +01:00
b3b38605b5 Multi-update system and version numeration 2013-01-06 13:31:30 +01:00
7030f9118d Fixes #31 Server crash in health regeneration 2013-01-06 02:28:58 +01:00
b150d4e001 Fixes #30 Server crash when a player dies 2013-01-06 01:53:13 +01:00
125f1c11b4 Added Furnace 2013-01-06 01:16:49 +01:00
82f2a0f2f8 Fixed creative crash when opening chests 2013-01-06 00:58:46 +01:00
700314d75a Starting to support Chest windows 2013-01-05 22:13:10 +01:00
54e6bd0ee9 Fixed death in Creative mode 2013-01-05 20:35:21 +01:00
fd1186061f Updated entity despawning 2013-01-05 19:39:12 +01:00
f03f376535 Fall damage 2013-01-05 19:37:01 +01:00
586f49994a Fixed entity despawn 2013-01-05 18:33:39 +01:00
c1aec49ad1 Changes in Entity events 2013-01-05 18:30:29 +01:00
683c05f206 Replace player spaces & handle more data packets 2013-01-05 17:13:12 +01:00
9ebe68294b Item Drop 2013-01-05 15:17:57 +01:00
c2a45212dd Fixed item spawning 2013-01-05 15:01:21 +01:00
344449fa12 Removed Raknet version & added Current MC version 2013-01-05 13:39:37 +01:00
732ee755e8 Updated to Alpha_1.0.4 2013-01-05 11:37:57 +01:00
f0393f9b93 /give command 2013-01-05 11:34:08 +01:00
f23c2f894d Merge pull request #27 from C0deH4cker/patch-1
Fixed typo [HUGE]
2013-01-05 01:32:41 -08:00
85dfb651bd Merge pull request #29 from C0deH4cker/patch-2
Added pause at the end
2013-01-05 01:31:09 -08:00
b5e6130214 Added pause at the end
Added pause so users can see any errors that occur instead of the command prompt window just closing.
2013-01-05 02:01:05 -05:00
957f24c1f3 Fixed typo 2013-01-04 23:08:39 -05:00
518afeae48 Item pickup 2013-01-05 03:16:11 +01:00
57282225d2 Fixed Sapling, flower placing 2013-01-05 02:40:29 +01:00
369f268b90 Improved compression 2013-01-04 21:47:36 +01:00
ab0abfab1c Alpha_1.0.3 2013-01-04 19:42:26 +01:00
a64f0c8bbe Entities despawning, half item pickup 2013-01-04 19:36:51 +01:00
8d9f9ed9ed Fixed item drop megaduplication 2013-01-04 19:02:54 +01:00
38eed99789 Fixed issues and sockets 2013-01-04 16:04:06 +01:00
284daff67f Removed quiet param 2013-01-04 15:53:52 +01:00
a1e6184c74 Updated ;) with removed one 2013-01-04 15:49:20 +01:00
a495e8f436 Added install scripts for linux 2013-01-04 15:46:29 +01:00
3e9afbdf54 Added world compression 2013-01-04 12:51:33 +01:00
3ba8662c2c NormalGenerator class 2013-01-04 11:29:08 +01:00
52b4220ade Fix for block updates 2013-01-04 01:32:06 +01:00
b9eca491e8 Updated triggers to handle or dhandle API method 2013-01-04 01:20:29 +01:00
d7b1ae4b47 Vectors 2013-01-03 23:39:57 +01:00
9b09ff4042 Added 0x03 unknown packet 2013-01-03 12:20:28 +01:00
f9c71f1800 Fixed unknown data folders 2013-01-03 12:07:08 +01:00
d71167f66c Added generator name to level.dat 2013-01-03 00:57:32 +01:00
4b641bba39 Changed base broadcasts frequency 2013-01-02 22:48:50 +01:00
00379bb2d1 Added command alias 2013-01-02 22:48:37 +01:00
b96070a53a Added PHP >= 5.5 notice 2013-01-02 19:44:52 +01:00
db1b7ec4f2 Line ending cleanup 2013-01-02 19:41:23 +01:00
aafd36859f Solve segfault killing the process 2013-01-02 19:10:05 +01:00
0bea6e8051 Detect Mac OS 2013-01-02 19:09:28 +01:00
96bac5aaec Added player hand distance check 2013-01-02 18:25:39 +01:00
a501020198 Fix for .DS_Store folders in Mac 2013-01-02 17:33:24 +01:00
19436d4953 Removed protocol Changing 2013-01-02 01:09:54 +01:00
6c8e283599 Function names 2012-12-30 20:49:04 +01:00
2b5c21d909 Updated deleted header 2012-12-30 19:55:52 +01:00
2370ca6fd4 Autoloading non-included extensions 2012-12-29 19:54:05 +01:00
04c3229835 Removed GC Collector 2012-12-29 19:12:38 +01:00
9cd5a0c030 Line endings ... 2012-12-29 19:10:55 +01:00
302c865f4e Use Console Thread for Async I/O 2012-12-29 19:10:04 +01:00
b3cc13d4f2 Async class 2012-12-29 18:06:10 +01:00
c922b073b5 Moved ToDo list to the Wiki 2012-12-29 16:21:03 +01:00
f1956464b0 Final merging changes 2012-12-29 16:14:59 +01:00
aa7d6b12b5 BlockIterator 2012-12-29 16:13:59 +01:00
9ea1a05536 More different trees, check grow space 2012-12-29 16:13:58 +01:00
29a5041ef1 Fix for placing blocks where no block exists 2012-12-29 16:13:57 +01:00
000ba5de52 Fix 2012-12-29 16:13:56 +01:00
637d1c313b Changed version to next release 2012-12-29 16:13:52 +01:00
3e392820f1 Readded pthreads dependency 2012-12-29 16:13:03 +01:00
3ab149cf58 Fix for not-placing action blocks 2012-12-29 13:58:33 +01:00
473f5ec01e Updated fopen error 2012-12-29 12:37:47 +01:00
cacf14df81 Nasty line endings :S 2012-12-29 03:27:40 +01:00
e20251eaf4 Fixed Linux bug 2012-12-29 03:23:02 +01:00
000a0dedd9 Alpha 1.0.2
Changed structure
2012-12-29 02:52:12 +01:00
5df48f3b7c Merge remote-tracking branch 'origin/threading' 2012-12-29 02:31:48 +01:00
4c34cdaa61 Removed pthreads dependency for merge 2012-12-29 02:31:19 +01:00
c959e14718 Cancel unallowed break/place events 2012-12-29 02:30:20 +01:00
470352cd31 Bedrock *again* 2012-12-29 02:27:51 +01:00
ca54acd09b Removed example folder (added those examples to the wiki) 2012-12-29 02:19:54 +01:00
8a0c5e4655 Scheduled update for entities 2012-12-28 16:33:16 +01:00
b5c191530a Updated folders 2012-12-28 15:27:49 +01:00
8abc36acd4 Changed files 2012-12-28 15:12:46 +01:00
0b683c6b0e Updated directory structure 2012-12-28 15:09:35 +01:00
0c498e96a3 Removed bedrock 2012-12-28 14:44:56 +01:00
2034dbfb15 Removed bedrock from unbreakable blocks 2012-12-28 14:43:29 +01:00
3409f873be Updated README.md 2012-12-28 04:59:45 +01:00
aefa34187b Updated README.md 2012-12-28 02:09:43 +01:00
2d9b701847 pthreads dependency 2012-12-28 01:02:22 +01:00
78c2a06623 Updated objectives 2012-12-28 00:23:41 +01:00
4d3ef98f1f Updated TODO list 2012-12-28 00:08:20 +01:00
ca12a5c2ce Changed message 2012-12-27 23:57:14 +01:00
ada2662627 Fixed placing Saplings in farmland 2012-12-27 17:35:40 +01:00
a7cc37ead6 Alpha 1.0.1
Fixes non-loading plugins and Tree Growing
2012-12-27 13:24:53 +01:00
2353457b5b Tree growing! 2012-12-27 01:08:26 +01:00
8f6ed22158 Fixed plugins loading? 2012-12-26 22:30:09 +01:00
be78530175 Removed a var_dump() 2012-12-26 20:35:49 +01:00
22d7f856d8 Add the property 2012-12-26 20:26:39 +01:00
c8a0315c52 Update channels! 2012-12-26 20:25:39 +01:00
356c5a6a72 Alpha v1.0 2012-12-26 19:44:32 +01:00
dfd06ac3f7 Correct bed placing 2012-12-26 19:44:16 +01:00
941f1479c7 Correct chest/furnace placement 2012-12-26 19:00:17 +01:00
b7af93ca17 Removed ClientID whitelisting 2012-12-26 18:31:27 +01:00
2d8b56fb5e Updated features to reflect changes in development 2012-12-26 18:22:57 +01:00
41e8df5b88 Implemented Lava Spread 2012-12-26 18:20:19 +01:00
d367a9b517 Water fix *again* 2012-12-26 18:01:30 +01:00
ead624274b Fixed water flow 2012-12-26 17:56:48 +01:00
80fda57c79 dot 2012-12-26 17:56:41 +01:00
38c7a6bf33 Added third party libraries 2012-12-26 17:51:15 +01:00
b505a23acf Updated BigInteger class 2012-12-26 17:50:06 +01:00
5b057654a7 Features 2012-12-26 16:58:44 +01:00
968b1becd7 Fixed water infinite liquid flowing loop 2012-12-26 16:53:35 +01:00
8930b361eb Water now works correctly 2012-12-26 16:28:11 +01:00
5042289ff7 Fixed object callable PHP 5.3 2012-12-26 16:25:22 +01:00
cae6285f64 Updated APIs to only allow PocketMinecraftServer object 2012-12-26 16:21:50 +01:00
3a0db10d6b getBlockFace() Level API fix 2012-12-26 15:52:03 +01:00
4e9df899c2 Fixed plugins not getting loaded 2012-12-26 14:02:50 +01:00
196b0a4263 Updated Interface 2012-12-26 14:02:37 +01:00
39d5fea0ef Double stop fix 2012-12-26 14:02:20 +01:00
d90f317590 Obligation of callable arguments 2012-12-26 13:46:09 +01:00
28048db141 Add getBlockFace method to Level API and BlockFace class 2012-12-26 13:39:39 +01:00
145d0707e6 Check if the Plugin uses the Plugin Interface 2012-12-26 13:38:54 +01:00
987a6e635e Implemented Plugin Interface 2012-12-26 13:33:43 +01:00
00fea6461c Improved the option to cancel handling events 2012-12-26 12:04:44 +01:00
6742273644 Cactus placement fix 2012-12-26 12:04:26 +01:00
bf7913f630 Deleted Server dependency for ExamplePlugin 2012-12-26 12:04:15 +01:00
c82072c998 Unix EOL 2012-12-26 04:20:27 +01:00
cecdf7e28f ChatAPI 2012-12-26 04:14:48 +01:00
06a3db9b45 New plugin: SpawnChanger 2012-12-26 04:14:38 +01:00
7ce0209b6c Fix for block breaking event 2012-12-26 04:14:25 +01:00
b169e269b8 Updated .gitignore 2012-12-26 03:02:28 +01:00
618e9c58c7 Added YAML configuration handling, and info getting methods 2012-12-26 03:02:16 +01:00
1b47a716d3 Updated plugins 2012-12-26 03:01:21 +01:00
ea6fe8312a Fixed unknown spawn, added start event 2012-12-26 03:00:49 +01:00
92c64db1b5 Added getSpawn() method to Level API 2012-12-26 03:00:23 +01:00
16be7d42a7 Added offline data saving/loading handling events 2012-12-26 02:59:53 +01:00
46ded9e675 Future all-memory impossible cleanup 2012-12-26 02:59:30 +01:00
ed42ba5176 Add event and action system alias into Server API 2012-12-26 02:59:02 +01:00
0329e6d217 Mark /give command as DUMMY 2012-12-26 02:56:59 +01:00
af1e3e7767 Save offline player data at connect 2012-12-26 02:56:42 +01:00
cb7e9bb572 Whitelist now uses the clientID as a identifier as soon as the player has logged in one time 2012-12-25 20:51:08 +01:00
504b37cfaa Posibility of changing data for handlers, and canceling it 2012-12-25 20:15:08 +01:00
bf24a937b2 Fix for blank map generation 2012-12-25 18:06:17 +01:00
b79374c13d Correct sapbling, mushroom and reed placing 2012-12-25 18:05:15 +01:00
2d9c400392 Show blocks in hand to other players 2012-12-25 17:25:48 +01:00
f987ff232b Fix for unknown spawn point 2012-12-25 17:04:18 +01:00
9f3523a920 Fix for spawn point 2012-12-25 17:00:47 +01:00
0cb8f28122 Fix for torches 2012-12-25 13:41:01 +01:00
cf5d8e5009 Updated TODO 2012-12-25 12:38:13 +01:00
6ed6c98c64 Fixed placing blocks on redstone ore 2012-12-25 12:17:34 +01:00
5dd0666436 Fixed always torches 2012-12-25 01:20:50 +01:00
e8519f954d Linux startup async I/O script 2012-12-25 01:05:24 +01:00
4695949ddd Fix for Blank generator map 2012-12-25 01:05:10 +01:00
5be1b78a7f Features 2012-12-24 21:00:35 +01:00
c4b8a7350c Tilling, bonemeal usage 2012-12-24 21:00:24 +01:00
333035c285 Opening/closing fence gates/trapdoors 2012-12-24 19:59:57 +01:00
28383deeee Door opening/closing 2012-12-24 19:57:20 +01:00
8b918a7bce errm... fix ^^ 2012-12-24 19:24:30 +01:00
c646b786e5 Kind of Water spreading 2012-12-24 19:22:01 +01:00
a1b51c3da4 Removed from TODO 2012-12-24 16:34:33 +01:00
332202c4e8 Block Updates 2012-12-24 16:34:09 +01:00
849cfcb01b Correct block drops, sapling/flower placing requirements 2012-12-24 14:43:19 +01:00
b0b39b2357 Uh, cactus were done 2012-12-24 14:07:48 +01:00
f2868f386e Correct slab placement 2012-12-24 14:02:04 +01:00
c3eec804f0 Added option to specify Generator name in server.properties 2012-12-24 13:33:50 +01:00
022e25ff05 Removed seed and spawn from server.properties 2012-12-24 13:26:52 +01:00
30a13fb1b4 Updated Features 2012-12-24 13:08:25 +01:00
529bb8a262 Do not drop blocks in creative mode 2012-12-24 13:07:58 +01:00
067147f750 Correct block breaking 2012-12-24 13:07:35 +01:00
30d2b41264 Fix for blocks getting replaced 2012-12-24 03:31:32 +01:00
52810a11ba Correct position for gates,doors,stairs,trapdoors
+ corrected cactus bug
2012-12-24 03:04:06 +01:00
dfa9f55115 Correct Torch/Ladder placing 2012-12-24 01:54:05 +01:00
bcb65c2960 Correct door, cactus, seeds placing 2012-12-24 01:03:18 +01:00
b867ba559e Huge commit (Block API, changed events)
Changed Session to Player
Block API
Block Data
2012-12-24 00:44:13 +01:00
e47bacce74 Moved third-party tools to the Wiki 2012-12-23 21:19:23 +01:00
44546fd11d Do not overwrite worlds and use level-name property 2012-12-23 21:11:45 +01:00
d44ca14eb5 Added things to Todo 2012-12-23 21:03:49 +01:00
8c82f9f9c1 Added to TODO 2012-12-23 20:41:38 +01:00
bbe7aacfaf Inverted metadata nibbles 2012-12-23 20:28:40 +01:00
fe3c054c83 World generation presets with metadata 2012-12-23 20:02:58 +01:00
fbfbd53204 Default Generator Presets 2012-12-23 18:53:37 +01:00
e0c245d86e PluginAPI 2012-12-23 17:37:53 +01:00
99151981db Use latest protocol always 2012-12-23 16:46:08 +01:00
7fef49fbfc Milestones 2012-12-23 09:59:12 +01:00
009ff61208 New TODO 2012-12-23 09:57:11 +01:00
67c9181a06 Github API error handling 2012-12-23 02:19:39 +01:00
3b800ff6b4 Map Generator 2012-12-23 02:02:02 +01:00
1cf47d0328 X,Y,Z in player list 2012-12-22 20:17:34 +01:00
61cfbaf3fd ;) 2012-12-22 17:21:23 +01:00
63 changed files with 6067 additions and 1232 deletions

5
.gitattributes vendored
View File

@ -1,5 +1,10 @@
# Auto detect text files and perform LF normalization
* text=auto
*.php text eol=lf
*.sh text eol=lf
*.txt text eol=lf
*.properties text eol=lf
*.bat text eol=crlf
# Custom for Visual Studio
*.cs diff=csharp

7
.gitignore vendored
View File

@ -1,10 +1,11 @@
data/players/*
data/maps/*
players/*
worlds/*
plugins/*
logs/*
*.log
server.properties
white-list.txt
banned-ips.txt
console.in
#################
## Eclipse

View File

@ -25,17 +25,12 @@ the Free Software Foundation, either version 3 of the License, or
*/
//Protocol Version: 4
require_once(dirname(__FILE__)."/src/common/dependencies.php");
require_once("classes/PocketMinecraftServer.class.php");
require_once("API/ServerAPI.php");
$server = new ServerAPI();
$server->run();//$server->start();
//$server->join();
define("MC_KEEP_ALIVE", 0x00);
define("MC_CLIENT_CONNECT", 0x09);
define("MC_SERVER_HANDSHAKE", 0x10);
define("MC_CLIENT_HANDSHAKE", 0x13);
define("MC_CLIENT_DISCONNECT", 0x15);
define("MC_LOGIN", 0x86);
define("MC_LOGIN_STATUS", 0x87);
define("MC_READY", 0x88);
define("MC_CHAT", 0x89);
define("MC_SET_TIME", 0x8a);
define("MC_START_GAME", 0x8b);
kill(getmypid()); //Fix for segfault

115
README.md
View File

@ -1,82 +1,59 @@
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
```
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
PocketMine-MP
=============
Github repo: https://github.com/shoghicp/PocketMine-MP
```
Server (and client) Minecraft Pocket Edition library written in PHP.
Currently a work in progress, and used to document http://www.wiki.vg/Pocket_Minecraft_Protocol
# PocketMine-MP
How to install it: https://github.com/shoghicp/PocketMine-MP/wiki/Tutorial:-Setting-up-a-Server
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.
**Project Status: `PRE-ALPHA`**
The entire server is done in PHP, and has been tested, profiled and optimized to run smoothly.
**Tested in: `v4.0.0, v5.0.0`**
[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:
-------------------------------
* Players can connect and move around the world (and see each other)
* Support for reading/sending chunks!
* Map saving! Place & remove blocks
* Multiple worlds and importing!
* PvP, life regeneration and death cause!
* Extensible API!
* Online list broadcast
* Configurable day/night cycle
* Mob spawning!
* Health and position saving
* server.properties configuration file
* Whitelist and IP Ban files
* Survival & Creative
* Awesome features in server list!
* Automatic new version checking
* Implemented packet loss recovery algorithm
* + more!
## Current features of the server:
* Full Creative mode!
* Plugin API
* Custom world generation
* Update Channels!! (stable / dev)
How to contact me
-----------------
* Email - <shoghicp@gmail.com>
* Twitter - [@shoghicp](https://twitter.com/shoghicp)
* Via IRC - #mcdevs or #mcpedevs on *irc.freenode.net* (or just /msg me there)
* [MinecraftForums profile](http://www.minecraftforum.net/user/1476633-shoghicp/)
---------------------------------------
Third-party Tools:
------------------
* [How to connect to internet servers](http://www.minecraftforum.net/topic/1256915-legit-minecraftpe-online-multiplayer/)
* [Video-Tutorial made by ChrisMCMine](http://www.youtube.com/watch?v=GC9MBVaHge0)
* [User-made program to merge server I/O done in C++](https://github.com/filfat/MCPES_CPP_INPUT/)
* [Proxy to allow devices in your local network join online servers using node.js](https://github.com/brandon15811/Minecraft-PE-Proxy)
## Third-party Libraries Used
* __[PHP cURL](http://php.net/manual/en/book.curl.php)__
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
* __[PHP SQLite3](http://php.net/manual/en/book.sqlite3.php)__
* __[PHP pthreads](https://github.com/krakjoe/pthreads)__ by _[krakjoe](https://github.com/krakjoe)_: Threading for PHP - Share Nothing, Do Everything
* __[PHP NBT](https://github.com/TheFrozenFire/PHP-NBT-Decoder-Encoder/blob/master/nbt.class.php)__ by _[TheFrozenFire](https://github.com/TheFrozenFire)_: Class for reading in NBT-format files (modified to handle Little-Endian files)
* __[Math_BigInteger](http://phpseclib.sourceforge.net/math/intro.html)__ by _[phpseclib](http://phpseclib.sourceforge.net/)_: Pure-PHP arbitrary precission integer arithmetic library
* __[Spyc](https://github.com/mustangostang/spyc/blob/master/Spyc.php)__ by _[Vlad Andersen](https://github.com/mustangostang)_: A simple YAML loader/dumper class for PHP

4
TODO
View File

@ -1,4 +0,0 @@
- Fix spawn position resetting
- Mob spawning, item pick up
- Inventory loading and saving
- Entity saving

View File

@ -1,328 +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 ServerAPI extends stdClass{ //Yay! I can add anything to this class in runtime!
var $server, $restart = false;
private $config, $apiList = array();
function __construct(){
console("[INFO] Starting ServerAPI server handler...");
file_put_contents(FILE_PATH."packets.log", "");
file_put_contents(FILE_PATH."console.in", "");
if(!file_exists(FILE_PATH."test.bin.log") or md5_file(FILE_PATH."test.bin.log") !== TEST_MD5){
console("[NOTICE] Executing integrity tests...");
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
console("[INFO] uname -a: ".php_uname("a"));
console("[INFO] PHP Version: ".phpversion());
console("[INFO] Endianness: ".ENDIANNESS);
$test = b"";
$test .= Utils::writeLong("5567381823242127440");
$test .= Utils::writeLong("2338608908624488819");
$test .= Utils::writeLong("2333181766244987936");
$test .= Utils::writeLong("2334669371112169504");
$test .= Utils::writeShort(Utils::readShort("\xff\xff\xff\xff"));
$test .= Utils::writeShort(Utils::readShort("\xef\xff\xff\xff"));
$test .= Utils::writeInt(Utils::readInt("\xff\xff\xff\xff"));
$test .= Utils::writeInt(1);
$test .= Utils::writeInt(-1);
$test .= Utils::writeFloat(Utils::readfloat("\xff\xff\xff\xff"));
$test .= Utils::writeFloat(-1.584563155838E+29);
$test .= Utils::writeFloat(1);
$test .= Utils::writeLDouble(Utils::readLDouble("\xff\xff\xff\xff\xff\xff\xff\xff"));
$test .= Utils::writeLong("-1152921504606846977");
$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");
$test .= Utils::writeLong($str->hashCode());
$test .= Utils::writeDataArray(array("a", "b", "c", "\xff\xff\xff\xff"));
$test .= Utils::hexToStr("012334567890");
file_put_contents(FILE_PATH."test.bin.log", $test);
if(md5($test) !== TEST_MD5){
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."common/default.properties", FILE_PATH."server.properties");
}
console("[DEBUG] Checking data folders...", true, true, 2);
@mkdir(FILE_PATH."data/players/", 0777, true);
@mkdir(FILE_PATH."data/maps/", 0777);
@mkdir(FILE_PATH."data/plugins/", 0777);
console("[DEBUG] Loading server.properties...", true, true, 2);
$this->parseProperties();
define("DEBUG", $this->config["debug"]);
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), $this->getProperty("seed"), $this->getProperty("protocol"), $this->getProperty("port"), $this->getProperty("server-id"));
$this->server->api = $this;
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
console("[INFO] Checking for new version...");
$info = json_decode(Utils::curl_get("https://api.github.com/repos/shoghicp/PocketMine-MP"), true);
$last = new DateTime($info["updated_at"]);
$last = $last->getTimestamp();
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false){
console("[NOTICE] PocketMine-MP has been updated at ".date("Y-m-d H:i:s", $last));
console("[NOTICE] If 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{
$last = time();
$this->setProperty("last-update", $last);
console("[INFO] Last check at ".date("Y-m-d H:i:s", $last));
}
}
if(file_exists(FILE_PATH."data/maps/level.dat")){
console("[NOTICE] Detected unimported map data. Importing...");
$this->importMap(FILE_PATH."data/maps/", true);
}
$this->server->mapName = $this->getProperty("level-name");
$this->server->mapDir = FILE_PATH."data/maps/".$this->getProperty("level-name")."/";
$this->loadProperties();
$this->server->loadMap();
//Autoload all default APIs
console("[INFO] Loading default APIs");
$dir = dir(FILE_PATH."classes/API/");
while(false !== ($file = $dir->read())){
if($file !== "." and $file !== ".."){
$API = basename($file, ".php");
if(strtolower($API) !== "serverapi"){
$name = strtolower(substr($API, 0, -3));
$this->loadAPI($name, $API);
}
}
}
foreach($this->apiList as $a){
if(method_exists($this->$a, "init")){
$this->$a->init();
}
}
$this->server->loadEntities();
}
public function getList(){
return $this->apiList;
}
public function loadAPI($name, $class, $dir = false){
if($dir === false){
$dir = FILE_PATH."classes/API/";
}
$file = $dir.$class.".php";
if(!file_exists($file)){
console("[ERROR] API ".$name." [".$class."] in ".$dir." doesn't exist", true, true, 0);
return false;
}
require_once($file);
$this->$name = new $class($this->server);
$this->apiList[] = $name;
console("[INFO] API ".$name." [".$class."] loaded");
}
public function importMap($dir, $remove = false){
if(file_exists($dir."level.dat")){
$nbt = new NBT();
$level = parseNBTData($nbt->loadFile($dir."level.dat"));
console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2);
unset($level["Player"]);
$lvName = $level["LevelName"]."/";
@mkdir(FILE_PATH."data/maps/".$lvName, 0777);
file_put_contents(FILE_PATH."data/maps/".$lvName."level.dat", serialize($level));
$entities = parseNBTData($nbt->loadFile($dir."entities.dat"));
file_put_contents(FILE_PATH."data/maps/".$lvName."entities.dat", serialize($entities["Entities"]));
if(!isset($entities["TileEntities"])){
$entities["TileEntities"] = array();
}
file_put_contents(FILE_PATH."data/maps/".$lvName."tileEntities.dat", serialize($entities["TileEntities"]));
console("[DEBUG] Imported ".count($entities["Entities"])." Entities and ".count($entities["TileEntities"])." TileEntities", true, true, 2);
if($remove === true){
rename($dir."chunks.dat", FILE_PATH."data/maps/".$lvName."chunks.dat");
unlink($dir."level.dat");
@unlink($dir."level.dat_old");
@unlink($dir."player.dat");
unlink($dir."entities.dat");
}else{
copy($dir."chunks.dat", FILE_PATH."data/maps/".$lvName."chunks.dat");
}
if($this->getProperty("level-name") === false){
console("[INFO] Setting default level to \"".$level["LevelName"]."\"");
$this->setProperty("level-name", $level["LevelName"]);
$this->setProperty("gamemode", $level["GameType"]);
$this->server->seed = $level["RandomSeed"];
$this->setProperty("spawn", array("x" => $level["SpawnX"], "y" => $level["SpawnY"], "z" => $level["SpawnZ"]));
$this->writeProperties();
}
console("[INFO] Map \"".$level["LevelName"]."\" importing done!");
unset($level, $entities, $nbt);
return true;
}
return false;
}
public function getProperty($name){
if(isset($this->config[$name])){
return $this->config[$name];
}
return false;
}
public function setProperty($name, $value){
$this->config[$name] = $value;
$this->writeProperties();
$this->loadProperties();
}
private function loadProperties(){
if(isset($this->config["memory-limit"])){
@ini_set("memory_limit", $this->config["memory-limit"]);
}else{
$this->config["memory-limit"] = "256M";
}
if(!isset($this->config["invisible"])){
$this->config["invisible"] = false;
}
if(is_object($this->server)){
$this->server->setType($this->config["server-type"]);
$this->server->timePerSecond = $this->config["time-per-second"];
$this->server->invisible = $this->config["invisible"];
$this->server->maxClients = $this->config["max-players"];
$this->server->description = $this->config["description"];
$this->server->motd = $this->config["motd"];
$this->server->gamemode = $this->config["gamemode"];
$this->server->difficulty = $this->config["difficulty"];
$this->server->spawn = $this->config["spawn"];
$this->server->whitelist = $this->config["white-list"];
$this->server->reloadConfig();
}
}
private function writeProperties(){
if(is_object($this->server)){
$this->config["seed"] = $this->server->seed;
$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){
if($n == "spawn"){
$v = implode(";", $v);
}
$prop .= $n."=".$v."\r\n";
}
file_put_contents(FILE_PATH."server.properties", $prop);
}
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($n){
case "last-update":
if(trim($v) == "false"){
$v = time();
}else{
$v = (int) $v;
}
break;
case "protocol":
if(trim($v) == "CURRENT"){
$v = CURRENT_PROTOCOL;
break;
}
case "gamemode":
case "max-players":
case "port":
case "debug":
case "difficulty":
case "time-per-second":
$v = (int) $v;
break;
case "seed":
$v = trim($v);
if($v == "false"){
$v = false;
}elseif(preg_match("/[^0-9\-]/", $v) > 0){
$str = new Java_String($v);
$v = $str->hashCode();
}else{
$v = (int) $v;
}
break;
case "server-id":
$v = trim($v);
$v = $v == "false" ? false:(preg_match("/[^0-9\-]/", $v) > 0 ? Utils::readInt(substr(md5($v, true), 0, 4)):$v);
break;
case "level-name":
$v = trim($v);
$v = $v == "false" ? false:$v;
break;
case "spawn":
$v = explode(";", $v);
$v = array("x" => floatval($v[0]), "y" => floatval($v[1]), "z" => floatval($v[2]));
break;
case "white-list":
case "invisible":
$v = trim($v) == "true" ? true:false;
break;
}
$this->config[$n] = $v;
}
}
public function start(){
$this->server->start();
unregister_tick_function(array($this->server, "tick"));
unset($this->server);
return $this->restart;
}
}

View File

@ -1,20 +0,0 @@
#Pocket Minecraft PHP server properties
server-name=PHP Server
description= This is a Work in Progress custom server.
motd=Welcome to PHP Server
invisible=false
port=19132
protocol=CURRENT
memory-limit=256M
last-update=false
white-list=false
debug=2
max-players=20
server-type=normal
time-per-second=20
gamemode=1
difficulty=1
seed=false
level-name=false
server-id=false
spawn=128.5;100;128.5

134
compile_php.sh Normal file
View File

@ -0,0 +1,134 @@
#!/bin/bash
echo "[PocketMine] PHP installer and compiler for Linux - by @shoghicp v0.3"
DIR=`pwd`
date > $DIR/install.log
uname -a >> $DIR/install.log
echo "[INFO] Checking dependecies"
type make >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"make\""; exit 1; }
type autoconf >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"autoconf\""; exit 1; }
type automake >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"automake\""; exit 1; }
type gcc >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"gcc\""; exit 1; }
type m4 >> $DIR/install.log 2>&1 || { echo >&2 "[ERROR] Please install \"m4\""; exit 1; }
rm -r -f install_data/ >> $DIR/install.log 2>&1
rm -r -f php5/ >> $DIR/install.log 2>&1
mkdir -m 0777 install_data >> $DIR/install.log 2>&1
mkdir -m 0777 php5 >> $DIR/install.log 2>&1
cd install_data
#PHP 5
echo -n "[PHP5] downloading..."
wget http://php.net/get/php-5.4.10.tar.gz/from/this/mirror -O php-5.4.10.tar.gz >> $DIR/install.log 2>&1
echo -n " extracting..."
tar -zxvf php-5.4.10.tar.gz >> $DIR/install.log 2>&1
rm -f php-5.4.10.tar.gz >> $DIR/install.log 2>&1
mv php-5.4.10 php
echo " done!"
#zlib
echo -n "[zlib] downloading..."
wget http://zlib.net/zlib-1.2.7.tar.gz -O zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
echo -n " extracting..."
tar -zxvf zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
rm -f zlib-1.2.7.tar.gz >> $DIR/install.log 2>&1
mv zlib-1.2.7 zlib
echo -n " compiling..."
cd zlib
./configure --prefix=$DIR/install_data/php/ext/zlib >> $DIR/install.log 2>&1
make >> $DIR/install.log 2>&1
echo -n " installing..."
make install >> $DIR/install.log 2>&1
echo -n " cleaning..."
cd ..
rm -r -f ./zlib
echo " done!"
#OpenSSL
#echo -n "[OpenSSL] downloading..."
#wget ftp://ftp.openssl.org/source/openssl-1.0.1c.tar.gz -O openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
#echo -n " extracting..."
#tar -zxvf openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
#rm -f openssl-1.0.1c.tar.gz >> $DIR/install.log 2>&1
#mv openssl-1.0.1c openssl
#echo -n " compiling..."
#cd openssl
#./config --prefix=$DIR/install_data/php/ext/openssl >> $DIR/install.log 2>&1
#make >> $DIR/install.log 2>&1
#echo -n " installing..."
#make install >> $DIR/install.log 2>&1
#echo -n " cleaning..."
#cd ..
#rm -r -f ./openssl
#echo " done!"
#GMP
echo -n "[GMP] downloading..."
wget ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.0.tar.bz2 -O gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
echo -n " extracting..."
tar -jxvf gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
rm -f gmp-5.1.0.tar.bz2 >> $DIR/install.log 2>&1
mv gmp-5.1.0 gmp
echo -n " compiling..."
cd gmp
./configure --prefix=$DIR/install_data/php/ext/gmp >> $DIR/install.log 2>&1
make >> $DIR/install.log 2>&1
echo -n " installing..."
make install >> $DIR/install.log 2>&1
echo -n " cleaning..."
cd ..
rm -r -f ./gmp
echo " done!"
echo -n "[cURL] downloading..."
wget https://github.com/bagder/curl/archive/master.tar.gz --no-check-certificate -O curl-master.tar.gz >> $DIR/install.log 2>&1
echo -n " extracting..."
tar -zxvf curl-master.tar.gz >> $DIR/install.log 2>&1
rm -f curl-master.tar.gz >> $DIR/install.log 2>&1
mv curl-master curl
echo -n " compiling..."
cd curl
./buildconf >> $DIR/install.log 2>&1
./configure --prefix=$DIR/install_data/php/ext/curl >> $DIR/install.log 2>&1
make >> $DIR/install.log 2>&1
echo -n " installing..."
make install >> $DIR/install.log 2>&1
echo -n " cleaning..."
cd ..
rm -r -f ./curl
echo " done!"
#pthreads
echo -n "[PHP pthreads] downloading..."
wget https://github.com/krakjoe/pthreads/archive/master.tar.gz --no-check-certificate -O pthreads-master.tar.gz >> $DIR/install.log 2>&1
echo -n " extracting..."
tar -zxvf pthreads-master.tar.gz >> $DIR/install.log 2>&1
rm -f pthreads-master.tar.gz >> $DIR/install.log 2>&1
mv pthreads-master $DIR/install_data/php/ext/pthreads
echo " done!"
#--with-openssl=$DIR/install_data/php/ext/openssl
echo -n "[PHP5] compiling..."
cd php
./buildconf --force >> $DIR/install.log 2>&1
./configure --prefix=$DIR/php5 \
--exec-prefix=$DIR/php5 \
--enable-embedded-mysqli \
--enable-bcmath \
--with-gmp=$DIR/install_data/php/ext/gmp \
--with-curl=$DIR/install_data/php/ext/curl \
--with-zlib=$DIR/install_data/php/ext/zlib \
--disable-xml \
--without-pear \
--enable-sockets \
--enable-pthreads \
--enable-maintainer-zts \
--enable-cli >> $DIR/install.log 2>&1
make >> $DIR/install.log 2>&1
make install >> $DIR/install.log 2>&1
echo " done!"
cd $DIR
echo -n "[INFO] Cleaning up..."
rm -r -f install_data/ >> $DIR/install.log 2>&1
rmdir install_data/ >> $DIR/install.log 2>&1
echo " done!"
echo "[PocketMine] You should start the server now using \"./start.sh\""
echo "[PocketMine] If it doesn't works, please send the \"install.log\" file to the Bug Tracker"

View File

@ -1,2 +0,0 @@
To import a Pocket Edition Map, drop to the folder "maps"
the chunk.dat, level.dat and entities.dat from the savegame file.

View File

@ -1,29 +0,0 @@
<?php
/*
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
require_once("common/dependencies.php");
require_once("classes/PocketMinecraftServer.class.php");
require_once("classes/API/ServerAPI.php");
while(true){
$server = new ServerAPI();
//You can add simple things here
if($server->start() !== true){
break;
}else{
$server = null;
console("[NOTICE] The server is restarting... (".gc_collect_cycles()." cycles collected)", true, true, 0);
}
}

939
src/API/BlockAPI.php Normal file
View File

@ -0,0 +1,939 @@
<?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("BLOCK_UPDATE_NORMAL", 0);
define("BLOCK_UPDATE_RANDOM", 1);
define("BLOCK_UPDATE_SCHEDULED", 2);
define("BLOCK_UPDATE_WEAK", 3);
class BlockAPI{
private $server;
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function init(){
$this->server->addHandler("world.block.update", array($this, "updateBlockRemote"), 1);
$this->server->addHandler("player.block.break", array($this, "blockBreak"), 1);
$this->server->addHandler("player.block.action", array($this, "blockAction"), 1);
$this->server->api->console->register("give", "Give items to a player", array($this, "commandHandler"));
}
public function commandHandler($cmd, $params){
switch($cmd){
case "give":
if(!isset($params[0]) or !isset($params[1])){
console("[INFO] Usage: /give <username> <item> [amount] [damage]");
break;
}
$username = $params[0];
$b = explode(":", $params[1]);
if(!isset($b[1])){
$meta = 0;
}else{
$meta = (int) $b[1];
}
$block = ((int) $b[0]) & 0xFFFF;
if(!isset($params[2])){
$amount = 64;
}else{
$amount = (int) $params[2];
}
if(isset($params[3])){
$meta = (int) $params[3];
}
if(($player = $this->server->api->player->get($username)) !== false){
$this->drop($player->entity->x - 0.5, $player->entity->y, $player->entity->z - 0.5, $block, $meta, $amount);
console("[INFO] Giving ".$amount." of ".$block.":".$meta." to ".$username);
}else{
console("[INFO] Unknown player");
}
break;
}
}
private function cancelAction($block){
$this->server->api->dhandle("world.block.change", array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2],
"block" => $block[0],
"meta" => $block[1],
"fake" => true,
));
return false;
}
public function blockBreak($data, $event){
if($event !== "player.block.break"){
return;
}
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
if(isset(Material::$unbreakable[$target[0]])){
return $this->cancelAction($target);
}
$drop = array(
$target[0], //Block
$target[1], //Meta
1, //Count
);
switch($target[0]){
case 1:
$drop[0] = 4;
break;
case 16:
$drop = array(263, 0, 1);
break;
case 21:
$drop = array(351, 4, mt_rand(4, 8));
break;
case 62:
$drop[0] = 61;
case 50: //Drop without metadata
case 53:
case 54:
case 61:
case 65:
case 67:
case 96:
case 107:
case 108:
case 109:
$drop[1] = 0;
break;
case 56:
$drop = array(264, 0, 1);
break;
case 73:
case 74:
$drop = array(351, 4, mt_rand(4, 5));
break;
case 18:
$drop = false;
if(mt_rand(1,20) === 1){ //Saplings
$drop = array(6, $target[1], 1);
}
if($target[1] === 0 and mt_rand(1,200) === 1){ //Apples
$this->drop($data["x"], $data["y"], $data["z"], 260, 0, 1);
}
break;
case 59:
if($target[1] >= 0x07){ //Seeds
$drop = array(296, 0, 1);
$this->drop($data["x"], $data["y"], $data["z"], 295, 0, mt_rand(0,3));
}else{
$drop = array(295, 0, 1);
}
break;
case 31:
$drop = false;
if(mt_rand(1,10) === 1){ //Seeds
$drop = array(295, 0, 1);
}
break;
case 20:
$drop = false;
break;
case 30:
$drop = false;
break;
case 51:
$drop = false;
break;
case 52:
$drop = false;
break;
case 43:
$drop = array(
44,
$target[1],
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: //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] === $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] === $target[0]){
$data2 = $data;
++$data2["y"];
$this->server->trigger("player.block.break", $data2);
}
}
break;
}
if($drop !== false and $drop[0] !== 0 and $drop[2] > 0){
$this->drop($data["x"], $data["y"], $data["z"], $drop[0], $drop[1] & 0x0F, $drop[2] & 0xFF);
}
$this->server->trigger("player.block.break", $data);
return false;
}
public function drop($x, $y, $z, $block, $meta, $stack = 1){
if($block === 0 or $stack <= 0 or $this->server->gamemode === 1){
return;
}
$data = array(
"x" => $x,
"y" => $y,
"z" => $z,
"meta" => $meta,
"stack" => $stack,
);
$data["x"] += mt_rand(2, 8) / 10;
$data["y"] += 0.19;
$data["z"] += mt_rand(2, 8) / 10;
if($this->server->api->handle("block.drop", $data) !== false){
for($count = $stack; $count > 0; ){
$data["stack"] = min(64, $count);
$count -= $data["stack"];
$e = $this->server->api->entity->add(ENTITY_ITEM, $block, $data);
$this->server->api->entity->spawnToAll($e->eid);
}
}
}
public function blockAction($data, $event){
if($event !== "player.block.action"){
return;
}
if($data["face"] < 0 or $data["face"] > 5){
return false;
}
$target = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
if($target[0] === 0){ //If no block exists
$this->cancelAction($target);
$block = $this->server->api->level->getBlockFace($target, $data["face"]);
return $this->cancelAction($block);
}
$cancelPlace = false;
if(isset(Material::$activable[$target[0]])){
switch($target[0]){
case 54:
$cancelPlace = true;
if($this->server->gamemode === 1){
break;
}
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
"windowid" => 1,
"type" => WINDOW_CHEST,
"slots" => 27,
"title" => "Chest",
));
break;
case 61:
case 62:
$cancelPlace = true;
if($this->server->gamemode === 1){
break;
}
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
"windowid" => 1,
"type" => WINDOW_FURNACE,
"slots" => 3,
"title" => "Furnace",
));
break;
case 6:
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
Sapling::growTree($this->server->api->level, $target, $target[1] & 0x03);
$cancelPlace = true;
}
break;
case 2:
case 3:
if($data["block"] === 292){ //Hoe
$data["block"] = 60;
$data["meta"] = 0;
$this->server->handle("player.block.place", $data);
$cancelPlace = true;
}
case 59:
case 105:
if($data["block"] === 351 and $data["meta"] === 0x0F){ //Bonemeal
$data["block"] = $target[0];
$data["meta"] = 0x07;
$this->server->handle("player.block.place", $data);
$cancelPlace = true;
}
break;
case 64: //Door
if(($target[1] & 0x08) === 0x08){
$down = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
if($down[0] === 64){
$down[1] = $down[1] ^ 0x04;
$data2 = array(
"x" => $data["x"],
"z" => $data["z"],
"y" => $data["y"] - 1,
"block" => $down[0],
"meta" => $down[1],
"eid" => $data["eid"],
);
if($this->server->handle("player.block.update", $data2) !== false){
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
}
}
}else{
$data["block"] = $target[0];
$data["meta"] = $target[1] ^ 0x04;
if($this->server->handle("player.block.update", $data) !== false){
$up = $this->server->api->level->getBlock($data["x"], $data["y"] + 1, $data["z"]);
if($up[0] === 64){
$data2 = $data;
$data2["meta"] = $up[1];
++$data2["y"];
$this->updateBlocksAround($data2["x"], $data2["y"], $data2["z"], BLOCK_UPDATE_NORMAL);
}
$this->updateBlocksAround($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_NORMAL);
}
}
$cancelPlace = true;
break;
case 96: //Trapdoor
case 107: //Fence gates
$data["block"] = $target[0];
$data["meta"] = $target[1] ^ 0x04;
$this->server->handle("player.block.update", $data);
$cancelPlace = true;
break;
default:
$cancelPlace = true;
break;
}
}
if($cancelPlace === true){
return false;
}
$replace = false;
switch($target[0]){
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;
}
break;
}
if($replace === false){
BlockFace::setPosition($data, $data["face"]);
}
if($data["y"] >= 127){
return false;
}
$block = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"]);
if($replace === false and !isset(Material::$replaceable[$block[0]])){
return $this->cancelAction($block);
}
if(isset(Material::$placeable[$data["block"]])){
$data["block"] = Material::$placeable[$data["block"]] === true ? $data["block"]:Material::$placeable[$data["block"]];
}else{
return $this->cancelAction($block);
}
$entity = $this->server->api->entity->get($data["eid"]);
if(($entity instanceof Entity) !== true){
return $this->cancelAction($block); //No Entity WTF?
}
if($entity->inBlock($block[2][0], $block[2][1], $block[2][2])){
return $this->cancelAction($block); //Entity in block
}
$direction = $entity->getDirection();
switch($data["block"]){
case 6:
if($target[0] === 60){
break;
}
case 37:
case 38:
if(($target[0] !== 2 and $target[0] !== 3) or $data["face"] !== 1){
return false;
}
break;
case 39://Mushrooms
case 40:
$blockDown = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
if(isset(Material::$transparent[$blockDown[0]])){
return false;
}
break;
case 83: //Sugarcane
$blockDown = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
if($blockDown[0] !== 2 and $blockDown[0] !== 3 and $blockDown[0] !== 12){
return false;
}
$block0 = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"] + 1);
$block1 = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"] - 1);
$block2 = $this->server->api->level->getBlock($data["x"] + 1, $data["y"], $data["z"]);
$block3 = $this->server->api->level->getBlock($data["x"] - 1, $data["y"], $data["z"]);
if($block0[0] === 9 or $block0[0] === 8 or $block1[0] === 9 or $block1[0] === 8 or $block2[0] === 9 or $block2[0] === 8 or $block3[0] === 9 or $block3[0] === 8){
}else{
return false;
}
break;
case 50: //Torch
if(isset(Material::$transparent[$target[0]])){
return false;
}
$faces = array(
0 => 6,
1 => 5,
2 => 4,
3 => 3,
4 => 2,
5 => 1,
);
if(!isset($faces[$data["face"]])){
return false;
}
$data["meta"] = $faces[$data["face"]];
break;
case 53://Stairs
case 67:
case 108:
$faces = array(
0 => 0,
1 => 2,
2 => 1,
3 => 3,
);
$data["meta"] = $faces[$direction] & 0x03;
break;
case 96: //trapdoor
if(isset(Material::$transparent[$target[0]])){
return false;
}
$faces = array(
2 => 0,
3 => 1,
4 => 2,
5 => 3,
);
if(!isset($faces[$data["face"]])){
return false;
}
$data["meta"] = $faces[$data["face"]] & 0x03;
break;
case 107: //Fence gate
$faces = array(
0 => 3,
1 => 0,
2 => 1,
3 => 2,
);
$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]])){
return false;
}else{
$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);
}
break;
case 54:
case 61:
$faces = array(
0 => 4,
1 => 2,
2 => 5,
3 => 3,
);
$data["meta"] = $faces[$direction];
break;
case 26: //bed
$face = array(
0 => 3,
1 => 4,
2 => 2,
3 => 5,
);
$next = $this->server->api->level->getBlockFace($block, $face[(($direction + 3) % 4)]);
if(!isset(Material::$replaceable[$next[0]])){
return false;
}
$data["meta"] = (($direction + 3) % 4) & 0x3;
$data2 = $data;
$data2["meta"] = $data2["meta"] | 0x08;
$data2["x"] = $next[2][0];
$data2["y"] = $next[2][1];
$data2["z"] = $next[2][2];
$this->server->handle("player.block.place", $data2);
break;
case 65: //Ladder
if(isset(Material::$transparent[$target[0]])){
return false;
}
$faces = array(
2 => 2,
3 => 3,
4 => 4,
5 => 5,
);
if(!isset($faces[$data["face"]])){
return false;
}
$data["meta"] = $faces[$data["face"]];
break;
case 59://Seeds
case 105:
$blockDown = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
if($blockDown[0] !== 60){
return false;
}
$data["meta"] = 0;
break;
case 81: //Cactus
$blockDown = $this->server->api->level->getBlock($data["x"], $data["y"] - 1, $data["z"]);
$block0 = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"] + 1);
$block1 = $this->server->api->level->getBlock($data["x"], $data["y"], $data["z"] - 1);
$block2 = $this->server->api->level->getBlock($data["x"] + 1, $data["y"], $data["z"]);
$block3 = $this->server->api->level->getBlock($data["x"] - 1, $data["y"], $data["z"]);
if($blockDown[0] !== 12 or !isset(Material::$transparent[$block0[0]]) or !isset(Material::$transparent[$block1[0]]) or !isset(Material::$transparent[$block2[0]]) or !isset(Material::$transparent[$block3[0]])){
return false;
}
break;
}
$this->server->handle("player.block.place", $data);
return false;
}
public function blockScheduler($data){
$this->updateBlock($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_SCHEDULED);
}
public function updateBlockRemote($data, $event){
if($event !== "block.update"){
return;
}
$this->updateBlock($data["x"], $data["y"], $data["z"], isset($data["type"]) ? $data["type"]:BLOCK_UPDATE_RANDOM);
}
public function flowLavaOn($source, $face){
$down = 0;
if($face === BlockFace::BOTTOM){
$level = 0;
$down = 1;
}else{
$level = ($source[1] & 0x07) + 2;
if($level > 0x07){
return false;
}
}
$spread = $this->server->api->level->getBlockFace($source, $face);
if(($source[0] === 10 or $source[0] === 11) and $spread[0] === 10){
if($level < ($spread[1] & 0x07)){
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
"y" => $spread[2][1],
"z" => $spread[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
return true;
}
}elseif(isset(Material::$flowable[$spread[0]])){
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
"y" => $spread[2][1],
"z" => $spread[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 10, $level | $down, false);
return true;
}elseif(($source[1] & 0x08) === 0x08){
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false);
return true;
}
return false;
}
public function flowWaterOn($source, $face){
$down = 0;
if($face === BlockFace::BOTTOM){
$level = 0;
$down = 1;
}else{
$level = ($source[1] & 0x07) + 1;
if($level > 0x07){
return false;
}
}
$spread = $this->server->api->level->getBlockFace($source, $face);
if(($source[0] === 8 or $source[0] === 9) and $spread[0] === 8){
if($level < ($spread[1] & 0x07)){
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
"y" => $spread[2][1],
"z" => $spread[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false);
return true;
}
}elseif(isset(Material::$flowable[$spread[0]])){
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $spread[2][0],
"y" => $spread[2][1],
"z" => $spread[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 8, $level | $down, false);
return true;
}elseif(($source[1] & 0x08) === 0x08){
$this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false);
return true;
}
return false;
}
public function updateBlock($x, $y, $z, $type = BLOCK_UPDATE_NORMAL){
$block = $this->server->api->level->getBlock($x, $y, $z);
$changed = false;
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);
}
if($block[0] === 8){
$drained = true;
$level = $block[1] & 0x07;
$up = $this->server->api->level->getBlockFace($block, BlockFace::UP);
if($up[0] === 8 or $up[0] === 9){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::NORTH);
if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::SOUTH);
if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::EAST);
if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::WEST);
if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}
}
}
}
}
if($drained === true){
++$level;
if($level > 0x07){
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0] + 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0] - 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] + 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] - 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1] - 1,
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false);
}else{
$block[1] = ($block[1] & 0x08) | $level;
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0] + 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0] - 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] + 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] - 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1] - 1,
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(10, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false);
}
}
}
break;
case 10:
case 11:
if(!$this->flowLavaOn($block, 0) or $block[0] === 11){
$this->flowLavaOn($block, 2);
$this->flowLavaOn($block, 3);
$this->flowLavaOn($block, 4);
$this->flowLavaOn($block, 5);
}
if($block[0] === 10){
$drained = true;
$level = $block[1] & 0x07;
$up = $this->server->api->level->getBlockFace($block, BlockFace::UP);
if($up[0] === 10 or $up[0] === 11){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::NORTH);
if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::SOUTH);
if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::EAST);
if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}else{
$b = $this->server->api->level->getBlockFace($block, BlockFace::WEST);
if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){
$drained = false;
}
}
}
}
}
if($drained === true){
++$level;
if($level > 0x07){
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0] + 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0] - 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] + 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] - 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1] - 1,
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false);
}else{
$block[1] = ($block[1] & 0x08) | $level;
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0] + 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0] - 1,
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] + 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2] - 1,
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1] - 1,
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->schedule(20, array($this, "blockScheduler"), array(
"x" => $block[2][0],
"y" => $block[2][1],
"z" => $block[2][2],
"type" => BLOCK_UPDATE_NORMAL,
));
$this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false);
}
}
}
break;
case 74:
if($type === BLOCK_UPDATE_SCHEDULED or $type === BLOCK_UPDATE_RANDOM){
$changed = true;
$this->server->api->level->setBlock($x, $y, $z, 73, $block[1], false);
$type = BLOCK_UPDATE_WEAK;
}
break;
case 73:
if($type === BLOCK_UPDATE_NORMAL){
$changed = true;
$this->server->api->level->setBlock($x, $y, $z, 74, $block[1], false);
$this->server->schedule(mt_rand(40, 100), array($this, "blockScheduler"), array(
"x" => $x,
"y" => $y,
"z" => $z,
));
$type = BLOCK_UPDATE_WEAK;
}
break;
}
if($type === BLOCK_TYPE_SCHEDULED){
$type = BLOCK_UPDATE_WEAK;
}
if($changed === true){
$this->updateBlocksAround($x, $y, $z, $type);
}
}
public function updateBlocksAround($x, $y, $z, $type){
$this->updateBlock($x + 1, $y, $z, $type);
$this->updateBlock($x, $y + 1, $z, $type);
$this->updateBlock($x, $y, $z + 1, $type);
$this->updateBlock($x - 1, $y, $z, $type);
$this->updateBlock($x, $y - 1, $z, $type);
$this->updateBlock($x, $y, $z - 1, $type);
}
}

51
src/API/ChatAPI.php Normal file
View File

@ -0,0 +1,51 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class ChatAPI{
private $server;
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function init(){
}
public function broadcast($message){
$this->send(false, $message);
}
public function send($owner, $text, $whitelist = false, $blacklist = false){
$message = "";
if($owner !== false){
$message = "<".$owner."> ";
}
$message .= $text;
console("[CHAT] ".$message);
$this->server->handle("server.chat", new Container($message, $whitelist, $blacklist));
}
}

View File

@ -26,25 +26,34 @@ the Free Software Foundation, either version 3 of the License, or
*/
class ConsoleAPI{
private $input, $server, $event;
function __construct($server){
private $loop, $server, $event, $help, $cmds;
function __construct(PocketMinecraftServer $server){
$this->help = array();
$this->cmds = array();
$this->server = $server;
$this->input = fopen(FILE_PATH."console.in", "w+b");
$this->last = microtime(true);
}
public function init(){
$this->event = $this->server->event("onTick", array($this, "handle"));
$this->event = $this->server->event("server.tick", array($this, "handle"));
$this->loop = new ConsoleLoop;
$this->loop->start();
}
function __destroy(){
function __destruct(){
$this->server->deleteEvent($this->event);
fclose($this->input);
$this->loop->stop = true;
$this->loop->notify();
$this->loop->join();
}
public function defaultCommands($cmd, $params){
switch($cmd){
case "crash": //Crashes the server to generate an report
$this->callNotDefinedMethodCrash();
$this->server->api->server; //Access a private property
callNotExistingFunction();
break;
case "invisible":
$p = strtolower(array_shift($params));
switch($p){
@ -74,6 +83,7 @@ class ConsoleAPI{
$this->server->api->setProperty("last-update", time());
break;
case "stop":
$this->loop->stop = true;
console("[INFO] Stopping the server...");
$this->server->close();
break;
@ -88,7 +98,7 @@ class ConsoleAPI{
case "pardon":
case "remove":
$ip = trim(implode($params));
$new = array();
$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");
@ -142,14 +152,14 @@ class ConsoleAPI{
console("[INFO] Usage: /say <message>");
break;
}
$this->server->chat(false, $s);
$this->server->api->chat->broadcast($s);
break;
case "whitelist":
$p = strtolower(array_shift($params));
switch($p){
case "remove":
$user = trim(implode(" ", $params));
$new = array();
$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");
@ -212,7 +222,7 @@ class ConsoleAPI{
console("[INFO] /stop: Stops the server");
//console("[INFO] /restart: Restarts the server");
foreach($this->help as $c => $h){
console("[INFO] /$c: ".$h[0]);
console("[INFO] /$c: ".$h);
}
break;
default:
@ -220,28 +230,50 @@ class ConsoleAPI{
break;
}
}
public function register($cmd, $help, $callback){
$this->help[strtolower(trim($cmd))] = array($help, $callback);
}
public function handle($time){
while(($line = fgets($this->input)) !== false){
$line = trim($line);
if($line === ""){
continue;
}
$params = explode(" ", $line);
$cmd = strtolower(array_shift($params));
console("[INFO] Issued server command: /$cmd ".implode(" ", $params));
if(isset($this->help[$cmd]) and is_callable($this->help[$cmd][1])){
call_user_func($this->help[$cmd][1], $cmd, $params);
}elseif($this->server->trigger("onCommand", array("cmd" => $cmd, "params" => $params)) !== false){
$this->defaultCommands($cmd, $params);
}
}
ftruncate($this->input, 0);
fseek($this->input, 0);
public function alias($alias, $cmd){
$this->cmds[strtolower(trim($alias))] = &$this->cmds[$cmd];
}
public function register($cmd, $help, $callback){
if(!is_callable($callback)){
return false;
}
$cmd = strtolower(trim($cmd));
$this->cmds[$cmd] = $callback;
$this->help[$cmd] = $help;
}
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);
}
}
}else{
$this->loop->notify();
}
}
}
class ConsoleLoop extends Thread{
var $line = false, $stop = false;
public function run(){
$fp = fopen("php://stdin", "r");
while($this->stop === false and ($line = fgets($fp)) !== false){
$this->line = $line;
$this->wait();
$this->line = false;
}
exit(0);
}
}

View File

@ -27,46 +27,8 @@ the Free Software Foundation, either version 3 of the License, or
class EntityAPI{
private $server;
function __construct($server){
function __construct(PocketMinecraftServer $server){
$this->server = $server;
$this->server->addHandler("onPlayerDeath", array($this, "handle"), 1);
}
public function init(){
$this->server->api->console->register("give", "Give items to a player", array($this, "commandHandler"));
}
public function handle($data, $event){
switch($event){
case "onPlayerDeath":
$message = $data["name"];
if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){
$e = $this->api->entity->get($data["cause"]);
switch($e->class){
case ENTITY_PLAYER:
$message .= " was killed by ".$e->name;
break;
default:
$message .= " was killed";
break;
}
}else{
switch($data["cause"]){
default:
$message .= " was killed";
break;
}
}
$this->server->chat(false, $message);
break;
}
}
public function commandHandler($cmd, $params){
switch($cmd){
case "give":
break;
}
}
public function get($eid){
@ -76,14 +38,18 @@ class EntityAPI{
return false;
}
public function init(){
}
public function getAll(){
return $this->server->entities;
}
public function heal($eid, $heal = 1, $cause){
$this->harm($eid, -$heal, $cause);
}
public function harm($eid, $attack = 1, $cause){
$e = $this->get($eid);
if($e === false or $e->dead === true){
@ -91,13 +57,14 @@ class EntityAPI{
}
$e->setHealth($e->getHealth()-$attack, $cause);
}
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];
}
public function spawnTo($eid, $player){
$e = $this->get($eid);
if($e === false){
@ -105,7 +72,7 @@ class EntityAPI{
}
$e->spawn($player);
}
public function spawnToAll($eid){
$e = $this->get($eid);
if($e === false){
@ -117,17 +84,20 @@ class EntityAPI{
}
}
}
public function spawnAll($player){
foreach($this->getAll() as $e){
$e->spawn($player);
}
}
public function remove($eid){
if(isset($this->server->entities[$eid])){
$this->server->entities[$eid]->close();
$entity = $this->server->entities[$eid];
unset($this->server->entities[$eid]);
$this->server->query("DELETE FROM entities WHERE EID = ".$entity->eid.";");
$this->server->api->dhandle("entity.remove", $entity);
unset($entity);
}
}
}
}

View File

@ -26,97 +26,84 @@ the Free Software Foundation, either version 3 of the License, or
*/
class LevelAPI{
private $server, $map, $active = false;
function __construct($server){
private $server, $map;
function __construct(PocketMinecraftServer $server){
$this->server = $server;
$this->map = $this->server->map;
if($this->map !== false){
$this->active = true;
}
$this->heightMap = array_fill(0, 256, array());
}
public function init(){
$this->server->addHandler("onBlockBreak", array($this, "handle"));
$this->server->addHandler("onBlockPlace", array($this, "handle"));
$this->server->event("player.block.break", array($this, "handle"));
$this->server->event("player.block.place", array($this, "handle"));
$this->server->event("player.block.update", array($this, "handle"));
}
public function handle($data, $event){
switch($event){
case "onBlockPlace":
$block = $this->getBlock($data["x"], $data["y"], $data["z"]);
console("[DEBUG] EID ".$data["eid"]." placed ".$data["block"].":".$data["meta"]." into ".$block[0].":".$block[1]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
case "player.block.place":
case "player.block.update":
console("[DEBUG] EID ".$data["eid"]." placed ".$data["block"].":".$data["meta"]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
$this->setBlock($data["x"], $data["y"], $data["z"], $data["block"], $data["meta"]);
break;
case "onBlockBreak":
$block = $this->getBlock($data["x"], $data["y"], $data["z"]);
console("[DEBUG] EID ".$data["eid"]." broke block ".$block[0].":".$block[1]." at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
if($block[0] === 0){
break;
}
$this->setBlock($data["x"], $data["y"], $data["z"], 0, 0);
$data["block"] = $block[0];
$data["meta"] = $block[1];
$data["stack"] = 1;
$data["x"] += mt_rand(2, 8) / 10;
$data["y"] += mt_rand(2, 8) / 10;
$data["z"] += mt_rand(2, 8) / 10;
$e = $this->server->api->entity->add(ENTITY_ITEM, $block[0], $data);
$this->server->api->entity->spawnToAll($e->eid);
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);
break;
}
}
private function check(){
if($this->active === true){
return true;
}elseif($this->active === false and $this->server->map === false){
return false;
}
$this->active = true;
return true;
public function getSpawn(){
return $this->server->spawn;
}
public function getChunk($X, $Z){
if($this->check() and isset($this->map->map[$X][$Z])){
return $this->map->map[$X][$Z];
}
return false;
return $this->map->map[$X][$Z];
}
public function getBlockFace($block, $face){
$data = array("x" => $block[2][0], "y" => $block[2][1], "z" => $block[2][2]);
BlockFace::setPosition($data, $face);
return $this->getBlock($data["x"], $data["y"], $data["z"]);
}
public function getBlock($x, $y, $z){
if($this->check()){
return $this->map->getBlock($x, $y, $z);
}
return array(0,0);
$b = $this->map->getBlock($x, $y, $z);
$b[2] = array($x, $y, $z);
return $b;
}
public function getFloor($x, $z){
if($this->check()){
return $this->map->getFloor($x, $z);
if(!isset($this->heightMap[$z][$x])){
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z);
}
return 0;
return $this->heightMap[$z][$x];
}
public function setBlock($x, $y, $z, $block, $meta = 0){
if($this->check()){
$this->map->setBlock($x, $y, $z, $block, $meta);
}
$this->server->trigger("onBlockUpdate", array(
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("block.change", array(
"x" => $x,
"y" => $y,
"z" => $z,
"block" => $block,
"meta" => $meta,
));
)) !== false){
if($update === true){
$this->server->api->block->updateBlock($x, $y, $z, BLOCK_UPDATE_NORMAL);
$this->server->api->block->updateBlocksAround($x, $y, $z, BLOCK_UPDATE_NORMAL);
}
}
}
public function getOrderedChunk($X, $Z, $columnsPerPacket = 2){
$columnsPerPacket = max(1, (int) $columnsPerPacket);
$c = $this->getChunk($X, $Z);
if($c === false){
return array(str_repeat("\x00", 256));
}
$ordered = array();
$i = 0;
$cnt = 0;

View File

@ -27,31 +27,55 @@ the Free Software Foundation, either version 3 of the License, or
class PlayerAPI{
private $server;
function __construct($server){
function __construct(PocketMinecraftServer $server){
$this->server = $server;
$this->server->event("onHealthRegeneration", array($this, "handle"));
}
public function init(){
$this->server->addHandler("server.regeneration", array($this, "handle"));
$this->server->addHandler("player.death", array($this, "handle"), 1);
$this->server->api->console->register("list", "Shows connected player list", array($this, "commandHandler"));
$this->server->api->console->register("kill", "Kills a player", array($this, "commandHandler"));
$this->server->api->console->register("tppos", "Teleports a player to a position", array($this, "commandHandler"));
$this->server->api->console->register("tp", "Teleports a player to another player", array($this, "commandHandler"));
}
public function handle($data, $event){
switch($event){
case "onHealthRegeneration":
$result = $this->server->query("SELECT ip,port FROM players WHERE EID = (SELECT EID FROM entities WHERE health < 20);", true);
case "server.regeneration":
$result = $this->server->query("SELECT EID FROM players WHERE EID = (SELECT EID FROM entities WHERE health < 20);");
if($result !== true and $result !== false){
while(false !== ($player = $result->fetchArray())){
$player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration");
if(($player = $this->server->api->player->getByEID($player["EID"])) !== false){
$player->entity->setHealth(min(20, $player->entity->getHealth() + $data), "regeneration");
}
}
}
break;
case "player.death":
$message = $data["name"];
if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){
$e = $this->api->entity->get($data["cause"]);
switch($e->class){
case ENTITY_PLAYER:
$message .= " was killed by ".$e->name;
break;
default:
$message .= " was killed";
break;
}
}else{
switch($data["cause"]){
default:
$message .= " was killed";
break;
}
}
$this->server->chat(false, $message);
break;
}
}
public function commandHandler($cmd, $params){
switch($cmd){
case "tp":
@ -93,12 +117,12 @@ class PlayerAPI{
case "list":
console("[INFO] Player list:");
foreach($this->server->clients as $c){
console("[INFO] ".$c->username." (".$c->ip.":".$c->port."), ClientID ".$c->clientID.", (".round($c->username->entity->x, 2).", ".round($c->username->entity->y, 2).", ".round($c->username->entity->z, 2).")");
console("[INFO] ".$c->username." (".$c->ip.":".$c->port."), ClientID ".$c->clientID.", (".round($c->entity->x, 2).", ".round($c->entity->y, 2).", ".round($c->entity->z, 2).")");
}
break;
}
}
public function teleport($name, $target){
$target = $this->get($target);
if($target !== false){
@ -106,7 +130,7 @@ class PlayerAPI{
}
return false;
}
public function tppos($name, $x, $y, $z){
$player = $this->get($name);
if($player !== false){
@ -122,7 +146,7 @@ class PlayerAPI{
}
return false;
}
public function get($name){
$CID = $this->server->query("SELECT ip,port FROM players WHERE name = '".str_replace("'", "", $name)."';", true);
$CID = $this->server->clientID($CID["ip"], $CID["port"]);
@ -131,11 +155,11 @@ class PlayerAPI{
}
return false;
}
public function getAll(){
return $this->server->clients;
}
public function getByEID($eid){
$eid = (int) $eid;
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
@ -145,7 +169,7 @@ class PlayerAPI{
}
return false;
}
public function getByClientID($clientID){
$clientID = (int) $clientID;
$CID = $this->server->query("SELECT ip,port FROM players WHERE clientID = '".$clientID."';", true);
@ -153,9 +177,9 @@ class PlayerAPI{
if(isset($this->server->clients[$CID])){
return $this->server->clients[$CID];
}
return false;
return false;
}
public function online(){
$o = array();
foreach($this->server->clients as $p){
@ -165,7 +189,7 @@ class PlayerAPI{
}
return $o;
}
public function add($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
@ -174,22 +198,21 @@ class PlayerAPI{
$this->server->query("INSERT OR REPLACE INTO players (clientID, ip, port, name) VALUES (".$player->clientID.", '".$player->ip."', ".$player->port.", '".$player->username."');");
}
}
public function remove($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
if(is_object($player->entity)){
$player->entity->close();
}
unset($this->server->clients[$CID]);
$player->close();
$this->saveOffline($player->username, $player->data);
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
unset($this->server->entities[$player->eid]);
unset($this->server->clients[$player->CID]);
$this->server->api->entity->remove($player->eid);
unset($player);
}
}
public function getOffline($name){
if(!file_exists(FILE_PATH."data/players/".$name.".dat")){
if(!file_exists(FILE_PATH."players/".$name.".dat")){
console("[NOTICE] Player data not found for \"".$name."\", creating new profile");
$data = array(
"spawn" => array(
@ -199,16 +222,18 @@ class PlayerAPI{
),
"health" => 20,
"lastIP" => "",
"lastID" => "",
"lastID" => 0,
);
$this->saveOffline($name, $data);
}else{
$data = unserialize(file_get_contents(FILE_PATH."data/players/".$name.".dat"));
$data = unserialize(file_get_contents(FILE_PATH."players/".$name.".dat"));
}
$this->server->handle("api.player.offline.get", $data);
return $data;
}
public function saveOffline($name, $data){
file_put_contents(FILE_PATH."data/players/".str_replace("/", "", $name).".dat", serialize($data));
}
$this->server->handle("api.player.offline.save", $data);
file_put_contents(FILE_PATH."players/".str_replace("/", "", $name).".dat", serialize($data));
}
}

179
src/API/PluginAPI.php Normal file
View File

@ -0,0 +1,179 @@
<?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 PluginAPI extends stdClass{
private $server, $plugins;
public function __construct(PocketMinecraftServer $server){
$this->server = $server;
$this->plugins = array();
require_once("classes/Spyc.class.php"); //YAML parser
}
public function getList(){
$list = array();
foreach($this->plugins as $p){
$list[] = $p[1];
}
return $list;
}
public function getInfo($className){
if(!isset($this->plugins[$className])){
return false;
}
$plugin = $this->plugins[$className];
return array($plugin[1], get_class_methods($plugin[0]));
}
public function load($file){
$content = file_get_contents($file);
$info = strstr($content, "*/", true);
$content = substr(strstr($content, "*/"),2);
if(preg_match_all('#([a-zA-Z0-9\-_]*)=([^\r\n]*)#u', $info, $matches) == 0){ //false or 0 matches
console("[ERROR] [PluginAPI] Failed parsing of ".basename($file));
return false;
}
$info = array();
foreach($matches[1] as $k => $i){
$v = $matches[2][$k];
switch(strtolower($v)){
case "on":
case "true":
case "yes":
$v = true;
break;
case "off":
case "false":
case "no":
$v = false;
break;
}
$info[$i] = $v;
}
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"]);
if(class_exists($info["class"])){
console("[ERROR] [PluginAPI] Failed loading plugin: class exists");
}
if(eval($content) === false or !class_exists($info["class"])){
console("[ERROR] [PluginAPI] Failed loading plugin: evaluation error");
}
$className = trim($info["class"]);
if(isset($info["api"]) and $info["api"] !== true){
console("[NOTICE] [PluginAPI] Plugin \"".$info["name"]."\" 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");
if(method_exists($object, "__destruct")){
$object->__destruct();
}
$object = null;
unset($object);
}else{
$this->plugins[$className] = array($object, $info);
}
}
public function get(Plugin $plugin){
foreach($this->plugins as &$p){
if($p[0] === $plugin){
return $p;
}
}
return false;
}
public function createConfig(Plugin $plugin, $default = array()){
$p = $this->get($plugin);
if($p === false){
return false;
}
$path = FILE_PATH."plugins/".$p[1]["name"]."/";
$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);
}
return $path;
}
private function fillDefaults($default, &$yaml){
foreach($default as $k => $v){
if(is_array($v)){
if(!isset($yaml[$k]) or !is_array($yaml[$k])){
$yaml[$k] = array();
}
$this->fillDefaults($v, $yaml[$k]);
}elseif(!isset($yaml[$k])){
$yaml[$k] = $v;
}
}
}
public function readYAML($file){
return Spyc::YAMLLoad(file_get_contents($file));
}
public function writeYAML($file, $data){
return file_put_contents($file, Spyc::YAMLDump($data));
}
public function init(){
$this->server->event("server.start", array($this, "loadAll"));
}
public function loadAll(){
console("[INFO] Loading Plugins...");
$dir = dir(FILE_PATH."plugins/");
while(false !== ($file = $dir->read())){
if($file{0} !== "."){
if(strtolower(substr($file, -3)) === "php"){
$this->load(FILE_PATH."plugins/" . $file);
}
}
}
foreach($this->plugins as $p){
if(method_exists($p[0], "init")){
$p[0]->init();
}
}
}
}
interface Plugin{
public function __construct(ServerAPI $api, $server = false);
public function init();
public function __destruct();
}

471
src/API/ServerAPI.php Normal file
View File

@ -0,0 +1,471 @@
<?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 ServerAPI{
var $restart = false;
private $server, $config, $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);
@mkdir(FILE_PATH."plugins/", 0777);
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 tests...");
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
console("[INFO] uname -a: ".php_uname("a"));
console("[INFO] PHP Version: ".phpversion());
console("[INFO] Endianness: ".ENDIANNESS);
$test = b"";
$test .= Utils::writeLong("5567381823242127440");
$test .= Utils::writeLong("2338608908624488819");
$test .= Utils::writeLong("2333181766244987936");
$test .= Utils::writeLong("2334669371112169504");
$test .= Utils::writeShort(Utils::readShort("\xff\xff\xff\xff"));
$test .= Utils::writeShort(Utils::readShort("\xef\xff\xff\xff"));
$test .= Utils::writeInt(Utils::readInt("\xff\xff\xff\xff"));
$test .= Utils::writeInt(1);
$test .= Utils::writeInt(-1);
$test .= Utils::writeFloat(Utils::readfloat("\xff\xff\xff\xff"));
$test .= Utils::writeFloat(-1.584563155838E+29);
$test .= Utils::writeFloat(1);
$test .= Utils::writeLDouble(Utils::readLDouble("\xff\xff\xff\xff\xff\xff\xff\xff"));
$test .= Utils::writeLong("-1152921504606846977");
$test .= Utils::writeLong("-1152921504606846976");
$test .= Utils::writeTriad(16777215);
$test .= Utils::writeTriad(16777216);
$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);
$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->parseProperties();
define("DEBUG", $this->getProperty("debug"));
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), false, $this->getProperty("port"), $this->getProperty("server-id"));
$this->server->api = $this;
if($this->getProperty("upnp-forwarding") === true){
console("[INFO] [UPnP] Trying to port forward...");
UPnP_PortForward($this->getProperty("port"));
}
if(($ip = Utils::getIP()) !== false){
console("[INFO] External IP: ".$ip);
}
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
console("[INFO] Checking for new server version");
console("[INFO] Last check: ".date("Y-m-d H:i:s", $this->getProperty("last-update")));
$channel = "stable";
if($this->getProperty("update-channel") == "dev" or $this->getProperty("update-channel") == "development"){
$channel = "dev";
}
$this->setProperty("update-channel", $channel);
if($channel === "dev"){
$info = json_decode(Utils::curl_get("https://api.github.com/repos/shoghicp/PocketMine-MP"), true);
if($info === false or !isset($info["updated_at"])){
console("[ERROR] GitHub API Error");
}else{
$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] 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");
}
}
}else{
$info = json_decode(Utils::curl_get("https://api.github.com/repos/shoghicp/PocketMine-MP/tags"), true);
if($info === false or !isset($info[0])){
console("[ERROR] GitHub API Error");
}else{
$newest = new VersionString(MAJOR_VERSION);
$newest = array(-1, $newest->getNumber());
foreach($info as $i => $tag){
$update = new VersionString($tag["name"]);
$update = $update->getNumber();
if($update > $newest[1]){
$newest = array($i, $update);
}
}
if($newest[0] !== -1){
$target = $info[$newest[0]];
console("[NOTICE] A new STABLE version of PocketMine-MP has been released");
console("[NOTICE] Version \"".(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");
}
}
}
}
if(file_exists(FILE_PATH."worlds/level.dat")){
console("[NOTICE] Detected unimported map data. Importing...");
$this->importMap(FILE_PATH."worlds/", true);
}
$this->server->mapName = $this->getProperty("level-name");
$this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/";
if($this->server->mapName === false or trim($this->server->mapName) === "" or (!file_exists($this->server->mapDir."chunks.dat") and !file_exists($this->server->mapDir."chunks.dat.gz"))){
if($this->server->mapName === false or trim($this->server->mapName) === ""){
$this->server->mapName = "world";
}
$this->server->mapDir = FILE_PATH."worlds/".$this->server->mapName."/";
$generator = "SuperflatGenerator";
if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){
$generator = $this->getProperty("generator");
}
$this->gen = new WorldGenerator($generator, $this->server->seed);
if($this->getProperty("generator-settings") !== false and trim($this->getProperty("generator-settings")) != ""){
$this->gen->set("preset", $this->getProperty("generator-settings"));
}
$this->gen->init();
$this->gen->generate();
$this->gen->save($this->server->mapDir, $this->server->mapName);
$this->setProperty("level-name", $this->server->mapName);
$this->setProperty("gamemode", 1);
}
$this->loadProperties();
$this->server->loadMap();
//Autoload all default APIs
console("[INFO] Loading default APIs");
$dir = dir(FILE_PATH."src/API/");
while(false !== ($file = $dir->read())){
if($file{0} !== "."){ //Hidden and upwards folders
$API = basename($file, ".php");
if(strtolower($API) !== "serverapi"){
$name = strtolower(substr($API, 0, -3));
$this->loadAPI($name, $API);
}
}
}
foreach($this->apiList as $ob){
if(is_callable(array($ob, "init"))){
$ob->init();
}
}
$this->server->loadEntities();
}
public function __destruct(){
foreach($this->apiList as $ob){
if(is_callable($ob, "__destruct")){
$ob->__destruct();
unset($this->apiList[$ob]);
}
}
}
private function loadProperties(){
if($this->getProperty("memory-limit") !== false){
@ini_set("memory_limit", $this->getProperty("memory-limit"));
}else{
$this->config["memory-limit"] = "256M";
}
if(!isset($this->config["invisible"])){
$this->config["invisible"] = false;
}
if(is_object($this->server)){
$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";
$config["upnp-forwarding"] = $config["upnp-forwarding"] === true ? "true":"false";
$prop = "#Pocket Minecraft PHP server properties\r\n#".date("D M j H:i:s T Y")."\r\n";
foreach($config as $n => $v){
$prop .= $n."=".$v."\r\n";
}
file_put_contents(FILE_PATH."server.properties", $prop);
}
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;
}
switch($n){
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;
}
$this->config[$n] = $v;
}
}
public function init(){
$this->server->init();
unregister_tick_function(array($this->server, "tick"));
$this->__destruct();
unset($this->server);
if($this->getProperty("upnp-forwarding") === true ){
console("[INFO] [UPnP] Removing port forward...");
UPnP_RemovePortForward($this->getProperty("port"));
}
return $this->restart;
}
/*-------------------------------------------------------------*/
public function addHandler($e, $c, $p = 5){
return $this->server->addHandler($e, $c, $p);
}
public function dhandle($e, $d){
return $this->server->handle($e, $d);
}
public function handle($e, &$d){
return $this->server->handle($e, $d);
}
public function action($t, $c, $r = true){
return $this->server->action($t, $c, $r);
}
public function schedule($t, $c, $d, $r = false, $e = "server.schedule"){
return $this->server->schedule($t, $c, $d, $r, $e);
}
public function event($e, $d){
return $this->server->event($e, $d);
}
public function trigger($e, $d){
return $this->server->trigger($e, $d);
}
public function deleteEvent($id){
return $this->server->deleteEvent($id);
}
public function importMap($dir, $remove = false){
if(file_exists($dir."level.dat")){
$nbt = new NBT();
$level = parseNBTData($nbt->loadFile($dir."level.dat"));
console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2);
unset($level["Player"]);
$lvName = $level["LevelName"]."/";
@mkdir(FILE_PATH."worlds/".$lvName, 0777);
file_put_contents(FILE_PATH."worlds/".$lvName."level.dat", serialize($level));
$entities = parseNBTData($nbt->loadFile($dir."entities.dat"));
file_put_contents(FILE_PATH."worlds/".$lvName."entities.dat", serialize($entities["Entities"]));
if(!isset($entities["TileEntities"])){
$entities["TileEntities"] = array();
}
file_put_contents(FILE_PATH."worlds/".$lvName."tileEntities.dat", serialize($entities["TileEntities"]));
console("[DEBUG] Imported ".count($entities["Entities"])." Entities and ".count($entities["TileEntities"])." TileEntities", true, true, 2);
if($remove === true){
rename($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat");
unlink($dir."level.dat");
@unlink($dir."level.dat_old");
@unlink($dir."player.dat");
unlink($dir."entities.dat");
}else{
copy($dir."chunks.dat", FILE_PATH."worlds/".$lvName."chunks.dat");
}
if($this->getProperty("level-name") === false){
console("[INFO] Setting default level to \"".$level["LevelName"]."\"");
$this->setProperty("level-name", $level["LevelName"]);
$this->setProperty("gamemode", $level["GameType"]);
$this->server->seed = $level["RandomSeed"];
$this->server->spawn = array("x" => $level["SpawnX"], "y" => $level["SpawnY"], "z" => $level["SpawnZ"]);
$this->writeProperties();
}
console("[INFO] Map \"".$level["LevelName"]."\" importing done!");
unset($level, $entities, $nbt);
return true;
}
return false;
}
public function getProperties(){
return $this->config;
}
public function getProperty($name){
if(($v = arg($name)) !== false){ //Allow for command-line arguments
switch(strtolower(trim($v))){
case "on":
case "true":
case "yes":
$v = true;
break;
case "off":
case "false":
case "no":
$v = false;
break;
}
switch($name){
case "last-update":
if($v === false){
$v = time();
}else{
$v = (int) $v;
}
break;
case "gamemode":
case "max-players":
case "port":
case "debug":
case "difficulty":
case "time-per-second":
$v = (int) $v;
break;
case "server-id":
if($v !== false){
$v = preg_match("/[^0-9\-]/", $v) > 0 ? Utils::readInt(substr(md5($v, true), 0, 4)):$v;
}
break;
}
return $v;
}
if(isset($this->config[$name])){
return $this->config[$name];
}
return false;
}
public function setProperty($name, $value){
$this->config[$name] = $value;
$this->writeProperties();
$this->loadProperties();
}
public function getList(){
return $this->apiList;
}
public function loadAPI($name, $class, $dir = false){
if($dir === false){
$dir = FILE_PATH."src/API/";
}
$file = $dir.$class.".php";
if(!file_exists($file)){
console("[ERROR] API ".$name." [".$class."] in ".$dir." doesn't exist", true, true, 0);
return false;
}
require_once($file);
$this->$name = new $class($this->server);
$this->apiList[] = $this->$name;
console("[INFO] API ".$name." [".$class."] loaded");
}
}

View File

@ -33,14 +33,14 @@ class TimeAPI{
"sunrise" => 17800,
);
private $server;
function __construct($server){
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function init(){
$this->server->api->console->register("time", "Manages server time", array($this, "commandHandler"));
}
public function commandHandler($cmd, $params){
switch($cmd){
case "time":
@ -74,7 +74,7 @@ class TimeAPI{
break;
}
}
public function night(){
$this->set("night");
}
@ -87,20 +87,20 @@ class TimeAPI{
public function sunset(){
$this->set("sunset");
}
public function get($raw = false){
return $raw === true ? $this->server->time:abs($this->server->time) % 19200;
}
public function add($time){
$this->server->time += (int) $time;
}
public function getDate($time = false){
$time = $time === false ? $this->get():$time;
return str_pad(strval((floor($time /800) + 6) % 24), 2, "0", STR_PAD_LEFT).":".str_pad(strval(floor(($time % 800) / 13.33)), 2, "0", STR_PAD_LEFT);
}
public function getPhase($time = false){
$time = $time === false ? $this->get():$time;
if($time < $this->phase["sunset"]){
@ -114,7 +114,7 @@ class TimeAPI{
}
return $time;
}
public function set($time){
if(is_string($time) and isset($this->phases[$time])){
$this->server->time = $this->phases[$time];
@ -122,6 +122,6 @@ class TimeAPI{
$this->server->time = (int) $time;
}
}
}

View File

@ -0,0 +1,71 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class Async extends Thread {
/**
* Provide a passthrough to call_user_func_array
**/
public function __construct($method, $params = array()){
$this->method = $method;
$this->params = $params;
$this->result = null;
$this->joined = false;
}
/**
* The smallest thread in the world
**/
public function run(){
if(($this->result=call_user_func_array($this->method, $this->params))){
return true;
}else{
return false;
}
}
/**
* Static method to create your threads from functions ...
**/
public static function call($method, $params = array()){
$thread = new Async($method, $params);
if($thread->start()){
return $thread;
} /** else throw Nastyness **/
}
/**
* Do whatever, result stored in $this->result, don't try to join twice
**/
public function __toString(){
if(!$this->joined) {
$this->joined = true;
$this->join();
}
return $this->result;
}
}

View File

@ -9,7 +9,7 @@
*
* PHP versions 4 and 5
*
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
* {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
*
* Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
@ -53,10 +53,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -70,7 +70,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version $Id: BigInteger.php 326530 2012-07-07 22:05:25Z terrafrost $
* @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
* @link http://pear.php.net/package/Math_BigInteger
*/
@ -234,7 +234,7 @@ class Math_BigInteger {
/**
* Mode independant value used for serialization.
*
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
* however, $this->hex is only calculated when $this->__sleep() is called.
*
@ -282,6 +282,10 @@ class Math_BigInteger {
}
}
if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
}
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
@ -601,13 +605,19 @@ class Math_BigInteger {
{
$hex = $this->toHex($twos_compliment);
$bits = '';
for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+=8) {
$bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
$bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
}
if ($end != strlen($hex)) { // hexdec('') == 0
$bits.= str_pad(decbin(hexdec(substr($hex, $end))), strlen($hex) & 7, '0', STR_PAD_LEFT);
if ($start) { // hexdec('') == 0
$bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
}
return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
$result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
return '0' . $result;
}
return $result;
}
/**
@ -740,7 +750,7 @@ class Math_BigInteger {
$vars[] = 'precision';
}
return $vars;
}
/**
@ -1591,6 +1601,53 @@ class Math_BigInteger {
return $this->_normalize($temp->modPow($e, $n));
}
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) {
$temp = new Math_BigInteger();
$temp->value = gmp_powm($this->value, $e->value, $n->value);
return $this->_normalize($temp);
}
if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
list(, $temp) = $this->divide($n);
return $temp->modPow($e, $n);
}
if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
$components = array(
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true)
);
$components = array(
'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
);
$RSAPublicKey = pack('Ca*a*a*',
48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'], $components['publicExponent']
);
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
$encapsulated = pack('Ca*a*',
48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($encapsulated)) .
'-----END PUBLIC KEY-----';
$plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
return new Math_BigInteger($result, 256);
}
}
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
@ -2180,7 +2237,7 @@ class Math_BigInteger {
/**
* Montgomery Multiply
*
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
*
* @see _prepMontgomery()
@ -2260,7 +2317,7 @@ class Math_BigInteger {
* {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
*
* As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
* int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
* auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
* the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
@ -3160,7 +3217,7 @@ class Math_BigInteger {
* @return Boolean
* @access public
* @internal Uses the
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
*/
function isPrime($t = false)
@ -3209,16 +3266,16 @@ class Math_BigInteger {
if (!isset($primes)) {
$primes = array(
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
953, 967, 971, 977, 983, 991, 997
);
@ -3550,4 +3607,24 @@ class Math_BigInteger {
$temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
return $temp['int'];
}
/**
* DER-encode an integer
*
* The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
*
* @see modPow()
* @access private
* @param Integer $length
* @return String
*/
function _encodeASN1Length($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
}

View File

@ -30,11 +30,11 @@ class ChunkParser{
var $sectorLength = 4096; //16 * 16 * 16
var $chunkLength = 86016; //21 * $sectorLength
var $map;
function __construct(){
$map = array();
}
private function loadLocationTable(){
$this->location = array();
console("[DEBUG] Loading Chunk Location table...", true, true, 2);
@ -57,36 +57,52 @@ class ChunkParser{
++$chunkCnt;
}
}
public function loadFile($file){
if(!file_exists($file)){
if(ZLIB_EXTENSION === true and file_exists($file.".gz")){
$this->raw = gzinflate(file_get_contents($file.".gz"));
$r = @gzinflate($this->raw);
if($r !== false and $r != ""){
$this->raw = $r;
}
@unlink($file.".gz");
file_put_contents($file, $this->raw);
}elseif(!file_exists($file)){
return false;
}else{
$this->raw = file_get_contents($file);
}
$this->file = $file;
$this->raw = file_get_contents($file);
$this->chunkLength = $this->sectorLength * ord($this->raw{0});
return true;
}
public function loadRaw($raw, $file){
$this->file = $file;
$this->raw = $raw;
$this->chunkLength = $this->sectorLength * ord($this->raw{0});
return true;
}
private function getOffsetPosition($X, $Z){
$data = substr($this->raw, ($X << 2) + ($Z << 7), 4); //$X * 4 + $Z * 128
return array(ord($data{0}), ord($data{1}), ord($data{2}), ord($data{3}));
}
private function getOffset($X, $Z, $sectors = 21){
return 0x1000 + (($X * $sectors) << 12) + (($Z * $sectors) << 16);
}
private function getOffsetLocation($X, $Z){
return $X << 2 + $Z << 7;
}
public function getChunk($X, $Z){
$X = (int) $X;
$Z = (int) $Z;
return substr($this->raw, $this->getOffset($X, $Z), $this->chunkLength);
}
public function writeChunk($X, $Z){
$X = (int) $X;
$Z = (int) $Z;
@ -101,7 +117,7 @@ class ChunkParser{
}
return Utils::writeLInt(strlen($chunk)).$chunk;
}
public function parseChunk($X, $Z){
$X = (int) $X;
$Z = (int) $Z;
@ -123,7 +139,7 @@ class ChunkParser{
}
return $chunk;
}
public function loadMap(){
if($this->raw == ""){
return false;
@ -139,9 +155,10 @@ class ChunkParser{
$this->raw = b"";
console("[DEBUG] Chunks loaded!", true, true, 2);
}
public function saveMap(){
public function saveMap($final = false){
console("[DEBUG] Saving chunks...", true, true, 2);
$fp = fopen($this->file, "r+b");
flock($fp, LOCK_EX);
foreach($this->map as $x => $d){
@ -152,8 +169,17 @@ class ChunkParser{
}
flock($fp, LOCK_UN);
fclose($fp);
if(ZLIB_EXTENSION === true){
$original = filesize($this->file);
file_put_contents($this->file .".gz", gzdeflate(gzdeflate(file_get_contents($this->file),9),9)); //Double compression for flat maps
$compressed = filesize($this->file .".gz");
console("[DEBUG] Saved chunks.dat.gz with ".round(($compressed/$original)*100, 2)."% (".round($compressed/1024, 2)."KB) of the original size", true, true, 2);
if($final === true){
@unlink($this->file);
}
}
}
public function getFloor($x, $z){
$X = $x >> 4;
$Z = $z >> 4;
@ -167,7 +193,7 @@ class ChunkParser{
}
return $y;
}
public function getBlock($x, $y, $z){
$x = (int) $x;
$y = (int) $y;
@ -186,12 +212,12 @@ class ChunkParser{
}
return array($block, $meta);
}
public function getChunkColumn($X, $Z, $x, $z, $type = 0){
$index = $z + ($x << 4);
return $this->map[$X][$Z][$type][$index];
}
public function setBlock($x, $y, $z, $block, $meta = 0){
$x = (int) $x;
$y = (int) $y;

View File

@ -42,7 +42,7 @@ class CustomPacketHandler{
}
return $data;
}
public function __construct($pid, $raw = "", $data = array(), $create = false){
$this->raw = $raw;
$this->data = $data;
@ -54,10 +54,19 @@ class CustomPacketHandler{
$this->data["payload"] = Utils::readLong($this->get(8));
}else{
$this->raw .= Utils::writeLong($this->data["payload"]);
}
}
break;
case 0x03:
if($this->c === false){
$this->data["unknown1"] = Utils::readLong($this->get(8));
$this->data["unknown2"] = Utils::readLong($this->get(8));
}else{
$this->raw .= Utils::writeLong($this->data["unknown1"]);
$this->raw .= Utils::writeLong($this->data["unknown2"]);
}
break;
case MC_CLIENT_CONNECT:
if($this->c === false){
if($this->c === false){
$this->data["clientID"] = Utils::readLong($this->get(8));
$this->data["session"] = Utils::readLong($this->get(8));
$this->data["unknown2"] = $this->get(1);
@ -96,7 +105,7 @@ class CustomPacketHandler{
$this->raw .= "\x00\x00";
$this->raw .= Utils::writeLong($this->data["session"]);
$this->raw .= Utils::writeLong($this->data["session2"]);
}
}
break;
case MC_CLIENT_HANDSHAKE:
if($this->c === false){
@ -128,7 +137,7 @@ class CustomPacketHandler{
//null
break;
case MC_LOGIN:
if($this->c === false){
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));
@ -138,35 +147,35 @@ class CustomPacketHandler{
}
break;
case MC_LOGIN_STATUS:
if($this->c === false){
if($this->c === false){
$this->data["status"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeInt($this->data["status"]);
}
break;
case MC_READY:
if($this->c === false){
if($this->c === false){
$this->data["status"] = ord($this->get(1));
}else{
$this->raw .= chr($this->data["status"]);
}
}
break;
case MC_CHAT:
if($this->c === false){
if($this->c === false){
$this->data["message"] = $this->get(Utils::readShort($this->get(2), false));
}else{
$this->raw .= Utils::writeShort(strlen($this->data["message"])).$this->data["message"];
}
break;
case MC_SET_TIME:
if($this->c === false){
if($this->c === false){
$this->data["time"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeInt($this->data["time"]);
}
break;
case MC_START_GAME:
if($this->c === false){
if($this->c === false){
$this->data["seed"] = Utils::readInt($this->get(4));
$this->data["unknown1"] = Utils::readInt($this->get(4));
$this->data["gamemode"] = Utils::readInt($this->get(4));
@ -182,9 +191,9 @@ class CustomPacketHandler{
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
}
}
break;
case MC_ADD_MOB:
case MC_ADD_MOB:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["type"] = Utils::readInt($this->get(4));
@ -205,7 +214,7 @@ class CustomPacketHandler{
));
}
break;
case MC_ADD_PLAYER:
case MC_ADD_PLAYER:
if($this->c === false){
$this->data["clientID"] = Utils::readLong($this->get(8));
$this->data["username"] = $this->get(Utils::readShort($this->get(2), false));
@ -279,8 +288,17 @@ class CustomPacketHandler{
$this->raw .= Utils::writeByte($this->data["roll"]);
}
break;
case MC_TAKE_ITEM_ENTITY:
if($this->c === false){
$this->data["target"] = Utils::readInt($this->get(4));
$this->data["eid"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeInt($this->data["target"]);
$this->raw .= Utils::writeInt($this->data["eid"]);
}
break;
case MC_MOVE_ENTITY:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readFloat($this->get(4));
$this->data["y"] = Utils::readFloat($this->get(4));
@ -293,7 +311,7 @@ class CustomPacketHandler{
}
break;
case MC_MOVE_ENTITY_POSROT:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readFloat($this->get(4));
$this->data["y"] = Utils::readFloat($this->get(4));
@ -310,7 +328,7 @@ class CustomPacketHandler{
}
break;
case MC_MOVE_PLAYER:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readFloat($this->get(4));
$this->data["y"] = Utils::readFloat($this->get(4));
@ -327,7 +345,7 @@ class CustomPacketHandler{
}
break;
case MC_PLACE_BLOCK:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
@ -343,10 +361,10 @@ class CustomPacketHandler{
$this->raw .= chr($this->data["block"]);
$this->raw .= chr($this->data["meta"]);
$this->raw .= chr($this->data["face"]);
}
}
break;
case MC_REMOVE_BLOCK:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
@ -356,7 +374,7 @@ class CustomPacketHandler{
$this->raw .= Utils::writeInt($this->data["x"]);
$this->raw .= Utils::writeInt($this->data["z"]);
$this->raw .= chr($this->data["y"]);
}
}
break;
case MC_UPDATE_BLOCK:
if($this->c === false){
@ -371,10 +389,35 @@ class CustomPacketHandler{
$this->raw .= chr($this->data["y"]);
$this->raw .= chr($this->data["block"]);
$this->raw .= chr($this->data["meta"]);
}
}
break;
case MC_EXPLOSION:
if($this->c === false){
$this->data["x"] = Utils::readFloat($this->get(4));
$this->data["y"] = Utils::readFloat($this->get(4));
$this->data["z"] = Utils::readFloat($this->get(4));
$this->data["radius"] = Utils::readFloat($this->get(4));
$this->data["count"] = Utils::readInt($this->get(4));
$this->data["records"] = array();
for($r = 0; $r < $this->data["count"]; ++$r){
$this->data["records"][] = array(Utils::readByte($this->get(1)), Utils::readByte($this->get(1)), Utils::readByte($this->get(1)));
}
}else{
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
$this->raw .= Utils::writeFloat($this->data["radius"]);
$this->data["records"] = (array) $this->data["records"];
$this->raw .= Utils::writeInt(count($this->data["records"]));
if(count($this->data["records"]) > 0){
foreach($this->data["records"] as $record){
$this->raw .= Utils::writeByte($record[0]) . Utils::writeByte($record[1]) . Utils::writeByte($record[2]);
}
}
}
break;
case MC_REQUEST_CHUNK:
if($this->c === false){
if($this->c === false){
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
}else{
@ -383,7 +426,7 @@ class CustomPacketHandler{
}
break;
case MC_CHUNK_DATA:
if($this->c === false){
if($this->c === false){
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
$this->data["data"] = $this->get(true);
@ -394,7 +437,7 @@ class CustomPacketHandler{
}
break;
case MC_PLAYER_EQUIPMENT:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["block"] = Utils::readShort($this->get(2), false);
$this->data["meta"] = Utils::readShort($this->get(2), false);
@ -402,10 +445,10 @@ class CustomPacketHandler{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeShort($this->data["block"]);
$this->raw .= Utils::writeShort($this->data["meta"]);
}
}
break;
case MC_INTERACT:
if($this->c === false){
if($this->c === false){
$this->data["action"] = Utils::readByte($this->get(1));
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["target"] = Utils::readInt($this->get(4));
@ -413,10 +456,10 @@ class CustomPacketHandler{
$this->raw .= Utils::writeByte($this->data["action"]);
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeInt($this->data["target"]);
}
}
break;
case MC_USE_ITEM:
if($this->c === false){
if($this->c === false){
$this->data["x"] = Utils::readInt($this->get(4));
$this->data["y"] = Utils::readInt($this->get(4));
$this->data["z"] = Utils::readInt($this->get(4));
@ -424,40 +467,40 @@ class CustomPacketHandler{
$this->data["block"] = Utils::readShort($this->get(2));
$this->data["meta"] = Utils::readByte($this->get(1));
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["unknown2"] = Utils::readFloat($this->get(4));
$this->data["unknown3"] = Utils::readFloat($this->get(4));
$this->data["unknown4"] = Utils::readFloat($this->get(4));
$this->data["fx"] = Utils::readFloat($this->get(4));
$this->data["fy"] = Utils::readFloat($this->get(4));
$this->data["fz"] = Utils::readFloat($this->get(4));
}else{
/*$this->raw .= Utils::writeByte($this->data["action"]);
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeInt($this->data["target"]);*/
}
}
break;
case MC_SET_ENTITY_DATA:
if($this->c === false){
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= Utils::writeMetadata(array(
));
}
}
break;
case MC_SET_HEALTH:
if($this->c === false){
$this->data["health"] = ord($this->get(1));
if($this->c === false){
$this->data["health"] = Utils::readByte($this->get(1));
}else{
$this->raw .= chr($this->data["health"]);
$this->raw .= Utils::writeByte($this->data["health"]);
}
break;
case MC_ANIMATE:
if($this->c === false){
if($this->c === false){
$this->data["action"] = Utils::readByte($this->get(1));
$this->data["eid"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeByte($this->data["action"]);
$this->raw .= Utils::writeInt($this->data["eid"]);
}
}
break;
case MC_RESPAWN:
if($this->c === false){
@ -470,17 +513,67 @@ class CustomPacketHandler{
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
}
}
break;
case MC_DROP_ITEM:
if($this->c === false){
$this->data["eid"] = Utils::readInt($this->get(4));
$this->data["unknown1"] = ord($this->get(1));
$this->data["block"] = Utils::readShort($this->get(2), false);
$this->data["stack"] = ord($this->get(1));
$this->data["meta"] = Utils::readShort($this->get(2), false);
}else{
$this->raw .= Utils::writeInt($this->data["eid"]);
$this->raw .= chr($this->data["unknown1"]);
$this->raw .= Utils::writeShort($this->data["block"]);
$this->raw .= chr($this->data["stack"]);
$this->raw .= Utils::writeShort($this->data["meta"]);
}
break;
case MC_CONTAINER_OPEN:
if($this->c === false){
$this->data["windowid"] = ord($this->get(1));
$this->data["type"] = ord($this->get(1));
$this->data["slots"] = Utils::readShort($this->get(2), false);
$this->data["title"] = $this->get(Utils::readShort($this->get(2), false));
}else{
$this->raw .= chr($this->data["windowid"]);
$this->raw .= chr($this->data["type"]);
$this->raw .= Utils::writeShort($this->data["slots"]);
$this->raw .= Utils::writeShort(strlen($this->data["title"])).$this->data["title"];
}
break;
case MC_CONTAINER_CLOSE:
if($this->c === false){
$this->data["windowid"] = ord($this->get(1));
}else{
$this->raw .= chr($this->data["windowid"]);
}
break;
case MC_CONTAINER_SET_SLOT:
if($this->c === false){
$this->data["windowid"] = ord($this->get(1));
$this->data["slot"] = Utils::readShort($this->get(2), false);
$this->data["block"] = Utils::readShort($this->get(2), false);
$this->data["stack"] = ord($this->get(1));
$this->data["meta"] = Utils::readShort($this->get(2), false);
}else{
$this->raw .= chr($this->data["windowid"]);
$this->raw .= Utils::writeShort($this->data["slot"]);
$this->raw .= Utils::writeShort($this->data["block"]);
$this->raw .= chr($this->data["stack"]);
$this->raw .= Utils::writeShort($this->data["meta"]);
}
break;
case MC_CLIENT_MESSAGE:
if($this->c === false){
if($this->c === false){
$this->data["message"] = $this->get(Utils::readShort($this->get(2), false));
}else{
$this->raw .= Utils::writeShort(strlen($this->data["message"])).$this->data["message"];
}
break;
case MC_SIGN_UPDATE:
if($this->c === false){
if($this->c === false){
$this->data["x"] = Utils::readShort($this->get(2));
$this->data["y"] = ord($this->get(1));
$this->data["z"] = Utils::readShort($this->get(2));
@ -497,7 +590,7 @@ class CustomPacketHandler{
}
break;
case MC_ADVENTURE_SETTINGS:
if($this->c === false){
if($this->c === false){
$this->data["x"] = Utils::readShort($this->get(2));
$this->data["y"] = ord($this->get(1));
$this->data["z"] = Utils::readShort($this->get(2));
@ -507,7 +600,14 @@ class CustomPacketHandler{
}else{
$this->raw .= $this->data["unknown1"];
$this->raw .= $this->data["unknown2"];
}
}
break;
default:
if($this->c === false){
console("[DEBUG] Received unknown Data Packet ID 0x".dechex($pid), true, true, 2);
}else{
console("[DEBUG] Sent unknown Data Packet ID 0x".dechex($pid), true, true, 2);
}
break;
}
}

243
src/classes/Data.class.php Normal file
View File

@ -0,0 +1,243 @@
<?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 BlockFace{
const BOTTOM = 0;
const TOP = 1;
const DOWN = 0;
const UP = 1;
const SOUTH = 3;
const EAST = 5;
const NORTH = 2;
const WEST = 4;
public static function setPosition(&$data, $face){
switch((int) $face){
case 0:
--$data["y"];
break;
case 1:
++$data["y"];
break;
case 2:
--$data["z"];
break;
case 3:
++$data["z"];
break;
case 4:
--$data["x"];
break;
case 5:
++$data["x"];
break;
default:
return false;
}
return true;
}
}
class Material{
static $flowable = array(
0 => true,
6 => true,
30 => true,
31 => true,
32 => true,
37 => true,
38 => true,
39 => true,
40 => true,
50 => true,
51 => true,
55 => true,
59 => true,
78 => true,
105 => true,
);
static $unbreakable = array(
0 => true,
7 => true,
8 => true,
9 => true,
10 => true,
11 => true,
);
static $transparent = array(
0 => true,
6 => true,
8 => true,
9 => true,
10 => true,
11 => true,
18 => true,
20 => true,
26 => true,
30 => true,
31 => true,
32 => true,
37 => true,
38 => true,
39 => true,
40 => true,
46 => true,
50 => true,
51 => true,
53 => true,
59 => true,
65 => true,
67 => true,
78 => true,
79 => true,
81 => true,
83 => true,
89 => true,
96 => true,
102 => true,
105 => true,
107 => true,
108 => true,
);
static $replaceable = array(
0 => true,
8 => true,
9 => true,
10 => true,
11 => true,
31 => true,
51 => true,
78 => true,
);
static $activable = array(
2 => true,
3 => true,
6 => true,
26 => true,
31 => true,
//46 => true,
51 => true,
54 => true,
58 => true,
59 => true,
61 => true,
62 => true,
64 => true,
71 => true,
78 => true,
96 => true,
105 => true,
107 => true,
247 => true,
);
static $placeable = array(
1 => true,
2 => true,
3 => true,
4 => true,
5 => true,
6 => true,
//7 => true,
8 => true,
9 => true,
10 => true,
11 => true,
12 => true,
13 => true,
14 => true,
15 => true,
16 => true,
17 => true,
18 => true,
19 => true,
20 => true,
21 => true,
22 => true,
24 => true,
355 => 26,
30 => true,
35 => true,
37 => true,
38 => true,
39 => true,
40 => true,
41 => true,
42 => true,
43 => true,
44 => true,
45 => true,
46 => true,
47 => true,
48 => true,
49 => true,
50 => true,
53 => true,
54 => true,
56 => true,
59 => true,
57 => true,
58 => true,
295 => 59,
61 => true,
324 => 64,
65 => true,
67 => true,
330 => 71,
73 => true,
79 => true,
80 => true,
81 => true,
82 => true,
83 => true,
85 => true,
86 => true,
87 => true,
88 => true,
89 => true,
91 => true,
96 => true,
98 => true,
102 => true,
103 => true,
362 => 105,
107 => true,
108 => true,
246 => true,
247 => true,
);
static $blocks = array(
0 => "Air",
1 => "Stone",
2 => "Grass",
3 => "Dirt",
4 => "Cobblestone",
5 => "Wooden Planks",
6 => "Sapling",
7 => "Bedrock",
);
}

View File

@ -33,8 +33,8 @@ define("ENTITY_ITEM", 3);
define("ENTITY_PAINTING", 4);
class Entity extends stdClass{
var $eid, $type, $name, $x, $y, $z, $yaw, $pitch, $dead, $data, $class, $attach, $metadata, $closed, $player;
var $invincible = false, $eid, $type, $name, $x, $y, $z, $speedX, $speedY, $speedZ, $last = array(0, 0, 0, 0), $yaw, $pitch, $dead, $data, $class, $attach, $metadata, $closed, $player, $onTick;
private $server;
function __construct($server, $eid, $class, $type = 0, $data = array()){
$this->server = $server;
$this->eid = (int) $eid;
@ -49,10 +49,14 @@ class Entity extends stdClass{
$this->closed = false;
$this->name = "";
$this->server->query("INSERT OR REPLACE INTO entities (EID, type, class, health) VALUES (".$this->eid.", ".$this->type.", ".$this->class.", ".$this->health.");");
$this->server->schedule(20, array($this, "update"), array(), true);
$this->metadata = array();
$this->x = isset($this->data["x"]) ? $this->data["x"]:0;
$this->y = isset($this->data["y"]) ? $this->data["y"]:0;
$this->z = isset($this->data["z"]) ? $this->data["z"]:0;
$this->speedX = isset($this->data["speedX"]) ? $this->data["speedX"]:0;
$this->speedY = isset($this->data["speedY"]) ? $this->data["speedY"]:0;
$this->speedZ = isset($this->data["speedZ"]) ? $this->data["speedZ"]:0;
$this->yaw = isset($this->data["yaw"]) ? $this->data["yaw"]:0;
$this->pitch = isset($this->data["pitch"]) ? $this->data["pitch"]:0;
$this->position = array("x" => &$this->x, "y" => &$this->y, "z" => &$this->z, "yaw" => &$this->yaw, "pitch" => &$this->pitch);
@ -73,7 +77,44 @@ class Entity extends stdClass{
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.pickup", array(
"eid" => $player["EID"],
"block" => $this->type,
"meta" => $this->meta,
"target" => $this->eid
)) !== false){
$this->close();
}
}
}
}
public function getDirection(){
$rotation = ($this->yaw - 90) % 360;
if ($rotation < 0) {
$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);
@ -91,6 +132,11 @@ class Entity extends stdClass{
"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(
@ -102,7 +148,7 @@ class Entity extends stdClass{
"meta" => $this->meta,
"stack" => $this->stack,
));
break;
break;
case ENTITY_MOB:
$player->dataPacket(MC_ADD_MOB, array(
"type" => $this->type,
@ -117,32 +163,31 @@ class Entity extends stdClass{
break;
}
}
public function close(){
if($this->closed === false){
$this->server->query("DELETE FROM entities WHERE EID = ".$this->eid.";");
$this->server->trigger("onEntityRemove", $this->eid);
$this->server->api->entity->remove($this->eid);
$this->closed = true;
}
}
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);
@ -150,14 +195,16 @@ class Entity extends stdClass{
$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.";");
$this->updateVelocity();
$this->server->api->dhandle("entity.move", $this);
}
public function move($x, $y, $z, $yaw = 0, $pitch = 0){
$this->x += $x;
$this->y += $y;
@ -167,26 +214,53 @@ class Entity extends stdClass{
$this->pitch += $pitch;
$this->pitch %= 90;
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
$this->updateVelocity();
$this->server->api->dhandle("entity.move", $this);
}
public function setPosition($x, $y, $z, $yaw, $pitch){
$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;
$this->server->query("UPDATE entities SET x = ".$this->x.", y = ".$this->y.", z = ".$this->z.", pitch = ".$this->pitch.", yaw = ".$this->yaw." WHERE EID = ".$this->eid.";");
$this->updateVelocity();
$this->server->api->dhandle("entity.move", $this);
}
public function inBlock($x, $y, $z){
$block = new Vector3($x + 0.5, $y, $z + 0.5);
$me = new Vector3($this->x, $this->y, $this->z);
$up = new Vector3($this->x, $this->y + 1, $this->z);
if($block->distance($me) < 0.8 or $block->distance($up) < 0.8){
return true;
}
return false;
}
public function updateVelocity(){
$diffTime = microtime(true) - $this->last[3];
$this->last[3] = microtime(true);
$speedX = ($this->x - $this->last[0]) / $diffTime;
$this->last[0] = $this->x;
$speedY = ($this->y - $this->last[1]) / $diffTime;
$this->last[1] = $this->y;
$speedZ = ($this->z - $this->last[2]) / $diffTime;
$this->last[2] = $this->z;
$this->speedX = $speedX;
$this->speedY = $speedY;
$this->speedZ = $speedZ;
}
public function getPosition($round = false){
return !isset($this->position) ? false:($round === true ? array_map("floor", $this->position):$this->position);
}
public function setHealth($health, $cause = ""){
public function setHealth($health, $cause = ""){
$this->health = (int) $health;
$this->server->query("UPDATE entities SET health = ".$this->health." WHERE EID = ".$this->eid.";");
$this->server->trigger("onHealthChange", array("eid" => $this->eid, "health" => $health, "cause" => $cause));
$this->server->api->dhandle("entity.health.change", array("eid" => $this->eid, "health" => $health, "cause" => $cause));
if($this->player !== false){
$this->player->dataPacket(MC_SET_HEALTH, array(
"health" => $this->health,
@ -195,13 +269,13 @@ class Entity extends stdClass{
if($this->health <= 0 and $this->dead === false){
$this->dead = true;
if($this->player !== false){
$this->server->handle("onPlayerDeath", array("name" => $this->name, "cause" => $cause));
$this->server->api->dhandle("player.death", array("name" => $this->name, "cause" => $cause));
}
}elseif($this->health > 0){
$this->dead = false;
}
}
public function getHealth(){
return $this->health;
}

View File

@ -0,0 +1,357 @@
<?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 WorldGenerator{
private $gen, $seed, $genName, $raw;
public function __construct($genName, $seed){
$this->seed = (int) $seed;
$this->raw = b"";
$this->genName = $genName;
$this->gen = new $genName($this->seed);
}
public function getSpawn(){
return $this->gen->getSpawn();
}
public function set($name, $value){
$this->gen->set($name, $value);
}
public function init(){
$this->raw = "\x15\x01\x00\x00\x15\x16\x00\x00\x15\x2b\x00\x00\x15\x40\x00\x00". //Location Header
"\x15\x55\x00\x00\x15\x6a\x00\x00\x15\x7f\x00\x00\x15\x94\x00\x00".
"\x15\xa9\x00\x00\x15\xbe\x00\x00\x15\xd3\x00\x00\x15\xe8\x00\x00".
"\x15\xfd\x00\x00\x15\x12\x01\x00\x15\x27\x01\x00\x15\x3c\x01\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x51\x01\x00\x15\x66\x01\x00\x15\x7b\x01\x00\x15\x90\x01\x00".
"\x15\xa5\x01\x00\x15\xba\x01\x00\x15\xcf\x01\x00\x15\xe4\x01\x00".
"\x15\xf9\x01\x00\x15\x0e\x02\x00\x15\x23\x02\x00\x15\x38\x02\x00".
"\x15\x4d\x02\x00\x15\x62\x02\x00\x15\x77\x02\x00\x15\x8c\x02\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xa1\x02\x00\x15\xb6\x02\x00\x15\xcb\x02\x00\x15\xe0\x02\x00".
"\x15\xf5\x02\x00\x15\x0a\x03\x00\x15\x1f\x03\x00\x15\x34\x03\x00".
"\x15\x49\x03\x00\x15\x5e\x03\x00\x15\x73\x03\x00\x15\x88\x03\x00".
"\x15\x9d\x03\x00\x15\xb2\x03\x00\x15\xc7\x03\x00\x15\xdc\x03\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xf1\x03\x00\x15\x06\x04\x00\x15\x1b\x04\x00\x15\x30\x04\x00".
"\x15\x45\x04\x00\x15\x5a\x04\x00\x15\x6f\x04\x00\x15\x84\x04\x00".
"\x15\x99\x04\x00\x15\xae\x04\x00\x15\xc3\x04\x00\x15\xd8\x04\x00".
"\x15\xed\x04\x00\x15\x02\x05\x00\x15\x17\x05\x00\x15\x2c\x05\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x41\x05\x00\x15\x56\x05\x00\x15\x6b\x05\x00\x15\x80\x05\x00".
"\x15\x95\x05\x00\x15\xaa\x05\x00\x15\xbf\x05\x00\x15\xd4\x05\x00".
"\x15\xe9\x05\x00\x15\xfe\x05\x00\x15\x13\x06\x00\x15\x28\x06\x00".
"\x15\x3d\x06\x00\x15\x52\x06\x00\x15\x67\x06\x00\x15\x7c\x06\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x91\x06\x00\x15\xa6\x06\x00\x15\xbb\x06\x00\x15\xd0\x06\x00".
"\x15\xe5\x06\x00\x15\xfa\x06\x00\x15\x0f\x07\x00\x15\x24\x07\x00".
"\x15\x39\x07\x00\x15\x4e\x07\x00\x15\x63\x07\x00\x15\x78\x07\x00".
"\x15\x8d\x07\x00\x15\xa2\x07\x00\x15\xb7\x07\x00\x15\xcc\x07\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xe1\x07\x00\x15\xf6\x07\x00\x15\x0b\x08\x00\x15\x20\x08\x00".
"\x15\x35\x08\x00\x15\x4a\x08\x00\x15\x5f\x08\x00\x15\x74\x08\x00".
"\x15\x89\x08\x00\x15\x9e\x08\x00\x15\xb3\x08\x00\x15\xc8\x08\x00".
"\x15\xdd\x08\x00\x15\xf2\x08\x00\x15\x07\x09\x00\x15\x1c\x09\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x31\x09\x00\x15\x46\x09\x00\x15\x5b\x09\x00\x15\x70\x09\x00".
"\x15\x85\x09\x00\x15\x9a\x09\x00\x15\xaf\x09\x00\x15\xc4\x09\x00".
"\x15\xd9\x09\x00\x15\xee\x09\x00\x15\x03\x0a\x00\x15\x18\x0a\x00".
"\x15\x2d\x0a\x00\x15\x42\x0a\x00\x15\x57\x0a\x00\x15\x6c\x0a\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x81\x0a\x00\x15\x96\x0a\x00\x15\xab\x0a\x00\x15\xc0\x0a\x00".
"\x15\xd5\x0a\x00\x15\xea\x0a\x00\x15\xff\x0a\x00\x15\x14\x0b\x00".
"\x15\x29\x0b\x00\x15\x3e\x0b\x00\x15\x53\x0b\x00\x15\x68\x0b\x00".
"\x15\x7d\x0b\x00\x15\x92\x0b\x00\x15\xa7\x0b\x00\x15\xbc\x0b\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xd1\x0b\x00\x15\xe6\x0b\x00\x15\xfb\x0b\x00\x15\x10\x0c\x00".
"\x15\x25\x0c\x00\x15\x3a\x0c\x00\x15\x4f\x0c\x00\x15\x64\x0c\x00".
"\x15\x79\x0c\x00\x15\x8e\x0c\x00\x15\xa3\x0c\x00\x15\xb8\x0c\x00".
"\x15\xcd\x0c\x00\x15\xe2\x0c\x00\x15\xf7\x0c\x00\x15\x0c\x0d\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x21\x0d\x00\x15\x36\x0d\x00\x15\x4b\x0d\x00\x15\x60\x0d\x00".
"\x15\x75\x0d\x00\x15\x8a\x0d\x00\x15\x9f\x0d\x00\x15\xb4\x0d\x00".
"\x15\xc9\x0d\x00\x15\xde\x0d\x00\x15\xf3\x0d\x00\x15\x08\x0e\x00".
"\x15\x1d\x0e\x00\x15\x32\x0e\x00\x15\x47\x0e\x00\x15\x5c\x0e\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x71\x0e\x00\x15\x86\x0e\x00\x15\x9b\x0e\x00\x15\xb0\x0e\x00".
"\x15\xc5\x0e\x00\x15\xda\x0e\x00\x15\xef\x0e\x00\x15\x04\x0f\x00".
"\x15\x19\x0f\x00\x15\x2e\x0f\x00\x15\x43\x0f\x00\x15\x58\x0f\x00".
"\x15\x6d\x0f\x00\x15\x82\x0f\x00\x15\x97\x0f\x00\x15\xac\x0f\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xc1\x0f\x00\x15\xd6\x0f\x00\x15\xeb\x0f\x00\x15\x00\x10\x00".
"\x15\x15\x10\x00\x15\x2a\x10\x00\x15\x3f\x10\x00\x15\x54\x10\x00".
"\x15\x69\x10\x00\x15\x7e\x10\x00\x15\x93\x10\x00\x15\xa8\x10\x00".
"\x15\xbd\x10\x00\x15\xd2\x10\x00\x15\xe7\x10\x00\x15\xfc\x10\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x11\x11\x00\x15\x26\x11\x00\x15\x3b\x11\x00\x15\x50\x11\x00".
"\x15\x65\x11\x00\x15\x7a\x11\x00\x15\x8f\x11\x00\x15\xa4\x11\x00".
"\x15\xb9\x11\x00\x15\xce\x11\x00\x15\xe3\x11\x00\x15\xf8\x11\x00".
"\x15\x0d\x12\x00\x15\x22\x12\x00\x15\x37\x12\x00\x15\x4c\x12\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\x61\x12\x00\x15\x76\x12\x00\x15\x8b\x12\x00\x15\xa0\x12\x00".
"\x15\xb5\x12\x00\x15\xca\x12\x00\x15\xdf\x12\x00\x15\xf4\x12\x00".
"\x15\x09\x13\x00\x15\x1e\x13\x00\x15\x33\x13\x00\x15\x48\x13\x00".
"\x15\x5d\x13\x00\x15\x72\x13\x00\x15\x87\x13\x00\x15\x9c\x13\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x15\xb1\x13\x00\x15\xc6\x13\x00\x15\xdb\x13\x00\x15\xf0\x13\x00".
"\x15\x05\x14\x00\x15\x1a\x14\x00\x15\x2f\x14\x00\x15\x44\x14\x00".
"\x15\x59\x14\x00\x15\x6e\x14\x00\x15\x83\x14\x00\x15\x98\x14\x00".
"\x15\xad\x14\x00\x15\xc2\x14\x00\x15\xd7\x14\x00\x15\xec\x14\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$this->gen->init();
}
public function generate(){
for($Z = 0; $Z < 16; ++$Z){
for($X = 0; $X < 16; ++$X){
$chunk = str_pad($this->getChunk($X, $Z), 86012, "\x00", STR_PAD_RIGHT);
$this->raw .= Utils::writeLInt(strlen($chunk)) . $chunk;
}
console("[DEBUG] Generating level ".ceil(($Z + 1)/0.16)."%", true, true, 2);
}
return true;
}
private function getChunk($X, $Z){
$chunk = b"";
$columns = array();
$X *= 16;
$Z *= 16;
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$columns[$x * 16 + $z] = $this->gen->getColumn($X + $x, $Z + $z);
}
}
for($i = 0; $i < 4; ++$i){
for($x = 0; $x < 16; ++$x){
for($z = 0; $z < 16; ++$z){
$chunk .= $columns[$x * 16 + $z][$i];
}
}
}
unset($columns);
return $chunk;
}
public function save($dir, $name){
@mkdir($dir, 0777, true);
file_put_contents($dir."chunks.dat", $this->raw);
$s = $this->getSpawn();
$array = array();
file_put_contents($dir."entities.dat", serialize($array));
file_put_contents($dir."tileEntities.dat", serialize($array));
$level = array(
"LevelName" => $name,
"Time" => 0,
"Gamemode" => 1,
"RandomSeed" => $this->seed,
"Generator" => $this->genName,
"SpawnX" => $s[0],
"SpawnY" => $s[1],
"SpawnZ" => $s[2],
);
file_put_contents($dir."level.dat", serialize($level));
}
}

View File

@ -28,26 +28,26 @@ the Free Software Foundation, either version 3 of the License, or
class Java_String{
private $value = "", $count = 0, $hash = 0;
public function __construct($string = false){
if($string !== false){
$this->value = (string) $string;
$this->count = strlen($this->value);
}
}
public function __toString(){
return $this->value;
}
public function lenght(){
return $this->count;
}
public function isEmpty(){
return $this->count === 0;
}
public function charAt($index){
$index = (int) $index;
if($index < 0 or $index >= $this->count){
@ -56,7 +56,7 @@ class Java_String{
}
return $this->value{$index};
}
public function hashCode(){
$h = $this->hash;
if($h === 0 and $this->count > 0){
@ -68,13 +68,13 @@ class Java_String{
$this->hash = $h;
}
return $h;
}
}
}
class Java_Random{
private $haveNextNextGaussian, $nextNextGaussian, $seed, $n1, $n2, $n3, $zero;
public function __construct($seed = false){
$this->n1 = new Math_BigInteger(0x5DEECE66D);
$this->n2 = new Math_BigInteger(1);
@ -86,19 +86,19 @@ class Java_Random{
}
$this->setSeed($seed);
}
public function setSeed($seed){
$seed = new Math_BigInteger($seed);
$this->seed = $seed->bitwise_xor($this->n1)->bitwise_and($this->n2);
$this->haveNextNextGaussian = false;
}
protected function next($bits){
$bits = (int) $bits;
$this->seed = $this->seed->multiply($this->n1)->add($this->n3)->bitwise_and($this->n2);
return $this->_tripleRightShift($this->seed, (48 - $bits));
}
private function _tripleRightShift($number, $places){
if($number->compare($this->zero) >= 0){
return $number->bitwise_rightShift($places);
@ -106,7 +106,7 @@ class Java_Random{
$n1 = new Math_BigInteger(2);
return $number->bitwise_rightShift($places)->add($n1->bitwise_leftShift(~$places));
}
public function nextBytes($bytes){
$bytes = (int) $bytes;
$b = b"";

View File

@ -26,14 +26,13 @@ the Free Software Foundation, either version 3 of the License, or
*/
class MinecraftInterface{
var $pstruct, $name, $protocol, $client, $dataName;
var $pstruct, $name, $client, $dataName;
private $socket, $data;
function __construct($server, $protocol = CURRENT_PROTOCOL, $port = 25565, $listen = false, $client = true){
function __construct($server, $port = 25565, $listen = false, $client = true){
$this->socket = new UDPSocket($server, $port, (bool) $listen);
$this->protocol = (int) $protocol;
require("pstruct/RakNet.php");
require("pstruct/packetName.php");
require("pstruct/".$this->protocol.".php");
require("pstruct/protocol.php");
require("pstruct/dataName.php");
$this->pstruct = $pstruct;
$this->name = $packetName;
@ -42,18 +41,18 @@ class MinecraftInterface{
$this->client = (bool) $client;
$this->start = microtime(true);
}
public function close(){
return $this->socket->close();
}
protected function getStruct($pid){
if(isset($this->pstruct[$pid])){
return $this->pstruct[$pid];
}
return false;
}
protected function writeDump($pid, $raw, $data, $origin = "client", $ip = "", $port = 0){
if(LOG === true and DEBUG >= 3){
$p = "[".(microtime(true) - $this->start)."] [".((($origin === "client" and $this->client === true) or ($origin === "server" and $this->client === false)) ? "CLIENT->SERVER":"SERVER->CLIENT")." ".$ip.":".$port."]: ".(isset($data["id"]) ? "MC Packet ".$this->dataName[$pid]:$this->name[$pid])." (0x".Utils::strTohex(chr($pid)).") [length ".strlen($raw)."]".PHP_EOL;
@ -66,9 +65,9 @@ class MinecraftInterface{
$p .= PHP_EOL;
logg($p, "packets", false);
}
}
public function readPacket(){
$p = $this->popPacket();
if($p !== false){
@ -91,14 +90,13 @@ class MinecraftInterface{
logg($p, "packets", true, 2);
return false;
}
$packet = new Packet($pid, $struct, $data[0]);
$packet->protocol = $this->protocol;
$packet->parse();
$this->data[] = array($pid, $packet->data, $data[0], $data[1], $data[2]);
return $this->popPacket();
}
public function popPacket(){
if(count($this->data) > 0){
$p = array_shift($this->data);
@ -114,12 +112,11 @@ class MinecraftInterface{
}
return false;
}
public function writePacket($pid, $data = array(), $raw = false, $dest = false, $port = false){
$struct = $this->getStruct($pid);
if($raw === false){
$packet = new Packet($pid, $struct);
$packet->protocol = $this->protocol;
$packet->data = $data;
$packet->create();
$write = $this->socket->write($packet->raw, $dest, $port);
@ -127,10 +124,10 @@ class MinecraftInterface{
}else{
$write = $this->socket->write($data, $dest, $port);
$this->writeDump($pid, $data, false, "client", $dest, $port);
}
}
return true;
}
}
?>

View File

@ -1,7 +1,7 @@
<?php
/**
* Class for reading in NBT-format files.
*
*
* @author Justin Martin <frozenfire@thefrozenfire.com>
* @version 1.0
* MODIFIED BY @shoghicp
@ -12,7 +12,7 @@
class NBT {
public $root = array();
const TAG_END = 0;
const TAG_BYTE = 1;
const TAG_SHORT = 2;
@ -24,7 +24,7 @@ class NBT {
const TAG_STRING = 8;
const TAG_LIST = 9;
const TAG_COMPOUND = 10;
public function loadFile($filename) {
if(is_file($filename)) {
$fp = fopen($filename, "rb");
@ -44,7 +44,7 @@ class NBT {
$this->traverseTag($fp, $this->root);
return end($this->root);
}
public function traverseTag($fp, &$tree) {
if(feof($fp)) {
return false;
@ -59,7 +59,7 @@ class NBT {
return true;
}
}
public function readType($fp, $tagType) {
switch($tagType) {
case self::TAG_BYTE: // Signed byte (8 bit)

View File

@ -0,0 +1,66 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class NormalGenerator{
private $config, $spawn, $structure;
public function __construct($seed){
$this->config = array(
"seed" => (int) $seed,
);
}
public function set($name, $value){
$this->config[$name] = $value;
}
public function init(){
$this->spawn = array(128, 128, 128);
}
public function getSpawn(){
return $this->spawn;
}
public function getColumn($x, $z){
$x = (int) $x;
$z = (int) $z;
$column = $this->structure;
if(floor(sqrt(pow($x - $this->spawn[0], 2) + pow($z - $this->spawn[2], 2))) <= $this->config["spawn-radius"]){
$column[0]{strlen($column[0])-1} = chr($this->config["spawn-surface"]);
}
if(($x % 8) === 0 and ($z % 8) === 0 and $this->config["torches"] == "1"){
$column[0] .= chr(50);
}
$column[0] .= str_repeat(chr(0), 128 - strlen($column[0]));
$column[1] .= str_repeat(chr(0), 64 - strlen($column[1]));
$column[2] .= str_repeat(chr(0), 64 - strlen($column[2]));
$column[3] .= str_repeat(chr(0), 64 - strlen($column[3]));
return $column;
}
}

View File

@ -29,8 +29,8 @@ the Free Software Foundation, either version 3 of the License, or
class Packet{
private $struct, $sock;
protected $pid, $packet;
public $data, $raw, $protocol;
public $data, $raw;
function __construct($pid, $struct, $data = ""){
$this->pid = $pid;
$this->offset = 1;
@ -42,7 +42,7 @@ class Packet{
$this->struct = $struct;
$this->sock = $sock;
}
public function create($raw = false){
foreach($this->struct as $field => $type){
if(!isset($this->data[$field])){
@ -75,7 +75,7 @@ class Packet{
case 0x40:
$reply = new CustomPacketHandler($this->data[$field]["id"], "", $this->data[$field], true);
$this->addRaw(Utils::writeShort((strlen($reply->raw) + 1) << 3));
$this->addRaw(Utils::writeTriad($this->data[$field]["count"]));
$this->addRaw(Utils::writeTriad(strrev($this->data[$field]["count"])));
$this->addRaw(chr($this->data[$field]["id"]));
$this->addRaw($reply->raw);
break;
@ -83,7 +83,7 @@ class Packet{
$reply = new CustomPacketHandler($this->data[$field]["id"], "", $this->data[$field], true);
$this->addRaw(Utils::writeShort((strlen($reply->raw) + 1) << 3));
$this->addRaw(chr($this->data[$field]["id"]));
$this->addRaw($reply->raw);
$this->addRaw($reply->raw);
break;
}
break;
@ -136,10 +136,10 @@ class Packet{
default:
$this->addRaw(Utils::writeByte($this->data[$field]));
break;
}
}
}
}
private function get($len = true){
if($len === true){
$data = substr($this->raw, $this->offset);
@ -150,12 +150,12 @@ class Packet{
$this->offset += $len;
return $data;
}
protected function addRaw($str){
$this->raw .= $str;
return $str;
}
public function parse(){
$continue = true;
foreach($this->struct as $field => $type){
@ -205,7 +205,7 @@ class Packet{
break;
case "byte":
$this->data[] = Utils::readByte($this->get(1));
break;
break;
case "ubyte":
$this->data[] = ord($this->get(1));
break;
@ -231,8 +231,8 @@ class Packet{
}
}
}
}

View File

@ -26,9 +26,9 @@ the Free Software Foundation, either version 3 of the License, or
*/
class Session{
private $server, $timeout, $connected, $evid, $queue, $buffer;
var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU, $spawned;
class Player{
private $server, $timeout, $connected, $queue, $buffer, $evid = array();
var $clientID, $ip, $port, $counter, $username, $eid, $data, $entity, $auth, $CID, $MTU, $spawned, $equipment;
function __construct($server, $clientID, $ip, $port, $MTU){
$this->queue = array();
$this->buffer = array();
@ -42,18 +42,18 @@ class Session{
$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("onTick", array($this, "onTick"));
$this->evid[] = $this->server->event("onClose", array($this, "close"));
$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);
$this->counter = array(0, 0, 0);
}
public function onTick($time, $event){
if($event !== "onTick"){
if($event !== "server.tick"){
return;
}
if($time > $this->timeout){
@ -79,7 +79,7 @@ class Session{
}
}
}
public function save(){
if(is_object($this->entity)){
$this->data["spawn"] = array(
@ -89,73 +89,74 @@ class Session{
);
}
}
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, "onChat");
$this->dataPacket(MC_LOGIN_STATUS, array(
"status" => 1,
));
$this->dataPacket(MC_DISCONNECT);
$this->connected = false;
if($msg === true){
$this->server->trigger("onChat", $this->username." left the game");
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->connected = false;
if($msg === true){
$this->server->api->chat->broadcast($this->username." left the game");
}
console("[INFO] Session with ".$this->ip.":".$this->port." Client ID ".$this->clientID." closed due to ".$reason);
$this->server->api->player->remove($this->CID);
}
console("[INFO] Session with ".$this->ip.":".$this->port." Client ID ".$this->clientID." closed due to ".$reason);
$this->server->api->player->remove($this->CID);
}
public function eventHandler($data, $event){
public function eventHandler($data, $event){
switch($event){
case "onBlockUpdate":
case "player.pickup":
if($data["eid"] === $this->eid){
$data["eid"] = 0;
}
$this->dataPacket(MC_TAKE_ITEM_ENTITY, $data);
break;
case "player.equipment.change":
if($data["eid"] === $this->eid){
break;
}
$this->dataPacket(MC_PLAYER_EQUIPMENT, $data);
break;
case "block.change":
$this->dataPacket(MC_UPDATE_BLOCK, $data);
break;
case "onTeleport":
if($data["eid"] !== $this->eid){
case "entity.move":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_MOVE_PLAYER, array(
"eid" => $data["eid"],
"x" => $data["x"],
"y" => $data["y"],
"z" => $data["z"],
"yaw" => 0,
"pitch" => 0,
));
break;
case "onEntityMove":
if($data === $this->eid){
break;
}
$entity = $this->server->entities[$data];
$this->dataPacket(MC_MOVE_ENTITY_POSROT, array(
"eid" => $data,
"x" => $entity->x,
"y" => $entity->y,
"z" => $entity->z,
"yaw" => $entity->yaw,
"pitch" => $entity->pitch,
"eid" => $data->eid,
"x" => $data->x,
"y" => $data->y,
"z" => $data->z,
"yaw" => $data->yaw,
"pitch" => $data->pitch,
));
break;
case "onEntityRemove":
if($data === $this->eid){
case "entity.remove":
if($data->eid === $this->eid){
break;
}
$this->dataPacket(MC_ENTITY_REMOVE, array(
"eid" => $data,
$this->dataPacket(MC_REMOVE_ENTITY, array(
"eid" => $data->eid,
));
break;
case "onTimeChange":
case "server.time":
$this->dataPacket(MC_SET_TIME, array(
"time" => $data,
));
break;
case "onAnimate":
case "entity.animate":
if($data["eid"] === $this->eid){
break;
}
@ -164,14 +165,23 @@ class Session{
"action" => $data["action"],
));
break;
case "onChat":
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" => $data,
));
"message" => str_replace("@username", $this->username, $message),
));
break;
}
}
public function handle($pid, $data){
if($this->connected === true){
$this->timeout = microtime(true) + 25;
@ -187,8 +197,19 @@ class Session{
}
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;
@ -200,11 +221,23 @@ class Session{
$data[3],
0,
));
break;
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
@ -218,8 +251,14 @@ class Session{
$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:
@ -230,10 +269,19 @@ class Session{
));
break;
case MC_CLIENT_HANDSHAKE:
break;
case MC_LOGIN:
$this->username = str_replace("/", "", $data["username"]);
$this->username = str_replace(array("\x00", "/", " ", "\r", "\n"), array("", "-", "_", "", ""), $data["username"]);
if($this->username == ""){
$this->close("bad username", false);
break;
}
$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){
@ -242,14 +290,15 @@ class Session{
if($c !== false){
$c->close("logged in from another location");
}
if($this->server->whitelist !== false and !in_array($this->username, $this->server->whitelist)){
$this->close("\"".$this->username."\" not being on white-list", false);
break;
if($this->server->api->dhandle("player.join", $this) === false){
$this->close();
return;
}
$this->server->api->player->add($this->CID);
$this->auth = true;
$this->data["lastIP"] = $this->ip;
$this->data["lastID"] = $this->clientID;
$this->server->api->player->saveOffline($this->username, $this->data);
$this->dataPacket(MC_LOGIN_STATUS, array(
"status" => 0,
));
@ -264,129 +313,129 @@ class Session{
));
break;
case MC_READY:
if($this->spawned !== false){
break;
}
$this->spawned = true;
$this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this));
$this->eid = $this->entity->eid;
$this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";");
$this->entity->setName($this->username);
$this->entity->data["clientID"] = $this->clientID;
$this->server->api->entity->spawnAll($this);
$this->server->api->entity->spawnToAll($this->eid);
$this->evid[] = $this->server->event("onTimeChange", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onChat", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onEntityRemove", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onEntityMove", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onAnimate", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onTeleport", array($this, "eventHandler"));
$this->evid[] = $this->server->event("onBlockUpdate", array($this, "eventHandler"));
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
$this->eventHandler($this->server->motd, "onChat");
if($this->MTU <= 548){
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "onChat");
switch($data["status"]){
case 1:
if($this->spawned !== false){
break;
}
$this->spawned = true;
$this->entity = $this->server->api->entity->add(ENTITY_PLAYER, 0, array("player" => $this));
$this->eid = $this->entity->eid;
$this->server->query("UPDATE players SET EID = ".$this->eid." WHERE clientID = ".$this->clientID.";");
$this->entity->setName($this->username);
$this->entity->data["clientID"] = $this->clientID;
$this->server->api->entity->spawnAll($this);
$this->server->api->entity->spawnToAll($this->eid);
$this->evid[] = $this->server->event("server.timee", array($this, "eventHandler"));
$this->evid[] = $this->server->event("server.chat", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.remove", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.move", array($this, "eventHandler"));
$this->evid[] = $this->server->event("entity.animate", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.equipment.change", array($this, "eventHandler"));
$this->evid[] = $this->server->event("player.pickup", array($this, "eventHandler"));
$this->evid[] = $this->server->event("block.change", array($this, "eventHandler"));
console("[DEBUG] Player with EID ".$this->eid." \"".$this->username."\" spawned!", true, true, 2);
$this->eventHandler(new Container($this->server->motd), "server.chat");
if($this->MTU <= 548){
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "server.chat");
}
break;
case 2://Chunk loaded?
break;
}
break;
case MC_MOVE_PLAYER:
if(is_object($this->entity)){
$this->entity->setPosition($data["x"], $data["y"], $data["z"], $data["yaw"], $data["pitch"]);
$this->server->trigger("onEntityMove", $this->eid);
$this->server->api->dhandle("player.move", $this->entity);
}
break;
case MC_PLAYER_EQUIPMENT:
console("[DEBUG] EID ".$this->eid." has now ".$data["block"].":".$data["meta"]." in their hands!", true, true, 2);
$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 = floor(($this->MTU - 16 - 255) / 192);
$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,
"data" => $d,
), true);
}
');
console("[INTERNAL] Chunk X ".$data["x"]." Z ".$data["z"]." requested", true, true, 3);
break;
case MC_USE_ITEM:
if($data["face"] >= 0 and $data["face"] <= 5 and $data["block"] !== 0){
switch($data["face"]){
case 0:
--$data["y"];
break;
case 1:
++$data["y"];
break;
case 2:
--$data["z"];
break;
case 3:
++$data["z"];
break;
case 4:
--$data["x"];
break;
case 5:
++$data["x"];
break;
}
if($data["block"] === 65){
$data["block"] = 63;
}
$data["eid"] = $this->eid;
$this->server->handle("onBlockPlace", $data);
if($data["block"] === 63){
$data["line0"] = "WHOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
$data["line1"] = "this is a test";
$data["line2"] = "I'm ".$this->username;
$data["line3"] = "TPS: ".$this->server->getTPS();
$this->dataPacket(MC_SIGN_UPDATE, $data);
}
$data["eid"] = $this->eid;
if(Utils::distance($this->entity->position, $data) > 10){
break;
}
break;
case MC_PLACE_BLOCK:
var_dump($data);
$this->server->handle("player.block.action", $data);
break;
case MC_REMOVE_BLOCK:
$data["eid"] = $this->eid;
$this->server->handle("onBlockBreak", $data);
if(Utils::distance($this->entity->position, $data) > 8){
break;
}
$this->server->handle("player.block.break", $data);
break;
case MC_INTERACT:
if(isset($this->server->entities[$data["target"]]) and Utils::distance($this->entity->position, $this->server->entities[$data["target"]]->position) <= 8){
console("[DEBUG] EID ".$this->eid." attacked EID ".$data["target"], true, true, 2);
if($this->server->gamemode !== 1 and $this->server->difficulty > 0){
$this->server->api->entity->harm($data["target"], $this->server->difficulty, $this->eid);
if($this->handle("player.interact", $data) !== false){
console("[DEBUG] EID ".$this->eid." attacked EID ".$data["target"], true, true, 2);
if($this->server->gamemode !== 1 and $this->server->difficulty > 0){
$this->server->api->entity->harm($data["target"], $this->server->difficulty, $this->eid);
}
}
}
break;
case MC_ANIMATE:
$this->server->trigger("onAnimate", array("eid" => $this->eid, "action" => $data["action"]));
$this->server->api->dhandle("entity.animate", array("eid" => $this->eid, "action" => $data["action"]));
break;
case MC_RESPAWN:
$this->entity->invincible = true;
$this->entity->setHealth(20, "respawn");
$this->entity->setPosition($data["x"], $data["y"], $data["z"], 0, 0);
$this->entity->invincible = false;
break;
case MC_SET_HEALTH:
if($this->server->gamemode === 1){
break;
}
//$this->entity->setHealth($data["health"], "client");
break;
case MC_DROP_ITEM:
if($this->server->handle("player.drop", $data) !== false){
$this->server->api->block->drop($this->entity->x, $this->entity->y, $this->entity->z, $data["block"], $data["meta"], $data["stack"]);
}
break;
default:
console("[DEBUG] Unhandled 0x".dechex($data["id"])." Data Packet for Client ID ".$this->clientID.": ".print_r($data, true), true, true, 2);
break;
}
break;
}
}
}
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);

View File

@ -25,30 +25,31 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("classes/Session.class.php");
class PocketMinecraftServer extends stdClass{
var $invisible, $tickMeasure, $preparedSQL, $seed, $protocol, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $responses, $spawn, $entities, $mapDir, $mapName, $map, $level, $tileEntities;
private $database, $interface, $evCnt, $handCnt, $events, $handlers, $version, $serverType, $lastTick;
function __construct($name, $gamemode = 1, $seed = false, $protocol = CURRENT_PROTOCOL, $port = 19132, $serverID = false, $version = CURRENT_VERSION){
$this->port = (int) $port; //19132 - 19135
console("[INFO] PocketMine-MP by @shoghicp, LGPL License. http://bit.ly/TbrimG", true, true, 0);
class PocketMinecraftServer{
var $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $spawn, $entities, $mapDir, $mapName, $map, $levelData, $tileEntities;
private $database, $interface, $evCnt, $handCnt, $events, $handlers, $serverType, $lastTick, $ticker;
private function load(){
$this->version = new VersionString();
console("[INFO] PocketMine-MP ".MAJOR_VERSION." #".$this->version->getNumber()." by @shoghicp, LGPL License", true, true, 0);
console("[DEBUG] Target Minecraft PE: ".CURRENT_MINECRAFT_VERSION.", protocol #".CURRENT_PROTOCOL, true, true, 2);
console("[INFO] Starting Minecraft PE Server at *:".$this->port);
if($this->port < 19132 or $this->port > 19135){
console("[WARNING] You've selected a not-standard port. Normal port range is from 19132 to 19135 included");
}
$this->serverID = $this->serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$this->serverID;
$this->seed = $this->seed === false ? Utils::readInt(Utils::getRandomBytes(4)):$this->seed;
console("[INFO] Loading database...");
$this->startDatabase();
$this->gamemode = (int) $gamemode;
$this->version = (int) $version;
$this->name = $name;
$this->doTick = false;
$this->api = false;
$this->mapDir = false;
$this->mapName = false;
$this->events = array();
$this->handlers = array();
$this->map = false;
$this->invisible = false;
$this->level = false;
$this->levelData = false;
$this->difficulty = 1;
$this->tileEntities = array();
$this->entities = array();
@ -57,52 +58,56 @@ class PocketMinecraftServer extends stdClass{
$this->handCnt = 0;
$this->eidCnt = 1;
$this->maxClients = 20;
$this->schedule = array();
$this->scheduleCnt = 0;
$this->description = "";
$this->whitelist = false;
$this->bannedIPs = array();
$this->motd = "Welcome to ".$name;
$this->serverID = $serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$serverID;
$this->seed = $seed === false ? Utils::readInt(Utils::getRandomBytes(4)):$seed;
$this->clients = array();
$this->protocol = (int) $protocol;
$this->spawn = array("x" => 128.5,"y" => 100,"z" => 128.5);
$this->time = 0;
$this->timePerSecond = 10;
$this->tickMeasure = array_fill(0, 40, 0);
$this->setType("normal");
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, $this->port, true, false);
$this->interface = new MinecraftInterface("255.255.255.255", $this->port, true, false);
$this->reloadConfig();
console("[INFO] Server Name: ".$this->name);
console("[INFO] Server GUID: ".$this->serverID);
console("[INFO] Protocol Version: ".$this->protocol);
console("[INFO] Max Clients: ".$this->maxClients);
$this->stop = false;
console("[DEBUG] Server GUID: ".$this->serverID, true, true, 2);
$this->stop = false;
}
function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $serverID = false){
$this->port = (int) $port; //19132 - 19135
$this->gamemode = (int) $gamemode;
$this->name = $name;
$this->motd = "Welcome to ".$name;
$this->serverID = $serverID;
$this->seed = $seed;
$this->load();
}
public function getTPS(){
$v = array_values($this->tickMeasure);
$tps = 40 / ($v[39] - $v[0]);
return round($tps, 4);
}
public function loadEvents(){
$this->event("onChat", "eventHandler", true);
$this->event("onPlayerAdd", "eventHandler", true);
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->trigger("onTimeChange", $this->time);');
$this->action(5000000, 'if($this->difficulty < 2){$this->trigger("onHealthRegeneration", 1);}');
public function loadEvents(){
$this->event("player.add", array($this, "eventHandler"));
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->api->dhandle("server.time", $this->time);');
$this->action(5000000, 'if($this->difficulty < 2){$this->api->dhandle("server.regeneration", 1);}');
$this->action(1000000 * 60, '$this->reloadConfig();');
$this->action(1000000 * 60 * 10, '$this->custom = array();');
if($this->api !== false){
$this->action(1000000 * 80, '$this->chat(false, count($this->clients)."/".$this->maxClients." online: ".implode(", ",$this->api->player->online()));');
$this->action(1000000 * 80, '$cnt = count($this->clients); if($cnt > 1){$this->api->chat->broadcast("Online (".$cnt."): ".implode(", ",$this->api->player->online()));}');
}
$this->action(1000000 * 75, '$this->debugInfo(true);');
$this->action(1000000 * 120, '$this->debugInfo(true);');
}
public function startDatabase(){
$this->preparedSQL = new stdClass();
$this->database = new SQLite3(":memory:");
//$this->query("PRAGMA journal_mode = OFF;");
//$this->query("PRAGMA journal_mode = OFF;");
//$this->query("PRAGMA encoding = \"UTF-8\";");
//$this->query("PRAGMA secure_delete = OFF;");
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE);");
@ -112,12 +117,12 @@ class PocketMinecraftServer extends stdClass{
$this->query("CREATE TABLE events (ID INTEGER PRIMARY KEY, name TEXT);");
$this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);");
//$this->query("PRAGMA synchronous = OFF;");
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
$this->preparedSQL->selectEvents = $this->database->prepare("SELECT ID FROM events WHERE name = :name;");
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
$this->preparedSQL->selectEvents = $this->database->prepare("SELECT DISTINCT ID FROM events WHERE name = :name;");
$this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);");
$this->preparedSQL->updateActions = $this->database->prepare("UPDATE actions SET last = :time WHERE last <= (:time - interval);");
}
public function query($sql, $fetch = false){
console("[INTERNAL] [SQL] ".$sql, true, true, 3);
$result = $this->database->query($sql) or console("[ERROR] [SQL Error] ".$this->database->lastErrorMsg().". Query: ".$sql, true, true, 0);
@ -126,14 +131,14 @@ class PocketMinecraftServer extends stdClass{
}
return $result;
}
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){
$info = array();
$info["tps"] = $this->getTPS();
@ -146,29 +151,28 @@ class PocketMinecraftServer extends stdClass{
$info["actions"] = $this->query("SELECT count(ID) as count FROM actions;", true);
$info["actions"] = $info["actions"]["count"];
$info["garbage"] = gc_collect_cycles();
$this->handle("server.debug", $info);
if($console === true){
console("[DEBUG] TPS: ".$info["tps"].", Memory usage: ".$info["memory_usage"]." (Peak ".$info["memory_peak_usage"]."), Entities: ".$info["entities"].", Events: ".$info["events"].", Actions: ".$info["actions"].", Garbage: ".$info["garbage"], true, true, 2);
}
return $info;
}
public function close($reason = "stop"){
$this->chat(false, "Stopping server...");
$this->save();
$this->stop = true;
$this->trigger("onClose");
$this->interface->close();
}
public function chat($owner, $text, $target = true){
$message = "";
if($owner !== false){
$message = "<".$owner."> ";
if($this->stop !== true){
$this->api->chat->send(false, "Stopping server...");
$this->ticker->stop = true;
$this->save(true);
$this->stop = true;
$this->trigger("server.close", $reason);
$this->interface->close();
}
$message .= $text;
$this->trigger("onChat", $message);
}
public function chat($owner, $text, $target = false){
$this->api->chat->send($owner, $text, $target);
}
public function setType($type = "normal"){
switch($type){
case "normal":
@ -178,9 +182,9 @@ class PocketMinecraftServer extends stdClass{
$this->serverType = "MCCPP;MINECON;";
break;
}
}
public function addHandler($event, $callable, $priority = 5){
if(!is_callable($callable)){
return false;
@ -191,41 +195,64 @@ class PocketMinecraftServer extends stdClass{
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++;
}
public function handle($event, $data){
public function handle($event, &$data){
$this->preparedSQL->selectHandlers->reset();
$this->preparedSQL->selectHandlers->clear();
$this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT);
$handlers = $this->preparedSQL->selectHandlers->execute();
if($handlers === false or $handlers === true){
return $this->trigger($event, $data);
$result = true;
if($handlers !== false and $handlers !== true){
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{
break;
}
}
}
while(false !== ($hn = $handlers->fetchArray(SQLITE3_ASSOC))){
$hnid = (int) $hn["ID"];
call_user_func($this->handlers[$hnid], $data, $event);
if($result !== false){
$this->trigger($event, $data);
}
$handlers->finalize();
return true;
return $result;
}
public function eventHandler($data, $event){
switch($event){
case "onPlayerAdd":
case "player.add":
console("[DEBUG] Player \"".$data["username"]."\" EID ".$data["eid"]." spawned at X ".$data["x"]." Y ".$data["y"]." Z ".$data["z"], true, true, 2);
break;
case "onChat":
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"];
$this->level["Time"] = &$this->time;
if($this->mapName !== false and trim($this->mapName) !== ""){
$this->levelData = unserialize(file_get_contents($this->mapDir."level.dat"));
console("[INFO] Map: ".$this->levelData["LevelName"]);
$this->time = (int) $this->levelData["Time"];
$this->seed = (int) $this->levelData["RandomSeed"];
if(isset($this->levelData["SpawnX"])){
$this->spawn = array("x" => $this->levelData["SpawnX"], "y" => $this->levelData["SpawnY"], "z" => $this->levelData["SpawnZ"]);
}else{
$this->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 ".$this->levelData["SpawnX"]." Y ".$this->levelData["SpawnY"]." Z ".$this->levelData["SpawnZ"]);
console("[INFO] Time: ".$this->time);
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
@ -234,7 +261,7 @@ class PocketMinecraftServer extends stdClass{
console("[INFO] Loading map...");
$this->map = new ChunkParser();
if(!$this->map->loadFile($this->mapDir."chunks.dat")){
console("[ERROR] Couldn't load the map \"".$this->level["LevelName"]."\"!", true, true, 0);
console("[ERROR] Couldn't load the map \"".$this->levelData["LevelName"]."\"!", true, true, 0);
$this->map = false;
}else{
$this->map->loadMap();
@ -245,7 +272,7 @@ class PocketMinecraftServer extends stdClass{
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
}
}
public function loadEntities(){
if($this->map !== false){
console("[INFO] Loading entities...");
@ -269,60 +296,98 @@ class PocketMinecraftServer extends stdClass{
$e = $this->api->entity->add(ENTITY_MOB, $entity["id"]);
$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");');
}
}
public function save(){
if($this->mapName !== false){
file_put_contents($this->mapDir."level.dat", serialize($this->level));
$this->map->saveMap();
console("[INFO] Saving entities...");
foreach($this->entities as $entity){
}
$this->action(1000000 * 60 * 15, '$this->api->chat->broadcast("Forcing save...");$this->save();');
}
}
public function start(){
public function save($final = false){
if($this->mapName !== false){
$this->levelData["Time"] = $this->time;
file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
$this->map->saveMap($final);
console("[INFO] Saving entities...");
foreach($this->entities as $entity){
}
$this->trigger("server.save", $final);
}
}
public function init(){
if($this->mapName !== false and $this->map === false){
$this->loadMap();
$this->loadEntities();
}
console("[INFO] Loading events...");
$this->loadEvents();
$this->ticker = new TickLoop($this);
$this->ticker->start();
declare(ticks=15);
register_tick_function(array($this, "tick"));
register_shutdown_function(array($this, "dumpError"));
register_shutdown_function(array($this, "close"));
$this->trigger("server.start", microtime(true));
console("[INFO] Server started!");
$this->process();
}
public function dumpError(){
console("[ERROR] An Unrecovereable has ocurred and the server has Crashed. Creating an Error Dump");
$dump = "# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
$dump .= "Error: ".var_export(error_get_last(), true)."\r\n\r\n";
$version = new VersionString();
$dump .= "PM Version: ".$version." #".$version->getNumber()." [Protocol ".CURRENT_PROTOCOL."]\r\n";
$dump .= "uname -a: ".php_uname("a")."\r\n";
$dump .= "PHP Version: " .phpversion()."\r\n";
$dump .= "Zend version: ".zend_version()."\r\n";
$dump .= "OS : " .PHP_OS.", ".Utils::getOS()."\r\n";
$dump .= "Debug Info: ".var_export($this->debugInfo(false), true)."\r\n\r\n\r\n";
global $arguments;
$dump .= "Parameters: ".var_export($arguments, true)."\r\n\r\n\r\n";
$dump .= "server.properties: ".var_export($this->api->getProperties(), true)."\r\n\r\n\r\n";
$dump .= "Loaded Modules: ".var_export(get_loaded_extensions(), true)."\r\n\r\n";
$name = "error_dump_".time();
logg($dump, $name, true, 0, true);
console("[ERROR] Please submit the \"logs/{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
}
public function tick(){
/*if($this->ticker->tick === true and $this->ticker->isWaiting() === true){
$this->ticker->tick = false;
$time = microtime(true);
array_shift($this->tickMeasure);
$this->tickMeasure[] = $this->lastTick = $time;
$this->tickerFunction($time);
$this->trigger("server.tick", $time);
$this->ticker->notify();
}*/
$time = microtime(true);
if($this->lastTick <= ($time - 0.05)){
$this->tickMeasure[] = $this->lastTick = $time;
array_shift($this->tickMeasure);
$this->tickMeasure[] = $this->lastTick = $time;
$this->tickerFunction($time);
$this->trigger("onTick", $time);
$this->trigger("server.tick", $time);
}
}
public function clientID($ip, $port){
return md5($pi . $port, true);
return md5($ip . $port, true);
}
public function packetHandler($packet){
$data =& $packet["data"];
$CID = $this->clientID($packet["ip"], $packet["port"]);
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){
@ -331,7 +396,7 @@ class PocketMinecraftServer extends stdClass{
$this->serverID,
MAGIC,
$this->serverType,
), false, $packet["ip"], $packet["port"]);
), false, $packet["ip"], $packet["port"]);
break;
}
if(in_array($packet["ip"], $this->bannedIPs)){
@ -378,9 +443,9 @@ class PocketMinecraftServer extends stdClass{
}
$version = $data[1];
$size = strlen($data[2]);
if($version !== $this->protocol){
if($version !== CURRENT_PROTOCOL){
$this->send(0x1a, array(
$this->protocol,
CURRENT_PROTOCOL,
MAGIC,
$this->serverID,
), false, $packet["ip"], $packet["port"]);
@ -415,17 +480,17 @@ class PocketMinecraftServer extends stdClass{
$port = $data[2];
$MTU = $data[3];
$clientID = $data[4];
$this->clients[$CID] = new Session($this, $clientID, $packet["ip"], $packet["port"], $MTU);
$this->clients[$CID] = new Player($this, $clientID, $packet["ip"], $packet["port"], $MTU);
$this->clients[$CID]->handle(0x07, $data);
break;
}
}
}
public function send($pid, $data = array(), $raw = false, $dest = false, $port = false){
$this->interface->writePacket($pid, $data, $raw, $dest, $port);
}
public function process(){
while($this->stop === false){
$packet = @$this->interface->readPacket();
@ -433,10 +498,10 @@ class PocketMinecraftServer extends stdClass{
$this->packetHandler($packet);
}else{
usleep(1);
}
}
}
}
public function trigger($event, $data = ""){
$this->preparedSQL->selectEvents->reset();
$this->preparedSQL->selectEvents->clear();
@ -445,25 +510,43 @@ class PocketMinecraftServer extends stdClass{
if($events === false or $events === true){
return;
}
while(false !== ($evn = $events->fetchArray(SQLITE3_ASSOC))){
$evid = (int) $evn["ID"];
$this->responses[$evid] = call_user_func($this->events[$evid], $data, $event, $this);
$call = array();
while(($evn = $events->fetchArray(SQLITE3_ASSOC)) !== false){
$call[(int) $evn["ID"]] = true;
}
$events->finalize();
foreach($call as $evid => $boolean){
$ev = $this->events[$evid];
if(!is_callable($ev)){
$this->deleteEvent($evid);
continue;
}
if(is_array($ev)){
$method = $ev[1];
$ev[0]->$method($data, $event);
}else{
$ev($data, $event);
}
}
return true;
}
public function response($eid){
if(isset($this->responses[$eid])){
$res = $this->responses[$eid];
unset($this->responses[$eid]);
return $res;
public function schedule($ticks, $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
if(!is_callable($callback)){
return false;
}
return false;
}
$add = "";
if($repeat === false){
$add = ' unset($this->schedule['.$this->scheduleCnt.']);';
}
$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 false;} call_user_func($schedule[0], $schedule[1], $schedule[2]);', (bool) $repeat);
return $this->scheduleCnt++;
}
public function action($microseconds, $code, $repeat = true){
$this->query("INSERT INTO actions (interval, last, code, repeat) VALUES(".($microseconds / 1000000).", ".microtime(true).", '".str_replace("'", "\\'", $code)."', ".($repeat === true ? 1:0).");");
$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);
}
@ -473,13 +556,13 @@ class PocketMinecraftServer extends stdClass{
$this->preparedSQL->selectActions->clear();
$this->preparedSQL->selectActions->bindValue(":time", $time, SQLITE3_FLOAT);
$actions = $this->preparedSQL->selectActions->execute();
if($actions === false or $actions === true){
return;
}
while(false !== ($action = $actions->fetchArray(SQLITE3_ASSOC))){
eval($action["code"]);
if($action["repeat"] === 0){
$return = eval(base64_decode($action["code"]));
if($action["repeat"] === 0 or $return === false){
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
}
}
@ -488,12 +571,9 @@ class PocketMinecraftServer extends stdClass{
$this->preparedSQL->updateActions->clear();
$this->preparedSQL->updateActions->bindValue(":time", $time, SQLITE3_FLOAT);
$this->preparedSQL->updateActions->execute();
}
public function event($event, $func, $in = false){
if($in === true){
$func = array($this, $func);
}
}
public function event($event, $func){
if(!is_callable($func)){
return false;
}
@ -502,11 +582,11 @@ class PocketMinecraftServer extends stdClass{
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++;
}
public function deleteEvent($id){
$id = (int) $id;
unset($this->events[$id]);
$this->query("DELETE FROM events WHERE ID = ".$id.";");
}
}
}

View File

@ -42,7 +42,7 @@ class SerializedPacketHandler{
}
return $data;
}
public function __construct($pid, $raw = "", $data = array(), $create = false){
$this->raw = $raw;
$this->data = $data;
@ -54,15 +54,15 @@ class SerializedPacketHandler{
case 0x00:
if($this->c === false){
$this->data["packets"] = array();
$i = 0;
$i = 0;
while($this->offset < strlen($this->raw)){
if($i > 0){
$pid = ord($this->get(1));
}
$len = ceil(Utils::readShort($this->get(2), false) / 8); //Utils::readShort($this->get(2), false) >> 3;
if($pid !== 0x00){
$c = Utils::readTriad($this->get(3));
$c = Utils::readTriad(strrev($this->get(3)));
}
if($pid === 0x60 and $i === 0){
$this->data["unknown1"] = $this->get(4);

1057
src/classes/Spyc.class.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
<?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 SuperflatGenerator{
private $config, $spawn, $structure;
public function __construct($seed){
$this->config = array(
"preset" => "7;20x1;3x3;2",
"spawn-surface" => 24,
"spawn-radius" => 10,
"torches" => 0,
"seed" => (int) $seed,
);
$this->parsePreset();
}
public function set($name, $value){
$this->config[$name] = $value;
if($name === "preset"){
$this->parsePreset();
}
}
private function parsePreset(){
$this->structure = array(
0 => "",
1 => "",
2 => str_repeat("\x00", 64),
3 => str_repeat("\x00", 64),
);
$preset = explode(";", trim($this->config["preset"]));
foreach($preset as $i => $data){
$num = 1;
if(preg_match('#([a-zA-Z\-_]*)\((.*)\)#', $data, $matches) > 0){ //Property
$this->config[$matches[1]] = $matches[2];
continue;
}elseif(preg_match('#([0-9]*)x([0-9:]*)#', $data, $matches) > 0){
$num = (int) $matches[1];
$d = explode(":", $matches[2]);
}else{
$d = explode(":", $data);
}
$block = (int) array_shift($d);
$meta = (int) @array_shift($d);
for($j = 0; $j < $num; ++$j){
$this->structure[0] .= chr($block & 0xFF);
$this->structure[1] .= substr(dechex($meta & 0x0F), -1);
}
}
$this->structure[1] = pack("h*", str_pad($this->structure[1], (strlen($this->structure[1])&0xFE) + 2, "0", STR_PAD_RIGHT)); //invert nibbles
$this->structure[0] = substr($this->structure[0], 0, 128);
$this->structure[1] = substr($this->structure[1], 0, 64);
$this->structure[2] = substr($this->structure[2], 0, 64);
$this->structure[3] = substr($this->structure[3], 0, 64);
}
public function init(){
$this->spawn = array(128, strlen($this->structure[0]), 128);
}
public function getSpawn(){
return $this->spawn;
}
public function getColumn($x, $z){
$x = (int) $x;
$z = (int) $z;
$column = $this->structure;
if(floor(sqrt(pow($x - $this->spawn[0], 2) + pow($z - $this->spawn[2], 2))) <= $this->config["spawn-radius"]){
$column[0]{strlen($column[0])-1} = chr($this->config["spawn-surface"]);
}
if(($x % 8) === 0 and ($z % 8) === 0 and $this->config["torches"] == "1"){
$column[0] .= chr(50);
}
$column[0] .= str_repeat(chr(0), 128 - strlen($column[0]));
$column[1] .= str_repeat(chr(0), 64 - strlen($column[1]));
$column[2] .= str_repeat(chr(0), 64 - strlen($column[2]));
$column[3] .= str_repeat(chr(0), 64 - strlen($column[3]));
return $column;
}
}

View File

@ -25,11 +25,12 @@ the Free Software Foundation, either version 3 of the License, or
*/
$fp = fopen(dirname(__FILE__)."/console.in","wb");
while(true){
$l = fgets(STDIN);
fwrite($fp, $l);
if(strtolower(trim($l)) === "stop" and isset($argv[1]) and trim($argv[1]) == "1"){
die();
class TileEntity extends stdClass{
private $server;
function __construct(PocketMinecraftServer $server){
}
}
}
?>

View File

@ -30,7 +30,6 @@ the Free Software Foundation, either version 3 of the License, or
class UDPSocket{
private $encrypt;
var $buffer, $connected, $errors, $sock, $server;
function __construct($server, $port, $listen = false, $socket = false){
$this->errors = array_fill(88,(125 - 88) + 1, true);
$this->server = $server;
@ -42,7 +41,7 @@ class UDPSocket{
$this->unblock();
}else{
$this->sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($this->sock, SOL_SOCKET, SO_BROADCAST, 1);
socket_set_option($this->sock, SOL_SOCKET, SO_BROADCAST, 1);
if($listen !== true){
$this->connected = true;
$this->buffer = array();
@ -57,8 +56,8 @@ class UDPSocket{
}
}
}
function listenSocket(){
public function listenSocket(){
$sock = @socket_accept($this->sock);
if($sock !== false){
$sock = new Socket(false, false, false, $sock);
@ -67,7 +66,7 @@ class UDPSocket{
}
return false;
}
public function close($error = 125){
$this->connected = false;
if($error === false){
@ -77,7 +76,7 @@ class UDPSocket{
}
return @socket_close($this->sock);
}
public function block(){
socket_set_block($this->sock);
}
@ -85,18 +84,18 @@ class UDPSocket{
public function unblock(){
socket_set_nonblock($this->sock);
}
public function read(){
$source = false;
$port = 1;
$len = @socket_recvfrom($this->sock, $buf, 65536, 0, $source, $port);
return array($buf, $source, $port, $len);
}
public function write($data, $dest = false, $port = false){
return @socket_sendto($this->sock, $data, strlen($data), 0, ($dest === false ? $this->server:$dest), ($port === false ? $this->port:$port));
}
}
?>

View File

@ -35,32 +35,53 @@ 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));
class Utils{
class Utils extends Thread{
public function run(){
}
public static function getIP(){
$ip = trim(Utils::curl_get("http://automation.whatismyip.com/n09230945.asp"));
if($ip != ""){
return $ip;
}else{
$ip = trim(Utils::curl_get("http://checkip.dyndns.org/"));
$ip = preg_replace("/Current IP Address: (.*)/", '$1', $ip);
if($ip != ""){
return $ip;
}else{
return false;
}
}
}
public static function getOS(){
$uname = strtoupper(php_uname("s"));
if(strpos($uname, "WIN") !== false){
return "win";
}elseif(strpos($uname, "DARWIN") !== false){
return "mac";
}else{
return "linux";
}
}
public static function hexdump($bin){
$output = "";
$bin = str_split($bin, 16);
foreach($bin as $counter => $line){
$hex = chunk_split(chunk_split(str_pad(bin2hex($line), 32, " ", STR_PAD_RIGHT), 2, " "), 24, " ");
$ascii = preg_replace('#([^\x20-\x7E])#', ".", $line);
$output .= str_pad(dechex($counter << 4), 4, "0", STR_PAD_LEFT). " " . $hex . " " . $ascii . PHP_EOL;
$output .= str_pad(dechex($counter << 4), 4, "0", STR_PAD_LEFT). " " . $hex . " " . $ascii . PHP_EOL;
}
return $output;
}
public static function printable($str){
return preg_replace('#([^\x20-\x7E])#', '.', $str);
}
public static function readTriad($str){
list(,$unpacked) = unpack("N", "\x00".$str);
return (int) $unpacked;
@ -101,18 +122,18 @@ class Utils{
$m .= Utils::writeLInt($data["value"][$i]);
}
break;
}
}
$m .= "\x7f";
return $m;
return $m;
}
public static function readMetadata($value, $types = false){
$offset = 0;
$m = array();
$b = ord($value{$offset});
++$offset;
++$offset;
while($b !== 127){
$bottom = $b & 0x1F;
$type = $b >> 5;
@ -155,7 +176,7 @@ class Utils{
$offset += 4;
}
break;
}
if($types === true){
$m[$bottom] = array($r, $type);
@ -165,9 +186,9 @@ class Utils{
$b = ord($value{$offset});
++$offset;
}
return $m;
return $m;
}
public static function readDataArray($str, $len = 10, &$offset = null){
$data = array();
$offset = 0;
@ -179,7 +200,7 @@ class Utils{
}
return $data;
}
public static function writeDataArray($data){
$raw = "";
foreach($data as $v){
@ -188,7 +209,7 @@ class Utils{
}
return $raw;
}
public static function getRandomBytes($length = 16, $secure = true, $raw = true, $startEntropy = "", &$rounds = 0, &$drop = 0){
$output = b"";
$length = abs((int) $length);
@ -225,7 +246,7 @@ class Utils{
(string) disk_total_space("."),
uniqid(microtime(),true),
);
shuffle($weakEntropy);
$value = hash("sha256", implode($weakEntropy), true);
foreach($weakEntropy as $k => $c){ //mixing entropy values with XOR and hash randomness extractor
@ -235,7 +256,7 @@ class Utils{
$value ^= hash("sha256", $c . microtime() . $k, true);
}
unset($weakEntropy);
if($secure === true){
$strongEntropy = array(
is_array($startEntropy) ? $startEntropy[($rounds + $drop) % count($startEntropy)]:$startEntropy, //Get a random index of the startEntropy, or just read it
@ -273,15 +294,15 @@ class Utils{
}
return $raw === false ? bin2hex($output):$output;
}
public static function round($number){
return round($number, 0, PHP_ROUND_HALF_DOWN);
}
public static function distance($pos1, $pos2){
return sqrt(pow($pos1["x"] - $pos2["x"], 2) + pow($pos1["y"] - $pos2["y"], 2) + pow($pos1["z"] - $pos2["z"], 2));
}
public static function angle3D($pos1, $pos2){
$X = $pos1["x"] - $pos2["x"];
$Z = $pos1["z"] - $pos2["z"];
@ -291,20 +312,20 @@ class Utils{
$vAngle = rad2deg(-atan2($Y, $dXZ));
return array("yaw" => $hAngle, "pitch" => $vAngle);
}
public static function sha1($input){
$number = new Math_BigInteger(sha1($input, true), -256);
$zero = new Math_BigInteger(0);
return ($zero->compare($number) <= 0 ? "":"-") . ltrim($number->toHex(), "0");
}
public static function microtime(){
return microtime(true);
}
public static function curl_get($page){
$ch = curl_init($page);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Minecraft PHP Client 2"));
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"));
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
@ -315,40 +336,40 @@ class Utils{
curl_close($ch);
return $ret;
}
public static function curl_post($page, $args, $timeout = 10){
$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);
curl_close($ch);
return $ret;
}
public static function strToHex($str){
return bin2hex($str);
}
public static function hexToStr($hex){
if(HEX2BIN === true){
return hex2bin($hex);
}
}
return pack("H*" , $hex);
}
public static function readBool($b){
return Utils::readByte($b, false) === 0 ? false:true;
}
public static function writeBool($b){
return Utils::writeByte($b === true ? 1:0);
}
public static function readByte($c, $signed = true){
$b = ord($c{0});
if($signed === true and ($b & 0x80) === 0x80){ //calculate Two's complement
@ -356,7 +377,7 @@ class Utils{
}
return $b;
}
public static function writeByte($c){
if($c > 0xff){
return false;
@ -374,14 +395,14 @@ class Utils{
}
return $unpacked;
}
public static function writeShort($value){
if($value < 0){
$value += 0x10000;
$value += 0x10000;
}
return pack("n", $value);
}
public static function readLShort($str, $signed = true){
list(,$unpacked) = unpack("v", $str);
if($unpacked > 0x7fff and $signed === true){
@ -389,10 +410,10 @@ class Utils{
}
return $unpacked;
}
public static function writeLShort($value){
if($value < 0){
$value += 0x10000;
$value += 0x10000;
}
return pack("v", $value);
}
@ -404,14 +425,14 @@ class Utils{
}
return (int) $unpacked;
}
public static function writeInt($value){
if($value < 0){
$value += 0x100000000;
$value += 0x100000000;
}
return pack("N", $value);
}
public static function readLInt($str){
list(,$unpacked) = unpack("V", $str);
if($unpacked >= 2147483648){
@ -419,50 +440,50 @@ class Utils{
}
return (int) $unpacked;
}
public static function writeLInt($value){
if($value < 0){
$value += 0x100000000;
$value += 0x100000000;
}
return pack("V", $value);
}
public static function readFloat($str){
list(,$value) = ENDIANNESS === BIG_ENDIAN ? unpack("f", $str):unpack("f", strrev($str));
return $value;
}
public static function writeFloat($value){
return ENDIANNESS === BIG_ENDIAN ? pack("f", $value):strrev(pack("f", $value));
}
public static function readLFloat($str){
list(,$value) = ENDIANNESS === BIG_ENDIAN ? unpack("f", strrev($str)):unpack("f", $str);
return $value;
}
public static function writeLFloat($value){
return ENDIANNESS === BIG_ENDIAN ? strrev(pack("f", $value)):pack("f", $value);
}
public static function printFloat($value){
return preg_replace("/(\.\d+?)0+$/", "$1", sprintf("%F", $value));
}
public static function readDouble($str){
list(,$value) = ENDIANNESS === BIG_ENDIAN ? unpack("d", $str):unpack("d", strrev($str));
return $value;
}
public static function writeDouble($value){
return ENDIANNESS === BIG_ENDIAN ? pack("d", $value):strrev(pack("d", $value));
}
public static function readLDouble($str){
list(,$value) = ENDIANNESS === BIG_ENDIAN ? unpack("d", strrev($str)):unpack("d", $str);
return $value;
}
public static function writeLDouble($value){
return ENDIANNESS === BIG_ENDIAN ? strrev(pack("d", $value)):pack("d", $value);
}
@ -471,20 +492,20 @@ class Utils{
$long = new Math_BigInteger($str, -256);
return $long->toString();
}
public static function writeLong($value){
$long = new Math_BigInteger($value, -10);
return str_pad($long->toBytes(true), 8, "\x00", STR_PAD_LEFT);
}
public static function readLLong($str){
$long = new Math_BigInteger(strrev($str), -256);
return $long->toString();
}
public static function writeLLong($value){
$long = new Math_BigInteger($value, -10);
return strrev(str_pad($long->toBytes(true), 8, "\x00", STR_PAD_LEFT));
}
}
}

View File

@ -25,21 +25,15 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once("common/dependencies.php");
require_once("classes/PocketMinecraftClient.class.php");
file_put_contents("packets.log", "");
define("DEBUG", 2);
define("WINDOW_CHEST", 0);
define("WINDOW_WORKBENCH", 1);
define("WINDOW_FURNACE", 2);
$client = new PocketMinecraftClient("shoghicp");
console("[INFO] Searching servers...");
$list = $client->getServerList();
foreach($list as $i => $info){
console("[Server] #".$i." ".$info["ip"]." ".$info["username"]);
class Window{
private $server;
public function __construct(PocketMinecraftServer $server){
}
}
console("[Select Server] #", false, false);
$i = (int) trim(fgets(STDIN));
if(isset($list[$i])){
$client->start($list[$i]["ip"]);
}else{
console("[Error] Unknown ID");
}
?>

View File

@ -32,11 +32,12 @@ error_reporting(E_ALL ^ E_NOTICE);
ini_set("allow_url_fopen", 1);
ini_set("display_errors", 1);
ini_set('default_charset', 'utf-8');
define("FILE_PATH", dirname(__FILE__)."/../");
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH . PATH_SEPARATOR . FILE_PATH . "/classes/");
ini_set("memory_limit", "256M");
define("CURRENT_PROTOCOL", 5);
define("CURRENT_VERSION", 1);
define("FILE_PATH", dirname(__FILE__)."/../../");
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH . PATH_SEPARATOR . FILE_PATH . "/src/" . PATH_SEPARATOR . FILE_PATH . "/src/classes/");
ini_set("memory_limit", "512M");
define("LOG", true);
define("MAGIC", "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78");
define("TEST_MD5", "5ca8eced50a5801619f7ae86d631a4e7");
define("TEST_MD5", "d0ca3786e53b615bb4fb9f5094d5c9a7");
define("MAJOR_VERSION", "Alpha_1.0.6");
define("CURRENT_PROTOCOL", 5);
define("CURRENT_MINECRAFT_VERSION", "v0.5.0 alpha");

View File

@ -0,0 +1,20 @@
#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

@ -25,7 +25,6 @@ the Free Software Foundation, either version 3 of the License, or
*/
require_once(dirname(__FILE__)."/config.php");
require_once("common/functions.php");
//set_error_handler("error_handler");
@ -35,6 +34,9 @@ $errors = 0;
if(version_compare("5.3.3", PHP_VERSION) > 0){
console("[ERROR] Use PHP >= 5.3.3", true, true, 0);
++$errors;
}elseif(version_compare("5.5.0", PHP_VERSION) <= 0){
console("[NOTICE] PocketMine-MP hasn't been tested with PHP >= 5.5", true, true, 0);
++$errors;
}
if(version_compare("5.4.0", PHP_VERSION) > 0){
@ -49,29 +51,49 @@ if(php_sapi_name() !== "cli"){
++$errors;
}
if(!extension_loaded("sockets")){
if(!extension_loaded("sockets") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "sockets." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find Socket extension", true, true, 0);
++$errors;
}
if(!extension_loaded("curl")){
if(!extension_loaded("pthreads") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "pthreads." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find pthreads extension. Use the Installer available in the Homepage", true, true, 0);
++$errors;
}
if(!extension_loaded("curl") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "curl." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find cURL extension", true, true, 0);
++$errors;
}
if(!extension_loaded("sqlite3")){
if(!extension_loaded("sqlite3") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "sqlite3." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find SQLite3 extension", true, true, 0);
++$errors;
}
if(!extension_loaded("zlib") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "zlib." . PHP_SHLIB_SUFFIX) === false){
console("[ERROR] Unable to find Zlib extension. Compressed worlds won't be loaded", true, true, 0);
define("ZLIB_EXTENSION", false);
}else{
define("ZLIB_EXTENSION", true);
}
if($errors > 0){
die();
}
require_once("classes/Async.class.php");
require_once("classes/Data.class.php");
require_once("classes/Player.class.php");
require_once("classes/Generator.class.php");
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");
@ -79,5 +101,6 @@ require_once("classes/SerializedPacketHandler.class.php");
require_once("classes/CustomPacketHandler.class.php");
require_once("classes/MinecraftInterface.class.php");
require_once("classes/BigInteger.class.php");
require_all(FILE_PATH . "src/misc/");
?>

View File

@ -26,6 +26,62 @@ the Free Software Foundation, either version 3 of the License, or
*/
function kill($pid){
switch(Utils::getOS()){
case "win":
ob_start();
passthru("%WINDIR%\\System32\\taskkill.exe /F /PID ".((int) $pid));
ob_end_clean();
break;
case "mac":
case "linux":
default:
ob_start();
passthru("kill -9 ".((int) $pid));
ob_end_clean();
}
}
function require_all($path, &$count = 0){
$dir = dir($path."/");
while(false !== ($file = $dir->read())){
if($file !== "." and $file !== ".."){
if(!is_dir($path.$file) and strtolower(substr($file, -3)) === "php"){
require_once($path.$file);
++$count;
}elseif(is_dir($path.$file)){
require_all($path.$file."/", $count);
}
}
}
}
function hard_unset(&$var){
if(is_object($var)){
$unset = new ReflectionClass($var);
foreach($unset->getProperties() as $prop){
$prop->setAccessible(true);
@hard_unset($prop->getValue($var));
$prop->setValue($var, null);
}
$var = null;
unset($var);
}elseif(is_array($var)){
foreach($var as $i => $v){
hard_unset($var[$i]);
}
$var = null;
unset($var);
}else{
$var = null;
unset($var);
}
}
function parseNBTData($data){
$x = array();
if(isset($data["value"])){
@ -51,12 +107,12 @@ function parseNBTData($data){
}
function arg($name, $default){
function arg($name, $default = false){
global $arguments, $argv;
if(!isset($arguments)){
$arguments = arguments($argv);
}
if(isset($arguments["commands"][$name])){
return $arguments["commands"][$name];
}else{
@ -71,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(
@ -109,13 +165,12 @@ 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;
if($log === true and (!defined("LOG") or LOG === true)){
logg($message, "console", false, $level);
}
}
echo $message;
}
}
@ -131,10 +186,10 @@ function logg($message, $name, $EOL = true, $level = 2, $close = false){
if(!isset($fpointers)){
$fpointers = array();
}
if(!isset($fpointers[$name])){
$fpointers[$name] = fopen(FILE_PATH."/".$name.".log", "ab");
if(!isset($fpointers[$name]) or $fpointers[$name] === false){
$fpointers[$name] = @fopen(FILE_PATH."logs/".$name.".log", "ab");
}
fwrite($fpointers[$name], $message);
@fwrite($fpointers[$name], $message);
if($close === true){
fclose($fpointers[$name]);
unset($fpointers[$name]);

View File

@ -0,0 +1,31 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
/*
class BlockIterator implements Iterator{
}*/

View File

@ -0,0 +1,38 @@
<?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 Sapling{
const OAK = 0;
const SPRUCE = 1;
const BIRCH = 2;
const BURN_TIME = 5;
public static function growTree(LevelAPI $level, $block, $type){
$type = $type & 0x03;
TreeObject::growTree($level, $block, $type);
}
}

110
src/misc/math/Vector2.php Normal file
View File

@ -0,0 +1,110 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class Vector2{
public $x, $y;
public function __construct($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
$this->__construct($x->x, $x->y);
}else{
$this->x = $x;
$this->y = $y;
}
}
public function getX(){
return $this->x;
}
public function getY(){
return $this->y;
}
public function getFloorX(){
return (int) $this->x;
}
public function getFloorY(){
return (int) $this->y;
}
public function add($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
return $this->add($x->x, $x->y);
}else{
$this->x += $x;
$this->y += $y;
return new Vector3($this->x + $x, $this->y + $y);
}
}
public function subtract($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
return $this->add(-$x->x, -$x->y);
}else{
return $this->add(-$x, -$y);
}
}
public function ceil(){
return new Vector2((int) ($this->x + 1), (int) ($this->y + 1));
}
public function floor(){
return new Vector2((int) $this->x, (int) $this->y);
}
public function round(){
return new Vector2(round($this->x), round($this->y));
}
public function abs(){
return new Vector2(abs($this->x), abs($this->y));
}
public function distance($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
return sqrt($this->distanceSquared($x->x, $x->y));
}else{
return sqrt($this->distanceSquared($x, $y));
}
}
public function distanceSquared($x = 0, $y = 0){
if(($x instanceof Vector2) === true){
return $this->distanceSquared($x->x, $x->y);
}else{
return pow($this->x - $x, 2) + pow($this->y - $y, 2);
}
}
public function __toString(){
return "Vector2(x=".$this->x.",y=".$this->y.")";
}
}

140
src/misc/math/Vector3.php Normal file
View File

@ -0,0 +1,140 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class Vector3{
public $x, $y, $z;
public function __construct($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
$this->__construct($x->x, $x->y, $x->z);
}else{
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
public function getX(){
return $this->x;
}
public function getY(){
return $this->y;
}
public function getZ(){
return $this->z;
}
public function getFloorX(){
return (int) $this->x;
}
public function getFloorY(){
return (int) $this->y;
}
public function getFloorZ(){
return (int) $this->z;
}
public function getRight(){
return $this->getX();
}
public function getUp(){
return $this->getY();
}
public function getForward(){
return $this->getZ();
}
public function getSouth(){
return $this->getX();
}
public function getWest(){
return $this->getZ();
}
public function add($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
return $this->add($x->x, $x->y, $x->z);
}else{
$this->x += $x;
$this->y += $y;
$this->z += $z;
return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
}
}
public function subtract($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
return $this->add(-$x->x, -$x->y, -$x->z);
}else{
return $this->add(-$x, -$y, -$z);
}
}
public function ceil(){
return new Vector3((int) ($this->x + 1), (int) ($this->y + 1), (int) ($this->z + 1));
}
public function floor(){
return new Vector3((int) $this->x, (int) $this->y, (int) $this->z);
}
public function round(){
return new Vector3(round($this->x), round($this->y), round($this->z));
}
public function abs(){
return new Vector3(abs($this->x), abs($this->y), abs($this->z));
}
public function distance($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
return sqrt($this->distanceSquared($x->x, $x->y, $x->z));
}else{
return sqrt($this->distanceSquared($x, $y, $z));
}
}
public function distanceSquared($x = 0, $y = 0, $z = 0){
if(($x instanceof Vector3) === true){
return $this->distanceSquared($x->x, $x->y, $x->z);
}else{
return pow($this->x - $x, 2) + pow($this->y - $y, 2) + pow($this->z - $z, 2);
}
}
public function __toString(){
return "Vector3(x=".$this->x.",y=".$this->y.",z=".$this->z.")";
}
}

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,47 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class TickLoop extends Thread{
var $tick = false, $stop = false, $lastTick = 0;
private $server;
public function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
public function run(){
while($this->stop !== true){
usleep(1);
$time = microtime(true);
if($this->lastTick <= ($time - 0.05)){
$this->lastTick = $time;
$this->tick = true;
$this->wait();
$this->tick = false;
}
}
exit(0);
}
}

61
src/misc/utils/UPnP.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
function UPnP_PortForward($port){
if(Utils::getOS() != "win" or !class_exists("COM")){
return false;
}
$port = (int) $port;
$myLocalIP = gethostbyname(trim(`hostname`));
try{
$com = new COM("HNetCfg.NATUPnP");
if($com === false or !is_object($com->StaticPortMappingCollection)){
return false;
}
$com->StaticPortMappingCollection->Add($port, "UDP", $port, $myLocalIP, true, "PocketMine-MP");
}catch(Exception $e){
return false;
}
return true;
}
function UPnP_RemovePortForward($port){
if(Utils::getOS() != "win" or !class_exists("COM")){
return false;
}
$port = (int) $port;
try{
$com = new COM("HNetCfg.NATUPnP") or false;
if($com === false or !is_object($com->StaticPortMappingCollection)){
return false;
}
$com->StaticPortMappingCollection->Remove($port, "UDP");
}catch(Exception $e){
return false;
}
return true;
}

View File

@ -0,0 +1,96 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class VersionString{
public static $stageOrder = array(
"alpha" => 0,
"beta" => 1,
"final" => 2,
);
private $stage, $major, $release, $minor;
public function __construct($version = MAJOR_VERSION){
if(is_int($version)){
$this->minor = $version & 0x1F;
$this->major = ($version >> 5) & 0x0F;
$this->generation = ($version >> 9) & 0x0F;
$this->stage = array_search(($version >> 13) & 0x0F, VersionString::$stageOrder, true);
}else{
$version = preg_split("/([A-Za-z]*)[ _\-]([0-9]*)\.([0-9]*)\.{0,1}([0-9]*)/", $version, -1, PREG_SPLIT_DELIM_CAPTURE);
$this->stage = strtolower($version[1]); //0-15
$this->generation = (int) $version[2]; //0-15
$this->major = (int) $version[3]; //0-15
$this->minor = (int) $version[4]; //0-31
}
}
public function getNumber(){
return (int) (VersionString::$stageOrder[$this->stage] << 13) + ($this->generation << 9) + ($this->major << 5) + $this->minor;
}
public function getStage(){
return $this->stage;
}
public function getGeneration(){
return $this->generation;
}
public function getMajor(){
return $this->major;
}
public function getMinor(){
return $this->minor;
}
public function getRelease(){
return $this->generation . "." . $this->major . "." . $this->minor;
}
public function __toString(){
return ucfirst($this->stage) . "_" . $this->generation . "." . $this->major . "." . $this->minor;
}
public function compare($target, $diff = false){
if(($target instanceof VersionString) === false){
$target = new VersionString($target);
}
$number = $this->getNumber();
$tNumber = $target->getNumber();
if($diff === true){
return $tNumber - $number;
}
if($number > $tNumber){
return -1; //Target is older
}elseif($number < $tNumber){
return 1; //Target is newer
}else{
return 0; //Same version
}
}
}

View File

@ -0,0 +1,89 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
class BigTreeObject extends TreeObject{
private $trunkHeightMultiplier = 0.618;
private $trunkHeight;
private $leafAmount = 1;
private $leafDistanceLimit = 5;
private $widthScale = 1;
private $branchSlope = 0.381;
private $totalHeight = 6;
private $leavesHeight = 3;
protected $radiusIncrease = 0;
private $addLeavesVines = false;
private $addLogVines = false;
private $addCocoaPlants = false;
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
return false;
}
public function placeObject(LevelAPI $level, $x, $y, $z, $type){
$this->trunkHeight = (int) ($this->totalHeight * $this->trunkHeightMultiplier);
$leaves = $this->getLeafGroupPoints($level, $x, $y, $z);
foreach($leaves as $leafGroup){
$groupX = $leafGroup->getBlockX();
$groupY = $leafGrou->getBlockY();
$groupZ = $leafGroup->getBlockZ();
for ($yy = $groupY; $yy < $groupY + $this->leafDistanceLimit; ++$yy) {
$this->generateGroupLayer($level, $groupX, $yy, $groupZ, $this->getLeafGroupLayerSize($yy - $groupY));
}
}
/*final BlockIterator trunk = new BlockIterator(new Point(w, x, y - 1, z), new Point(w, x, y + trunkHeight, z));
while (trunk.hasNext()) {
trunk.next().setMaterial(VanillaMaterials.LOG, logMetadata);
}
generateBranches(w, x, y, z, leaves);
$level->setBlock($x, $y - 1, $z, 3, 0);
$this->totalHeight += mt_rand(-1, 3);
$this->leavesHeight += mt_rand(0, 1);
for($yy = ($this->totalHeight - $this->leavesHeight); $yy < ($this->totalHeight + 1); ++$yy){
$yRadius = ($yy - $this->totalHeight);
$xzRadius = (int) (($this->radiusIncrease + 1) - $yRadius / 2);
for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){
for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){
if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $type);
}
}
}
}
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
$level->setBlock($x, $y + $yy, $z, 17, $type);
}
*/
}
}

View File

@ -0,0 +1,97 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
class PineTreeObject extends TreeObject{
var $type = 1;
private $totalHeight = 8;
private $leavesSizeY = -1;
private $leavesAbsoluteMaxRadius = -1;
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
$this->findRandomLeavesSize();
$checkRadius = 0;
for($yy = 0; $yy < ($this->totalHeight + 2); ++$yy) {
if($yy === $this->leavesSizeY) {
$checkRadius = $this->leavesAbsoluteMaxRadius;
}
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
if(!isset($this->overridable[$block[0]])){
return false;
}
}
}
}
return true;
}
private function findRandomLeavesSize(){
$this->totalHeight += mt_rand(-1, 2);
$this->leavesSizeY = 1 + mt_rand(0,2);
$this->leavesAbsoluteMaxRadius = 2 + mt_rand(0, 2);
}
public function placeObject(LevelAPI $level, $x, $y, $z){
if($this->leavesSizeY === -1 or $this->leavesAbsoluteMaxRadius === -1) {
$this->findRandomLeavesSize();
}
$level->setBlock($x, $y - 1, $z, 3, 0);
$leavesRadius = mt_rand(0,2);
$leavesMaxRadius = 1;
$leavesBottomY = $this->totalHeight - $this->leavesSizeY;
$firstMaxedRadius = false;
for($leavesY = 0; $leavesY < ($leavesBottomY + 1); ++$leavesY) {
$yy = $this->totalHeight - $leavesY;
for ($xx = -$leavesRadius; $xx < ($leavesRadius + 1); ++$xx) {
for ($zz = -$leavesRadius; $zz < ($leavesRadius + 1); ++$zz) {
if (abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0) {
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
}
}
}
if ($leavesRadius >= $leavesMaxRadius) {
$leavesRadius = $firstMaxedRadius ? 1 : 0;
$firstMaxedRadius = true;
if (++$leavesMaxRadius > $this->leavesAbsoluteMaxRadius) {
$leavesMaxRadius = $this->leavesAbsoluteMaxRadius;
}
}else{
++$leavesRadius;
}
}
$trunkHeightReducer = mt_rand(0,3);
for($yy = 0; $yy < ($this->totalHeight - $trunkHeightReducer); ++$yy){
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
}
}
}

View File

@ -0,0 +1,79 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
class SmallTreeObject extends TreeObject{
var $type = 0;
private $totalHeight = 6;
private $leavesHeight = 3;
protected $radiusIncrease = 0;
private $addLeavesVines = false;
private $addLogVines = false;
private $addCocoaPlants = false;
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
$radiusToCheck = $this->radiusIncrease;
for ($yy = 0; $yy < $this->totalHeight + 2; ++$yy) {
if ($yy == 1 or $yy === $this->totalHeight - 1) {
++$radiusToCheck;
}
for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){
for($zz = -$radiusToCheck; $zz < ($radiusToCheck + 1); ++$zz){
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
if(!isset($this->overridable[$block[0]])){
return false;
}
}
}
}
return true;
}
public function placeObject(LevelAPI $level, $x, $y, $z){
$level->setBlock($x, $y - 1, $z, 3, 0);
$this->totalHeight += mt_rand(-1, 3);
$this->leavesHeight += mt_rand(0, 1);
for($yy = ($this->totalHeight - $this->leavesHeight); $yy < ($this->totalHeight + 1); ++$yy){
$yRadius = ($yy - $this->totalHeight);
$xzRadius = (int) (($this->radiusIncrease + 1) - $yRadius / 2);
for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){
for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){
if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
}
}
}
}
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
}
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
require_once("misc/world/generator/object/tree/TreeObject.php");
class SpruceTreeObject extends TreeObject{
var $type = 1;
private $totalHeight = 8;
private $leavesBottomY = -1;
private $leavesMaxRadius = -1;
public function canPlaceObject(LevelAPI $level, $x, $y, $z){
$this->findRandomLeavesSize();
$checkRadius = 0;
for($yy = 0; $yy < $this->totalHeight + 2; ++$yy) {
if($yy === $this->leavesBottomY) {
$checkRadius = $this->leavesMaxRadius;
}
for($xx = -$checkRadius; $xx < ($checkRadius + 1); ++$xx){
for($zz = -$checkRadius; $zz < ($checkRadius + 1); ++$zz){
$block = $level->getBlock($x + $xx, $y + $yy, $z + $zz);
if(!isset($this->overridable[$block[0]])){
return false;
}
}
}
}
return true;
}
private function findRandomLeavesSize(){
$this->totalHeight += mt_rand(-1, 2);
$this->leavesBottomY = (int) ($this->totalHeight - mt_rand(1,2) - 3);
$this->leavesMaxRadius = 1 + mt_rand(0, 1);
}
public function placeObject(LevelAPI $level, $x, $y, $z){
if($this->leavesBottomY === -1 or $this->leavesMaxRadius === -1) {
$this->findRandomLeavesSize();
}
$level->setBlock($x, $y - 1, $z, 3, 0);
$leavesRadius = 0;
for($yy = $this->totalHeight; $yy >= $this->leavesBottomY; --$yy){
for ($xx = -$leavesRadius; $xx < ($leavesRadius + 1); ++$xx) {
for ($zz = -$leavesRadius; $zz < ($leavesRadius + 1); ++$zz) {
if (abs($xx) != $leavesRadius or abs($zz) != $leavesRadius or $leavesRadius <= 0) {
$level->setBlock($x + $xx, $y + $yy, $z + $zz, 18, $this->type);
}
}
}
if ($leavesRadius > 0 and $yy === ($y + $this->leavesBottomY + 1)) {
--$leavesRadius;
}elseif($leavesRadius < $this->leavesMaxRadius){
++$leavesRadius;
}
}
for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){
$level->setBlock($x, $y + $yy, $z, 17, $this->type);
}
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
class TreeObject{
var $overridable = array(
0 => true,
6 => true,
17 => true,
18 => true,
);
public static function growTree(LevelAPI $level, $block, $type){
switch($type){
case Sapling::SPRUCE:
if(mt_rand(0,1) == 2){
$tree = new SpruceTreeObject();
}else{
$tree = new PineTreeObject();
}
break;
case Sapling::BIRCH:
$tree = new SmallTreeObject();
$tree->type = Sapling::BIRCH;
break;
default:
case Sapling::OAK:
if(mt_rand(0,9) === 0){
$tree = new BigTreeObject();
}else{
$tree = new SmallTreeObject();
}
break;
}
if($tree->canPlaceObject($level, $block[2][0], $block[2][1], $block[2][2])){
$tree->placeObject($level, $block[2][0], $block[2][1], $block[2][2]);
}
}
}

View File

@ -30,20 +30,20 @@ $pstruct = array(
"long", //Ping ID
"magic",
),
0x05 => array(
"magic",
"byte", //Protocol Version
"special1", //MTU Size Null Lenght
),
0x06 => array(
"magic",
"long", //Server GUID
"byte", //Server Security
"short", //MTU Size
),
0x07 => array(
"magic",
5, //Security Cookie (idk why it's sent here)
@ -51,7 +51,7 @@ $pstruct = array(
"short", //MTU Size
"long", //Client GUID
),
0x08 => array(
"magic",
"long", //Server GUID
@ -59,20 +59,20 @@ $pstruct = array(
"short", //MTU Size
"byte", //Security
),
0x1a => array(
"byte", //Server Version
"magic",
"long", //Server GUID
),
0x1c => array(
"long", //Ping ID
"long", //Server GUID
"magic",
"string", //Data
),
0x1d => array(
"long", //Ping ID
"long", //Server GUID
@ -85,50 +85,50 @@ $pstruct = array(
"ubyte",
"customData",
),
0x81 => array(
"itriad",
"ubyte",
"customData",
),
0x82 => array(
"itriad",
"ubyte",
"customData",
),
0x83 => array(
"itriad",
"ubyte",
"customData",
),
0x84 => array(
"itriad",
"ubyte",
"customData",
),
0x85 => array(
"itriad",
"ubyte",
"customData",
),
0x86 => array(
"itriad",
"ubyte",
"customData",
),
0x87 => array(
"itriad",
"ubyte",
"customData",
),
0x88 => array(
"itriad",
"ubyte",
@ -140,52 +140,52 @@ $pstruct = array(
"ubyte",
"customData",
),
0x8a => array(
"itriad",
"ubyte",
"customData",
),
0x8b => array(
"itriad",
"ubyte",
"customData",
),
0x8c => array(
"itriad",
"ubyte",
"customData",
),
0x8d => array(
"itriad",
"ubyte",
"customData",
),
0x8e => array(
"itriad",
"ubyte",
"customData",
),
0x8f => array(
"itriad",
"ubyte",
"customData",
),
0xa0 => array(
"short",
"bool",
"itriad",
"special1",
),
0xc0 => array(
"short",
"bool",

View File

@ -27,43 +27,46 @@ the Free Software Foundation, either version 3 of the License, or
$dataName = array(
MC_KEEP_ALIVE => "KeepAlive",
MC_CLIENT_CONNECT => "ClientConnect",
MC_SERVER_HANDSHAKE => "ServerHandshake",
MC_CLIENT_HANDSHAKE => "ClientHandshake",
MC_DISCONNECT => "Disconnect",
0x18 => "Unknown",
MC_LOGIN => "Login",
MC_LOGIN_STATUS => "LoginStatus",
MC_READY => "Ready",
MC_CHAT => "Chat",
MC_SET_TIME => "SetTime",
MC_START_GAME => "StartGame",
MC_ADD_MOB => "AddMob",
MC_ADD_PLAYER => "AddPlayer",
MC_ADD_ENTITY => "AddEntity",
MC_REMOVE_ENTITY => "RemoveEntity",
MC_ADD_ITEM_ENTITY => "AddItemEntity",
MC_TAKE_ITEM_ENTITY => "TakeItemEntity",
MC_MOVE_ENTITY => "MoveEntity",
MC_MOVE_ENTITY_POSROT => "MoveEntity_PosRot",
MC_MOVE_PLAYER => "MovePlayer",
MC_PLACE_BLOCK => "PlaceBlock",
MC_PLACE_BLOCK => "PlaceBlock",
MC_REMOVE_BLOCK => "RemoveBlock",
MC_UPDATE_BLOCK => "UpdateBlock",
MC_EXPLOSION => "Explosion",
MC_REQUEST_CHUNK => "RequestChunk",
MC_CHUNK_DATA => "ChunkData",
MC_PLAYER_EQUIPMENT => "PlayerEquipment",
MC_INTERACT => "Interact",
MC_USE_ITEM => "UseItem",
MC_PLAYER_ACTION => "PlayerAction",
@ -73,7 +76,12 @@ $dataName = array(
MC_SET_SPAWN_POSITION => "SetSpawnPosition",
MC_ANIMATE => "Animate",
MC_RESPAWN => "Respawn",
MC_DROP_ITEM => "DropItem",
MC_CONTAINER_OPEN => "ContainerOpen",
MC_CONTAINER_CLOSE => "ContainerClose",
MC_CONTAINER_SET_SLOT => "ContainerSetSlot",
MC_CLIENT_MESSAGE => "ClientMessage",
MC_SIGN_UPDATE => "SignUpdate",
MC_ADVENTURE_SETTINGS => "AdventureSettings",

View File

@ -50,6 +50,7 @@ define("MC_ADD_PLAYER", 0x89);
define("MC_ADD_ENTITY", 0x8c);
define("MC_REMOVE_ENTITY", 0x8d);
define("MC_ADD_ITEM_ENTITY", 0x8e);
define("MC_TAKE_ITEM_ENTITY", 0x8f);
define("MC_MOVE_ENTITY", 0x90);
@ -59,6 +60,8 @@ define("MC_PLACE_BLOCK", 0x95);
define("MC_REMOVE_BLOCK", 0x96);
define("MC_UPDATE_BLOCK", 0x97);
define("MC_EXPLOSION", 0x99);
define("MC_REQUEST_CHUNK", 0x9d);
define("MC_CHUNK_DATA", 0x9e);
@ -74,6 +77,11 @@ define("MC_SET_SPAWN_POSITION", 0xa6);
define("MC_ANIMATE", 0xa7);
define("MC_RESPAWN", 0xa8);
define("MC_DROP_ITEM", 0xaa);
define("MC_CONTAINER_OPEN", 0xab);
define("MC_CONTAINER_CLOSE", 0xac);
define("MC_CONTAINER_SET_SLOT", 0xad);
define("MC_CLIENT_MESSAGE", 0xb1);
define("MC_SIGN_UPDATE", 0xb2);
define("MC_ADVENTURE_SETTINGS", 0xb3);

View File

@ -1,5 +1,5 @@
@echo off
TITLE Pocket-Minecraft-PHP Server - by @shoghicp
TITLE PocketMine-MP Server - by @shoghicp
COLOR F0
mode con: cols=90
@ -7,8 +7,8 @@ echo.
echo -
echo / \
echo / \
echo / POCKET \
echo / MINECRAFT PHP \
echo / PocketMine \
echo / MP \
echo ^|\ @shoghicp /^|
echo ^|. \ / .^|
echo ^| .. \ / .. ^|
@ -26,7 +26,6 @@ if not "%PHPOUTPUT%"=="1" (
echo [ERROR] Couldn't find PHP binary in PATH.
ping 127.0.0.1 -n 3 -w 1000>nul
) else (
START /B CMD /C CALL php server.php
START /B /WAIT php input.php 1
ping 127.0.0.1 -n 5 -w 1000>nul
)
START /B /WAIT php -d enable_dl=On PocketMine-MP.php
)
pause

8
start.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
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
exit 0
fi
php -d enable_dl=On PocketMine-MP.php