Compare commits

..

9 Commits

44 changed files with 744 additions and 175 deletions

View File

@ -564,7 +564,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
Level::getXZ($index, $X, $Z);
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
if($entity !== $this){
if($entity !== $this and !$entity->closed and !$entity->dead){
$entity->spawnTo($this);
}
}

View File

@ -73,7 +73,7 @@ namespace pocketmine {
use raklib\RakLib;
const VERSION = "Alpha_1.4dev";
const API_VERSION = "1.4.1";
const API_VERSION = "1.5.0";
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
const MINECRAFT_VERSION = "v0.9.5 alpha";

View File

@ -290,14 +290,14 @@ class Server{
* @return string
*/
public function getIp(){
return $this->getConfigString("server-ip", "");
return $this->getConfigString("server-ip", "0.0.0.0");
}
/**
* @return string
*/
public function getServerName(){
return $this->getConfigString("server-name", "Unknown server");
return $this->getConfigString("motd", "Unknown server");
}
/**
@ -1584,7 +1584,7 @@ class Server{
Generator::addGenerator(Normal::class, "default");
//Temporal workaround, pthreads static property nullification test
if(PluginManager::$pluginParentTimer === null){
if(PluginManager::$pluginParentTimer === null or Timings::$serverTickTimer === null){
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
kill(getmypid());
return;

View File

@ -167,7 +167,8 @@ abstract class Block extends Position implements Metadatable{
const MELON_BLOCK = 103;
const PUMPKIN_STEM = 104;
const MELON_STEM = 105;
const VINE = 106;
const VINES = 106;
const FENCE_GATE = 107;
const BRICK_STAIRS = 108;
const STONE_BRICK_STAIRS = 109;
@ -345,7 +346,7 @@ abstract class Block extends Position implements Metadatable{
[Item::SNOW_LAYER, 0],
[Item::GLASS, 0],
[Item::GLOWSTONE_BLOCK, 0],
//TODO: Vines
[Item::VINES, 0],
[Item::NETHER_REACTOR, 0],
[Item::LADDER, 0],
[Item::SPONGE, 0],
@ -621,7 +622,7 @@ abstract class Block extends Position implements Metadatable{
self::MELON_BLOCK => Melon::class,
self::PUMPKIN_STEM => PumpkinStem::class,
self::MELON_STEM => MelonStem::class,
self::VINE => Vine::class,
self::FENCE_GATE => FenceGate::class,
self::BRICK_STAIRS => BrickStairs::class,
self::STONE_BRICK_STAIRS => StoneBrickStairs::class,
@ -686,7 +687,10 @@ abstract class Block extends Position implements Metadatable{
}
if($pos instanceof Position){
$block->position($pos);
$block->x = $pos->x;
$block->y = $pos->y;
$block->z = $pos->z;
$block->level = $pos->level;
}
return $block;

View File

@ -51,7 +51,6 @@ abstract class Fallable extends Solid{
new Double("", $this->y + 0.5),
new Double("", $this->z + 0.5)
]),
//TODO: add random motion with physics
"Motion" => new Enum("Motion", [
new Double("", 0),
new Double("", 0),

View File

@ -21,8 +21,16 @@
namespace pocketmine\block;
use pocketmine\entity\PrimedTNT;
use pocketmine\item\Item;
use pocketmine\level\Explosion;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Float;
use pocketmine\Player;
use pocketmine\utils\Random;
class TNT extends Solid{
public function __construct(){
@ -33,9 +41,8 @@ class TNT extends Solid{
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::FLINT_STEEL){
if(($player->gamemode & 0x01) === 0){
$item->useOn($this);
}
$item->useOn($this);
$data = [
"x" => $this->x + 0.5,
"y" => $this->y + 0.5,
@ -44,9 +51,27 @@ class TNT extends Solid{
"fuse" => 20 * 4, //4 seconds
];
$this->getLevel()->setBlock($this, new Air(), false, false, true);
//TODO
//$e = Server::getInstance()->api->entity->add($this->level, ENTITY_OBJECT, OBJECT_PRIMEDTNT, $data);
//$e->spawnToAll();
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = new PrimedTNT($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [
new Double("", $this->x + 0.5),
new Double("", $this->y + 0.5),
new Double("", $this->z + 0.5)
]),
"Motion" => new Enum("Motion", [
new Double("", -sin($mot) * 0.02),
new Double("", 0.2),
new Double("", -cos($mot) * 0.02)
]),
"Rotation" => new Enum("Rotation", [
new Float("", 0),
new Float("", 0)
]),
"Fuse" => new Byte("Fuse", 80)
]));
$tnt->spawnToAll();
return true;
}

View File

@ -0,0 +1,168 @@
<?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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\Player;
use pocketmine\entity\Entity;
class Vine extends Transparent{
public function __construct($meta = 0){
parent::__construct(self::VINE, $meta, "Vines");
$this->isSolid = false;
$this->isFullBlock = false;
$this->hardness = 1;
}
public function onEntityCollide(Entity $entity){
$entity->fallDistance = 0;
}
public function getBoundingBox(){
$f1 = 1;
$f2 = 1;
$f3 = 1;
$f4 = 0;
$f5 = 0;
$f6 = 0;
$flag = $this->meta > 0;
if(($this->meta & 0x02) > 0){
$f4 = max($f4, 0.0625);
$f1 = 0;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$flag = true;
}
if(($this->meta & 0x08) > 0){
$f1 = min($f1, 0.9375);
$f4 = 1;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$flag = true;
}
if(($this->meta & 0x01) > 0){
$f3 = min($f3, 0.9375);
$f6 = 1;
$f1 = 0;
$f4 = 1;
$f2 = 0;
$f5 = 1;
$flag = true;
}
if(!$flag and $this->getSide(1)->isSolid){
$f2 = min($f2, 0.9375);
$f5 = 1;
$f1 = 0;
$f4 = 1;
$f3 = 0;
$f6 = 1;
}
return new AxisAlignedBB(
$this->x + $f1,
$this->y + $f2,
$this->z + $f3,
$this->x + $f4,
$this->y + $f5,
$this->z + $f6
);
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
if($target->isSolid){
$faces = [
0 => 0,
1 => 0,
2 => 1,
3 => 4,
4 => 8,
5 => 2,
];
if(isset($faces[$face])){
$this->meta = $faces[$face];
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
}
return false;
}
public function getBreakTime(Item $item){
if($item->isShears()){
return 0.02;
}elseif($item->isSword()){
return 0.2;
}elseif($item->isAxe()){
switch($item->isAxe()){
case Tool::TIER_WOODEN:
return 0.15;
case Tool::TIER_STONE:
return 0.075;
case Tool::TIER_IRON:
return 0.05;
case Tool::TIER_DIAMOND:
return 0.0375;
case Tool::TIER_GOLD:
return 0.025;
}
}
return 0.3;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
/*if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
Server::getInstance()->api->entity->drop($this, Item::get(LADDER, 0, 1));
$this->getLevel()->setBlock($this, new Air(), true, true, true);
return Level::BLOCK_UPDATE_NORMAL;
}*/
}
return false;
}
public function getDrops(Item $item){
if($item->isShears()){
return [
[$this->id, 0, 1],
];
}else{
return [];
}
}
}

View File

@ -97,6 +97,8 @@ class DroppedItem extends Entity{
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
$this->updateMovement();
if($this->onGround){
$this->motionY *= -0.5;
}
@ -105,7 +107,6 @@ class DroppedItem extends Entity{
$this->kill();
}
$this->updateMovement();
}
$this->timings->stopTiming();

View File

@ -281,10 +281,10 @@ abstract class Entity extends Position implements Metadatable{
foreach($player as $p){
if($p === $this){
/** @var Player $p */
$pk = new SetEntityDataPacket();
$pk->eid = 0;
$pk->metadata = $this->getData();
$p->dataPacket($pk);
$pk2 = new SetEntityDataPacket();
$pk2->eid = 0;
$pk2->metadata = $this->getData();
$p->dataPacket($pk2);
}else{
$p->dataPacket($pk);
}
@ -585,7 +585,7 @@ abstract class Entity extends Position implements Metadatable{
}
public function onUpdate(){
if($this->closed !== false){
if($this->closed){
return false;
}
$this->timings->startTiming();
@ -1171,6 +1171,9 @@ abstract class Entity extends Position implements Metadatable{
$this->server->getPluginManager()->callEvent(new EntityDespawnEvent($this));
$this->closed = true;
unset($this->level->updateEntities[$this->id]);
if($this->chunk instanceof FullChunk){
$this->chunk->removeEntity($this);
}
if(($level = $this->getLevel()) instanceof Level){
$level->removeEntity($this);
}

View File

@ -24,4 +24,5 @@ namespace pocketmine\entity;
interface Explosive{
public function explode();
}

View File

@ -22,10 +22,124 @@
namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\level\Explosion;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player;
class PrimedTNT extends Entity implements Explosive{
const NETWORK_ID = 65;
public $width = 0.98;
public $length = 0.98;
public $height = 0.98;
protected $gravity = 0.04;
protected $drag = 0.02;
protected $fuse;
public $canCollide = false;
protected function initEntity(){
$this->namedtag->id = new String("id", "PrimedTNT");
if(isset($this->namedtag->Fuse)){
$this->fuse = $this->namedtag["Fuse"];
}else{
$this->fuse = 80;
}
}
public function canCollideWith(Entity $entity){
return false;
}
public function getData(){
return [
16 => ["type" => 0, "value" => $this->fuse],
];
}
public function saveNBT(){
parent::saveNBT();
$this->namedtag->Fuse = new Byte("Fuse", $this->fuse);
}
public function onUpdate(){
if($this->closed){
return false;
}
$this->timings->startTiming();
$this->entityBaseTick();
if(!$this->dead){
$this->motionY -= $this->gravity;
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
$this->motionX *= $friction;
$this->motionY *= $friction;
$this->motionZ *= $friction;
$this->updateMovement();
if($this->onGround){
$this->motionY *= -0.5;
$this->motionX *= 0.7;
$this->motionZ *= 0.7;
}
if($this->fuse-- <= 0){
$this->kill();
$this->explode();
}else{
$this->sendMetadata($this->getViewers());
}
}
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
}
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
}
public function heal($amount){
}
public function explode(){
(new Explosion($this, 4, $this))->explode();
}
public function spawnTo(Player $player){
$pk = new AddEntityPacket();
$pk->type = PrimedTNT::NETWORK_ID;
$pk->eid = $this->getID();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->did = 0;
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket();
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
$player->dataPacket($pk);
parent::spawnTo($player);
}
}

View File

@ -0,0 +1,222 @@
<?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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\event\server;
use pocketmine\event;
use pocketmine\Server;
use pocketmine\utils\Binary;
class QueryRegenerateEvent extends ServerEvent{
public static $handlerList = null;
const GAME_ID = "MINECRAFTPE";
private $timeout;
private $serverName;
private $listPlugins;
/** @var \pocketmine\plugin\Plugin[] */
private $plugins;
/** @var \pocketmine\Player[] */
private $players;
private $gametype;
private $version;
private $server_engine;
private $map;
private $numPlayers;
private $maxPlayers;
private $whitelist;
private $port;
private $ip;
private $extraData = [];
public function __construct(Server $server, $timeout = 5){
$this->timeout = $timeout;
$this->serverName = $server->getServerName();
$this->listPlugins = $server->getProperty("settings.query-plugins", true);
$this->plugins = $server->getPluginManager()->getPlugins();
$this->players = [];
foreach($server->getOnlinePlayers() as $player){
if($player->getName() != "" and $player->isConnected()){
$this->players[] = $player;
}
}
$this->gametype = ($server->getGamemode() & 0x01) === 0 ? "SMP" : "CMP";
$this->version = $server->getVersion();
$this->server_engine = $server->getName() ." ". $server->getPocketMineVersion();
$this->map = $server->getDefaultLevel() === null ? "unknown" : $server->getDefaultLevel()->getName();
$this->numPlayers = count($this->players);
$this->maxPlayers = $server->getMaxPlayers();
$this->whitelist = $server->hasWhitelist() ? "on" : "off";
$this->port = $server->getPort();
$this->ip = $server->getIp();
}
/**
* Gets the min. timeout for Query Regeneration
*
* @return int
*/
public function getTimeout(){
return $this->timeout;
}
public function setTimeout($timeout){
$this->timeout = $timeout;
}
public function getServerName(){
return $this->serverName;
}
public function setServerName($serverName){
$this->serverName = $serverName;
}
public function canListPlugins(){
return $this->listPlugins;
}
public function setListPlugins($value){
$this->listPlugins = (bool) $value;
}
/**
* @return \pocketmine\plugin\Plugin[]
*/
public function getPlugins(){
return $this->plugins;
}
/**
* @param \pocketmine\plugin\Plugin[] $plugins
*/
public function setPlugins(array $plugins){
$this->plugins = $plugins;
}
/**
* @return \pocketmine\Player[]
*/
public function getPlayerList(){
return $this->players;
}
/**
* @param \pocketmine\Player[] $players
*/
public function setPlayerList(array $players){
$this->players = $players;
}
public function getPlayerCount(){
return $this->numPlayers;
}
public function setPlayerCount($count){
$this->numPlayers = (int) $count;
}
public function getMaxPlayerCount(){
return $this->maxPlayers;
}
public function setMaxPlayerCount($count){
$this->maxPlayers = (int) $count;
}
public function getWorld(){
return $this->map;
}
public function setWorld($world){
$this->map = (string) $world;
}
/**
* Returns the extra Query data in key => value form
*
* @return array
*/
public function getExtraData(){
return $this->extraData;
}
public function setExtraData(array $extraData){
$this->extraData = $extraData;
}
public function getLongQuery(){
$query = "";
$plist = $this->server_engine;
if(count($this->plugins) > 0 and $this->listPlugins){
$plist .= ":";
foreach($this->plugins as $p){
$d = $p->getDescription();
$plist .= " " . str_replace([";", ":", " "], ["", "", "_"], $d->getName()) . " " . str_replace([";", ":", " "], ["", "", "_"], $d->getVersion()) . ";";
}
$plist = substr($plist, 0, -1);
}
$KVdata = [
"splitnum" => chr(128),
"hostname" => $this->serverName,
"gametype" => $this->gametype,
"game_id" => self::GAME_ID,
"version" => $this->version,
"server_engine" => $this->server_engine,
"plugins" => $plist,
"map" => $this->map,
"numplayers" => $this->numPlayers,
"maxplayers" => $this->maxPlayers,
"whitelist" => $this->whitelist,
"hostip" => $this->ip,
"hostport" => $this->port
];
foreach($KVdata as $key => $value){
$query .= $key . "\x00" . $value . "\x00";
}
foreach($this->extraData as $key => $value){
$query .= $key . "\x00" . $value . "\x00";
}
$query .= "\x00\x01player_\x00\x00";
foreach($this->players as $player){
$query .= $player->getName() . "\x00";
}
$query .= "\x00";
return $query;
}
public function getShortQuery(){
return $this->serverName . "\x00" . $this->gametype . "\x00" . $this->map . "\x00" . $this->numPlayers . "\x00" . $this->maxPlayers . "\x00" . Binary::writeLShort($this->port) . $this->ip . "\x00";
}
}

View File

@ -27,4 +27,8 @@ class DiamondAxe extends Tool{
parent::__construct(self::DIAMOND_AXE, $meta, $count, "Diamond Axe");
}
public function isAxe(){
return Tool::TIER_DIAMOND;
}
}

View File

@ -27,4 +27,7 @@ class DiamondHoe extends Tool{
parent::__construct(self::DIAMOND_HOE, $meta, $count, "Diamond Hoe");
}
public function isHoe(){
return Tool::TIER_DIAMOND;
}
}

View File

@ -27,4 +27,7 @@ class DiamondPickaxe extends Tool{
parent::__construct(self::DIAMOND_PICKAXE, $meta, $count, "Diamond Pickaxe");
}
public function isPickaxe(){
return Tool::TIER_DIAMOND;
}
}

View File

@ -27,4 +27,7 @@ class DiamondShovel extends Tool{
parent::__construct(self::DIAMOND_SHOVEL, $meta, $count, "Diamond Shovel");
}
public function isShovel(){
return Tool::TIER_DIAMOND;
}
}

View File

@ -27,4 +27,7 @@ class DiamondSword extends Tool{
parent::__construct(self::DIAMOND_SWORD, $meta, $count, "Diamond Sword");
}
public function isSword(){
return Tool::TIER_DIAMOND;
}
}

View File

@ -27,4 +27,7 @@ class GoldAxe extends Tool{
parent::__construct(self::GOLD_AXE, $meta, $count, "Gold Axe");
}
public function isAxe(){
return Tool::TIER_GOLD;
}
}

View File

@ -27,4 +27,7 @@ class GoldHoe extends Tool{
parent::__construct(self::GOLD_HOE, $meta, $count, "Gold Hoe");
}
public function isHoe(){
return Tool::TIER_GOLD;
}
}

View File

@ -27,4 +27,7 @@ class GoldPickaxe extends Tool{
parent::__construct(self::GOLD_PICKAXE, $meta, $count, "Gold Pickaxe");
}
public function isPickaxe(){
return Tool::TIER_GOLD;
}
}

View File

@ -27,4 +27,7 @@ class GoldShovel extends Tool{
parent::__construct(self::GOLD_SHOVEL, $meta, $count, "Gold Shovel");
}
public function isShovel(){
return Tool::TIER_GOLD;
}
}

View File

@ -27,4 +27,7 @@ class GoldSword extends Tool{
parent::__construct(self::GOLD_SWORD, $meta, $count, "Gold Sword");
}
public function isSword(){
return Tool::TIER_GOLD;
}
}

View File

@ -27,4 +27,7 @@ class IronAxe extends Tool{
parent::__construct(self::IRON_AXE, $meta, $count, "Iron Axe");
}
public function isAxe(){
return Tool::TIER_IRON;
}
}

View File

@ -27,4 +27,7 @@ class IronHoe extends Tool{
parent::__construct(self::IRON_HOE, $meta, $count, "Iron Hoe");
}
public function isHoe(){
return Tool::TIER_IRON;
}
}

View File

@ -27,4 +27,7 @@ class IronPickaxe extends Tool{
parent::__construct(self::IRON_PICKAXE, $meta, $count, "Iron Pickaxe");
}
public function isPickaxe(){
return Tool::TIER_IRON;
}
}

View File

@ -27,4 +27,7 @@ class IronShovel extends Tool{
parent::__construct(self::IRON_SHOVEL, $meta, $count, "Iron Shovel");
}
public function isShovel(){
return Tool::TIER_IRON;
}
}

View File

@ -27,4 +27,7 @@ class IronSword extends Tool{
parent::__construct(self::IRON_SWORD, $meta, $count, "Iron Sword");
}
public function isSword(){
return Tool::TIER_IRON;
}
}

View File

@ -159,7 +159,8 @@ class Item{
const MELON_BLOCK = 103;
const PUMPKIN_STEM = 104;
const MELON_STEM = 105;
const VINE = 106;
const VINES = 106;
const FENCE_GATE = 107;
const BRICK_STAIRS = 108;
const STONE_BRICK_STAIRS = 109;

View File

@ -27,4 +27,8 @@ class StoneAxe extends Tool{
parent::__construct(self::STONE_AXE, $meta, $count, "Stone Axe");
}
public function isAxe(){
return Tool::TIER_STONE;
}
}

View File

@ -27,4 +27,7 @@ class StoneHoe extends Tool{
parent::__construct(self::STONE_HOE, $meta, $count, "Stone Hoe");
}
public function isHoe(){
return Tool::TIER_STONE;
}
}

View File

@ -27,4 +27,7 @@ class StonePickaxe extends Tool{
parent::__construct(self::STONE_PICKAXE, $meta, $count, "Stone Pickaxe");
}
public function isPickaxe(){
return Tool::TIER_IRON;
}
}

View File

@ -27,4 +27,7 @@ class StoneShovel extends Tool{
parent::__construct(self::STONE_SHOVEL, $meta, $count, "Stone Shovel");
}
public function isShovel(){
return Tool::TIER_STONE;
}
}

View File

@ -27,4 +27,7 @@ class StoneSword extends Tool{
parent::__construct(self::STONE_SWORD, $meta, $count, "Stone Sword");
}
public function isSword(){
return Tool::TIER_STONE;
}
}

View File

@ -26,6 +26,11 @@ use pocketmine\block\Block;
use pocketmine\entity\Entity;
abstract class Tool extends Item{
const TIER_WOODEN = 1;
const TIER_GOLD = 2;
const TIER_STONE = 3;
const TIER_IRON = 4;
const TIER_DIAMOND = 5;
public function __construct($id, $meta = 0, $count = 1, $name = "Unknown"){
parent::__construct($id, $meta, $count, $name);
@ -87,84 +92,23 @@ abstract class Tool extends Item{
}
public function isPickaxe(){
switch($this->id){
case self::WOODEN_PICKAXE:
return 1;
case self::STONE_PICKAXE:
return 3;
case self::IRON_PICKAXE:
return 4;
case self::DIAMOND_PICKAXE:
return 5;
case self::GOLD_PICKAXE:
return 2;
default:
return false;
}
return false;
}
final public function isAxe(){
switch($this->id){
case self::IRON_AXE:
return 4;
case self::WOODEN_AXE:
return 1;
case self::STONE_AXE:
return 3;
case self::DIAMOND_AXE:
return 5;
case self::GOLD_AXE:
return 2;
default:
return false;
}
public function isAxe(){
return false;
}
final public function isSword(){
switch($this->id){
case self::IRON_SWORD:
return 4;
case self::WOODEN_SWORD:
return 1;
case self::STONE_SWORD:
return 3;
case self::DIAMOND_SWORD:
return 5;
case self::GOLD_SWORD:
return 2;
default:
return false;
}
public function isSword(){
return false;
}
final public function isShovel(){
switch($this->id){
case self::IRON_SHOVEL:
return 4;
case self::WOODEN_SHOVEL:
return 1;
case self::STONE_SHOVEL:
return 3;
case self::DIAMOND_SHOVEL:
return 5;
case self::GOLD_SHOVEL:
return 2;
default:
return false;
}
public function isShovel(){
return false;
}
public function isHoe(){
switch($this->id){
case self::IRON_HOE:
case self::WOODEN_HOE:
case self::STONE_HOE:
case self::DIAMOND_HOE:
case self::GOLD_HOE:
return true;
default:
return false;
}
return false;
}
public function isShears(){
@ -172,8 +116,6 @@ abstract class Tool extends Item{
}
public function isTool(){
return false;
return ($this->id === self::FLINT_STEEL or $this->id === self::SHEARS or $this->id === self::BOW or $this->isPickaxe() !== false or $this->isAxe() !== false or $this->isShovel() !== false or $this->isSword() !== false);
}
}

View File

@ -27,4 +27,7 @@ class WoodenAxe extends Tool{
parent::__construct(self::WOODEN_AXE, $meta, $count, "Wooden Axe");
}
public function isAxe(){
return Tool::TIER_WOODEN;
}
}

View File

@ -27,4 +27,7 @@ class WoodenHoe extends Tool{
parent::__construct(self::WOODEN_HOE, $meta, $count, "Wooden Hoe");
}
public function isHoe(){
return Tool::TIER_WOODEN;
}
}

View File

@ -27,4 +27,7 @@ class WoodenPickaxe extends Tool{
parent::__construct(self::WOODEN_PICKAXE, $meta, $count, "Wooden Pickaxe");
}
public function isPickaxe(){
return Tool::TIER_WOODEN;
}
}

View File

@ -27,4 +27,7 @@ class WoodenShovel extends Tool{
parent::__construct(self::WOODEN_SHOVEL, $meta, $count, "Wooden Shovel");
}
public function isShovel(){
return Tool::TIER_WOODEN;
}
}

View File

@ -27,4 +27,7 @@ class WoodenSword extends Tool{
parent::__construct(self::WOODEN_SWORD, $meta, $count, "Wooden Sword");
}
public function isSword(){
return Tool::TIER_WOODEN;
}
}

View File

@ -24,20 +24,24 @@ namespace pocketmine\level;
use pocketmine\block\Block;
use pocketmine\block\TNT;
use pocketmine\entity\Entity;
use pocketmine\entity\PrimedTNT;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityExplodeEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Math;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Float;
use pocketmine\network\protocol\ExplodePacket;
use pocketmine\Server;
use pocketmine\utils\Random;
class Explosion{
public static $specialDrops = [
Item::GRASS => Item::DIRT,
Item::STONE => Item::COBBLESTONE,
Item::COAL_ORE => Item::COAL,
Item::DIAMOND_ORE => Item::DIAMOND,
Item::REDSTONE_ORE => Item::REDSTONE,
];
private $rays = 16; //Rays
public $level;
public $source;
@ -47,6 +51,7 @@ class Explosion{
*/
public $affectedBlocks = [];
public $stepLen = 0.3;
/** @var Entity|Block|Tile */
private $what;
public function __construct(Position $center, $size, $what = null){
@ -56,6 +61,9 @@ class Explosion{
$this->what = $what;
}
/**
* @return bool
*/
public function explode(){
if($this->size < 0.1){
return false;
@ -64,6 +72,7 @@ class Explosion{
$mRays = $this->rays - 1;
for($i = 0; $i < $this->rays; ++$i){
for($j = 0; $j < $this->rays; ++$j){
//break 2 gets here
for($k = 0; $k < $this->rays; ++$k){
if($i == 0 or $i == $mRays or $j == 0 or $j == $mRays or $k == 0 or $k == $mRays){
$vector = new Vector3($i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1); //($i / $mRays) * 2 - 1
@ -72,6 +81,9 @@ class Explosion{
for($blastForce = $this->size * (mt_rand(700, 1300) / 1000); $blastForce > 0; $blastForce -= $this->stepLen * 0.75){
$vBlock = $pointer->floor();
if($vBlock->y < 0 or $vBlock->y > 127){
break;
}
$blockID = $this->level->getBlockIdAt($vBlock->x, $vBlock->y, $vBlock->z);
if($blockID > 0){
@ -96,11 +108,10 @@ class Explosion{
$send = [];
$source = $this->source->floor();
$radius = 2 * $this->size;
$yield = (1 / $this->size) * 100;
if($this->what instanceof Entity){
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityExplodeEvent($this->what, $this->source, $this->affectedBlocks, $yield));
$this->level->getServer()->getPluginManager()->callEvent($ev = new EntityExplodeEvent($this->what, $this->source, $this->affectedBlocks, $yield));
if($ev->isCancelled()){
return false;
}else{
@ -109,33 +120,66 @@ class Explosion{
}
}
//TODO
/*foreach($server->api->entity->getRadius($this->source, $radius) as $entity){
$impact = (1 - $this->source->distance($entity) / $radius) * 0.5; //placeholder, 0.7 should be exposure
$damage = (int) (($impact * $impact + $impact) * 8 * $this->size + 1);
$entity->harm($damage, "explosion");
}*/
$explosionSize = $this->size * 2;
$minX = Math::floorFloat($this->source->x - $explosionSize - 1);
$maxX = Math::floorFloat($this->source->x + $explosionSize + 1);
$minY = Math::floorFloat($this->source->y - $explosionSize - 1);
$maxY = Math::floorFloat($this->source->y + $explosionSize + 1);
$minZ = Math::floorFloat($this->source->z - $explosionSize - 1);
$maxZ = Math::floorFloat($this->source->z + $explosionSize + 1);
$explosionBB = new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
$list = $this->level->getNearbyEntities($explosionBB, $this->what instanceof Entity ? $this->what : null);
foreach($list as $entity){
$distance = $entity->distance($this->source) / $explosionSize;
if($distance <= 1){
$motion = $entity->subtract($this->source)->normalize();
$impact = (1 - $distance) * ($exposure = 1);
$damage = (int) ((($impact * $impact + $impact) / 2) * 8 * $explosionSize + 1);
$this->level->getServer()->getPluginManager()->callEvent($ev = new EntityDamageEvent($entity, $this->what instanceof Entity ? EntityDamageEvent::CAUSE_ENTITY_EXPLOSION : EntityDamageEvent::CAUSE_BLOCK_EXPLOSION, $damage));
if(!$ev->isCancelled()){
$entity->attack($ev->getFinalDamage(), $ev);
$entity->setMotion($motion->multiply($impact));
}
}
}
$air = Item::get(Item::AIR);
foreach($this->affectedBlocks as $block){
$block->setDamage($this->level->getBlockDataAt($block->x, $block->y, $block->z));
if($block instanceof TNT){
$data = [
"x" => $block->x + 0.5,
"y" => $block->y + 0.5,
"z" => $block->z + 0.5,
"power" => 4,
"fuse" => mt_rand(10, 30), //0.5 to 1.5 seconds
];
//TODO
//$e = $server->api->entity->add($this->level, ENTITY_OBJECT, OBJECT_PRIMEDTNT, $data);
//$e->spawnToAll();
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = new PrimedTNT($this->level->getChunk($block->x >> 4, $block->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [
new Double("", $block->x + 0.5),
new Double("", $block->y + 0.5),
new Double("", $block->z + 0.5)
]),
"Motion" => new Enum("Motion", [
new Double("", -sin($mot) * 0.02),
new Double("", 0.2),
new Double("", -cos($mot) * 0.02)
]),
"Rotation" => new Enum("Rotation", [
new Float("", 0),
new Float("", 0)
]),
"Fuse" => new Byte("Fuse", mt_rand(10, 30))
]));
$tnt->spawnToAll();
}elseif(mt_rand(0, 100) < $yield){
if(isset(self::$specialDrops[$block->getID()])){
//TODO
//$server->api->entity->drop(new Position($block->x + 0.5, $block->y, $block->z + 0.5, $this->level), Item::get(self::$specialDrops[$block->getID()], 0));
}else{
//TODO
//$server->api->entity->drop(new Position($block->x + 0.5, $block->y, $block->z + 0.5, $this->level), Item::get($block->getID(), $this->level->level->getBlockDamage($block->x, $block->y, $block->z)));
foreach($block->getDrops($air) as $drop){
$this->level->dropItem($block, Item::get(...$drop));
}
}
$this->level->setBlockIdAt($block->x, $block->y, $block->z, 0);
@ -147,7 +191,9 @@ class Explosion{
$pk->z = $this->source->z;
$pk->radius = $this->size;
$pk->records = $send;
Server::broadcastPacket($this->level->getPlayers(), $pk);
Server::broadcastPacket($this->level->getUsingChunk($source->x >> 4, $source->z >> 4), $pk);
return true;
}
}

View File

@ -883,7 +883,7 @@ class Level implements ChunkManager, Metadatable{
return $air;
}
return Block::get($blockId, $meta, Position::fromObject($pos, $this));
return Block::get($blockId, $meta, new Position($pos->x, $pos->y, $pos->z, $this));
}
/**
@ -1079,7 +1079,7 @@ class Level implements ChunkManager, Metadatable{
if(!($player instanceof Player) or ($player->getGamemode() & 0x01) === 0){
foreach($drops as $drop){
if($drop[2] > 0){
$this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get($drop[0], $drop[1], $drop[2]));
$this->dropItem($vector->add(0.5, 0.5, 0.5), Item::get(...$drop));
}
}
}

View File

@ -25,12 +25,13 @@
*/
namespace pocketmine\network\query;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\Server;
use pocketmine\utils\Binary;
use pocketmine\utils\Utils;
class QueryHandler{
private $server, $lastToken, $token, $longData, $timeout;
private $server, $lastToken, $token, $longData, $shortData, $timeout;
const HANDSHAKE = 9;
const STATISTICS = 0;
@ -57,43 +58,10 @@ class QueryHandler{
}
public function regenerateInfo(){
$str = "";
$plist = $this->server->getName() . " " . $this->server->getPocketMineVersion();
$pl = $this->server->getPluginManager()->getPlugins();
if(count($pl) > 0 and $this->server->getProperty("settings.query-plugins", true) === true){
$plist .= ":";
foreach($pl as $p){
$d = $p->getDescription();
$plist .= " " . str_replace([";", ":", " "], ["", "", "_"], $d->getName()) . " " . str_replace([";", ":", " "], ["", "", "_"], $d->getVersion()) . ";";
}
$plist = substr($plist, 0, -1);
}
$KVdata = [
"splitnum" => chr(128),
"hostname" => $this->server->getServerName(),
"gametype" => ($this->server->getGamemode() & 0x01) === 0 ? "SMP" : "CMP",
"game_id" => "MINECRAFTPE",
"version" => $this->server->getVersion(),
"server_engine" => $this->server->getName() . " " . $this->server->getPocketMineVersion(),
"plugins" => $plist,
"map" => $this->server->getDefaultLevel() === null ? "unknown" : $this->server->getDefaultLevel()->getName(),
"numplayers" => count($this->server->getOnlinePlayers()),
"maxplayers" => $this->server->getMaxPlayers(),
"whitelist" => $this->server->hasWhitelist() === true ? "on" : "off",
"hostport" => $this->server->getPort()
];
foreach($KVdata as $key => $value){
$str .= $key . "\x00" . $value . "\x00";
}
$str .= "\x00\x01player_\x00\x00";
foreach($this->server->getOnlinePlayers() as $player){
if($player->getName() != ""){
$str .= $player->getName() . "\x00";
}
}
$str .= "\x00";
$this->longData = $str;
$this->timeout = microtime(true) + 5;
$this->server->getPluginManager()->callEvent($ev = new QueryRegenerateEvent($this->server, 5));
$this->longData = $ev->getLongQuery();
$this->shortData = $ev->getShortQuery();
$this->timeout = microtime(true) + $ev->getTimeout();
}
public function regenerateToken(){
@ -127,13 +95,15 @@ class QueryHandler{
}
$reply = chr(self::STATISTICS);
$reply .= Binary::writeInt($sessionID);
if($this->timeout < microtime(true)){
$this->regenerateInfo();
}
if(strlen($payload) === 8){
if($this->timeout < microtime(true)){
$this->regenerateInfo();
}
$reply .= $this->longData;
}else{
$reply .= $this->server->getServerName() . "\x00" . (($this->server->getGamemode() & 0x01) === 0 ? "SMP" : "CMP") . "\x00" . ($this->server->getDefaultLevel() === null ? "unknown" : $this->server->getDefaultLevel()->getName()) . "\x00" . count($this->server->getOnlinePlayers()) . "\x00" . $this->server->getMaxPlayers() . "\x00" . Binary::writeLShort($this->server->getPort()) . $this->server->getIp() . "\x00";
$reply .= $this->shortData;
}
$this->server->sendPacket($address, $port, $reply);
break;

View File

@ -641,10 +641,6 @@ class PluginManager{
* @param Event $event
*/
public function callEvent(Event $event){
$this->fireEvent($event);
}
private function fireEvent(Event $event){
$handlers = $event->getHandlers();
$listeners = $handlers->getRegisteredListeners();

View File

@ -58,7 +58,7 @@ abstract class Spawnable extends Tile{
return;
}
foreach($this->getLevel()->getPlayers() as $player){
foreach($this->getLevel()->getUsingChunk($this->chunk->getX(), $this->chunk->getZ()) as $player){
if($player->spawned === true){
$this->spawnTo($player);
}