
<?php
echo "PocketMine-MP plugin SimpleFill v1.0.3
This file has been generated using DevTools v1.14.2 at Mon, 15 Feb 2021 01:05:46 +0000
----------------
Name: SimpleFill
Version: 1.0.3
Main: rark\\simple_fill\\Main
Api: 3.6.0
Depend: 
Description: 
Authors: 
Website: 
CreationDate: 1613351146
";
__HALT_COMPILER(); ?>
                a:9:{s:4:"name";s:10:"SimpleFill";s:7:"version";s:5:"1.0.3";s:4:"main";s:21:"rark\simple_fill\Main";s:3:"api";s:5:"3.6.0";s:6:"depend";s:0:"";s:11:"description";s:0:"";s:7:"authors";s:0:"";s:7:"website";s:0:"";s:12:"creationDate";i:1613351146;}
   plugin.yml  )`  H#~      5   src/rark/simple_fill/listener/PlayerEventListener.php  )`  @a      4   src/rark/simple_fill/listener/BlockEventListener.php  )`  ްԤ      )   src/rark/simple_fill/form/WarningForm.php  )`  ?6      ,   src/rark/simple_fill/command/FillCommand.php  )`  [ e      ,   src/rark/simple_fill/command/UndoCommand.php  )`  =L2      #   src/rark/simple_fill/utils/Undo.php  )`  \      #   src/rark/simple_fill/utils/Fill.php  )`  )Q7      $   src/rark/simple_fill/utils/sound.php	  )`	  Z      &   src/rark/simple_fill/utils/sortPos.php  )`  3U      (   src/rark/simple_fill/utils/in_region.php  )`  5z         src/rark/simple_fill/Main.phpS  )`S  J      name : SimpleFill
version : 1.0.3
api : 3.6.0

main : rark\simple_fill\Main
author : Rark

#<UpDdate Log>
#
#[1.0.0]
#リリース
#
#
#[1.0.1]
#無駄なコードの削除
#
#
#[1.0.2]
#pharアーカイブだと動作しない問題を修正
#
#
#[1.0.3]
#警告フォームが表示された場合の処理で、
#Undoのデータに正しく保存されない問題を修正
#
#PMMPサーバー上でPCプラットフォームでプレイする際に発生する
#右クリック判定が連続で発生する問題の対処のため
#アイテムをもってスニークで使用する方法を追加
#
#Undoのデータ保存量をユーザ側で設定できるように変更<?php

declare(strict_types = 1);

namespace rark\simple_fill\listener;

use pocketmine\Player;
use pocketmine\item\Item;
use pocketmine\event\Listener;
use pocketmine\event\player\{
	PlayerQuitEvent,
	PlayerInteractEvent,
	PlayerDropItemEvent,
	PlayerToggleSneakEvent
};
use rark\simple_fill\Main;
use rark\simple_fill\utils\Fill;
use function rark\simple_fill\utils\sound;


final class PlayerEventListener implements Listener{
	/** @var Closure  */
	private $use_fill_item;

	public function __construct(){
		$this->use_fill_item = function(Player $player, Item $item):void{
			if($item->getCustomName() !== Main::$item->getCustomName() or !$player->isOp()){
				return;
			}

			if(Main::$fill->isRegisteredPlayer($player)){
				sound($player);
				Main::$fill->unregisterPlayer($player);
				$player->sendMessage(Main::HEADER.'§bFillモードをOFFにしました');

			}else{
				sound($player);
				Main::$fill->registerPlayer($player);
				$player->sendMessage(Main::HEADER.'§aFillモードをONにしました');
			}
		};
	}

	public function onQuit(PlayerQuitEvent $event):void{
		Main::$fill->unregisterPlayer($event->getPlayer());
	}

	public function onSneak(PlayerToggleSneakEvent $event):void{
		if(!Main::$config->get('UseType')['Sneak'] or !$event->isSneaking()){
			return;
		}
		$player = $event->getPlayer();
		$item = $player->getInventory()->getItemInHand();
		($this->use_fill_item)($player, $item);
	}

	public function onInteract(PlayerInteractEvent $event):void{
		if(!Main::$config->get('UseType')['Tap']){
			return;
		}
		$player = $event->getPlayer();
		$item = $event->getItem();
		($this->use_fill_item)($player, $item);
	}

	public function onDrop(PlayerDropItemEvent $event):void{
		$item = $event->getItem();

		if($item->getCustomName() === Main::$item->getCustomName()){
			$event->getPlayer()->getInventory()->removeItem($item);
			$event->setCancelled();
		}
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\listener;

use pocketmine\event\Listener;
use pocketmine\Player;
use pocketmine\block\Block;
use pocketmine\event\block\{
	BlockBreakEvent,
	BlockPlaceEvent
};
use pocketmine\scheduler\Task;
use pocketmine\math\Vector3;
use rark\simple_fill\Main;
use rark\simple_fill\utils\Fill;
use function rark\simple_fill\utils\sound;


final class BlockEventListener implements Listener{

	public function onBreak(BlockBreakEvent $event):void{

		if($event->getItem()->getCustomName() === Main::$item->getCustomName()){
			$event->setCancelled();
		}
	}

	public function onPlace(BlockPlaceEvent $event):void{
		$player = $event->getPlayer();

		if(!Main::$fill->isRegisteredPlayer($player)){
			return;
		}

		$before = $event->getBlockReplaced();
		$name = $player->getName();
		sound($player);

		if(is_bool(Main::$fill->data[$name]['pos1'])){
			$player->sendMessage(Main::HEADER.'§a起点をセット');
			Main::$fill->data[$name]['pos1'] = $before;

		}else{
			Main::$fill->data[$name]['pos2'] = $before;
			$player->sendMessage(Main::HEADER.'§aFill!');
			Main::$instance->getScheduler()->scheduleDelayedTask(new Class($player, $event->getBlock()) extends Task{
					/** @var Player */
					private $player;
					/** @var Vector3 */
					private $v;

					public function __construct(Player $player, Vector3 $v){
						$this->player = $player;
						$this->v = $v;
					}

					public function onRun(int $tick){
						$block = $this->player->getLevel()->getBlock($this->v);
						Main::$fill->do($this->player, $block);
					}
				},
				1
			);
		}
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\form;

use pocketmine\form\Form;
use pocketmine\Player;
use pocketmine\block\Block;
use pocketmine\level\Position;
use rark\simple_fill\Main;


final class WarningForm implements Form{
	/** @var array */
	private $blocks;
	/** @var array */
	private $tiles;
	/** @var Block */
	private $block;

	public function __construct(array $blocks, array $tiles, Block $block){
		$this->blocks = $blocks;
		$this->tiles = $tiles;
		$this->block = $block;
	}

	public function jsonSerialize(){
		return [
			'type' => 'modal',
			'title' => '§c警告',
			'content' => $this->getText(),
			'button1' => '続行',
			'button2' => '中止'
		];
	}

	public function handleResponse(Player $player, $data):void{
		if($data){
			Main::$fill->setBlocks($player, $this->blocks, $this->tiles, $this->block);

		}else{
			$player->sendMessage(Main::HEADER.'§c処理を中断しました');
			Main::$fill->registerPlayer($player);
		}
	}

	private function getText():string{
		return '現在実行しようとしているFillのブロック数は'.count($this->blocks).'です。'."\n".'Fillを続行しますか？';
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\command;

use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\command\{CommandSender, PluginCommand};
use rark\simple_fill\Main;
use function rark\simple_fill\utils\sound;


final class FillCommand extends PluginCommand{

	public function __construct(Plugin $plugin){
		parent::__construct('simplefill', $plugin);
		$this->setAliases(['sf']);
		$this->setDescription(Main::HEADER.'Fillモードを切り替えるアイテムを付与');
	}

	public function execute(CommandSender $sender, string $command, array $args){
		if(!$sender instanceof Player or !$sender->isOp()){
			$sender->sendMessage(Main::HEADER.'§c実行権限がありません');
			return;
		}
		$inventory = $sender->getInventory();

		if($inventory->canAddItem(Main::$item)){
			sound($sender);
			$inventory->addItem(Main::$item);
		}
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\command;

use pocketmine\command\{PluginCommand, CommandSender};
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use rark\simple_fill\Main;
use function rark\simple_fill\utils\sound;

final class UndoCommand extends PluginCommand{

	public function __construct(Plugin $plugin){
		parent::__construct('sfundo', $plugin);
		$this->setAliases(['su']);
		$this->setDescription(Main::HEADER.'操作を取り消す');
	}

	public function execute(CommandSender $sender, string $command, array $args){
		if(!$sender instanceof Player or !$sender->isOp()){
			$sender->sendMessage(Main::HEADER.'§c実行権限がありません');
			return;
		}
		$value = 1;

		if(isset($args[0])){
			$value = intval($args[0]);

			if($value <= 0){
				$sender->sendMessage(Main::HEADER.'§c不正な値です');
				return;
			}
		}
		sound($sender);
		Main::$undo->undo($sender, $value);
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\utils;

use pocketmine\Player;
use rark\simple_fill\Main;


final class Undo{
	/** @var array */
	public $data = [];

	public function reportFillData(Player $player, array $blocks, array $tiles){
		$name = $player->getName();
		$tiles_data = [];

		foreach($tiles as $tile){
			$tiles_data[] = [get_class($tile), $tile->saveNBT()];
			unset($tile);
		}
		$this->data[$name][] = [$player->getLevel(), $blocks, $tiles_data];

		if(count($this->data[$name]) > Main::$config->get('SaveQueue')){
			$this->data = array_slice($this->data, 1);
		}
	}

	public function undo(Player $player, int $value):void{
		$name = $player->getName();

		if(!isset($this->data[$name][0])){
			$player->sendMessage(Main::HEADER.'§c履歴がありません');
			return;
		}
		$log = array_reverse($this->data[$name]);

		/**
		 * @var Level $data[0]
		 * @var array $data[1]
		 * @var array $data[2]
		*/
		for($amount = 0; $value !== 0; --$value){
			++$amount;
			$data = $log[0];

			foreach($data[1] as $block){
				$data[0]->setBlock($block, clone $block);
			}

			foreach($data[2] as $tile_data){
				new $tile_data[0]($data[0], $tile_data[1]);
			}

			$this->data[$name] = array_slice($this->data[$name], 0, -1);

			if(!isset($this->data[$name][0])){
				unset($this->data[$name]);
				break;
			}
		}
		$player->sendMessage(Main::HEADER.'§a'.$amount.'回分操作を取り消しました');
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\utils;

use pocketmine\Player;
use pocketmine\block\Block;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use rark\simple_fill\Main;
use rark\simple_fill\form\WarningForm;


final class Fill{

	/** @var int*/
	private const ERROR_EXEPTION_BROKEN_DATA = 0;
	private const ERROR_HAS_NOT_PERMISSION = 1;
	private const ERROR_LEVEL_CLOSED = 2;
	private const ERROR_POS1_NOT_FOUND = 3;
	private const ERROR_POS2_NOT_FOUND = 4;
	private const NO_ERROR = 5;

	/** @var array */
	public $data = [];

	public function registerPlayer(Player $player){
		$this->data[$player->getName()] = [
			'pos1' => true,
			'pos2' => true
		];
	}

	public function isRegisteredPlayer(Player $player):bool{
		return isset($this->data[$player->getName()]);
	}

	public function unregisterPlayer(Player $player):void{
		if(!$this->isRegisteredPlayer($player)){
			return;
		}
		unset($this->data[$player->getName()]);
	}


	private function canDo(Player $player):int{
		$name = $player->getName();

		switch(false){
			case $this->isRegisteredPlayer($player):
				return self::ERROR_EXEPTION_BROKEN_DATA;
			break;

			case $player->isOP():
				return self::ERROR_HAS_NOT_PERMISSION;
			break;

			case $this->data[$name]['pos1'] instanceof Vector3:
				return self::ERROR_POS1_NOT_FOUND;
			break;

			case $this->data[$name]['pos2'] instanceof Vector3:
				return self::ERROR_POS2_NOT_FOUND;
			break;

			case $player->isValid():
				return self::ERROR_LEVEL_CLOSED;
			break;

			default:
				return self::NO_ERROR;
		}
	}

	public function do(Player $player, Block $block):void{
		$messages = [
			'§cFillのリクエストがキャンセルされました',
			'§cFillを実行する権限がありません',
			'§c何らかの原因でPos1のデータが破損したためFillを中止します',
			'§c何らかの原因でPos2のデータが破損したためFillを中止します',
			'§cワールドが存在しません'
		];
		$case = $this->canDo($player);

		if($case === self::NO_ERROR){
			$this->fill($player, $block);
			return;
		}
		$player->sendMessage(Main::HEADER.$messages[$case]);
	}

	private function fill(Player $player, Block $block):void{
		Main::$fill->getLevelData($player, $blocks, $tiles);

		if(count($blocks) >= 1000){
			$player->sendForm(new WarningForm($blocks, $tiles, $block));
			return;
		}
		$this->setBlocks($player, $blocks, $tiles, $block);
	}


	public function getLevelData(Player $player, &$blocks, &$tiles):void{
		$level = $player->getLevel();
		$pos1 = $this->data[$player->getName()]['pos1'];
		$pos2 = $this->data[$player->getName()]['pos2'];
		$pos1_clone = clone $pos1;
		$pos2_clone = clone $pos2;
		sortPos($pos1, $pos2);
		$blocks = [];
		$tiles = [];

		for($x = $pos2->x - $pos1->x; $x >= 0; --$x){
			for($y = $pos2->y - $pos1->y; $y >= 0; --$y){
				for($z = $pos2->z - $pos1->z; $z >= 0; --$z){
					$blocks[] = $level->getBlock($pos1->add($x, $y, $z));
				}
			}
		}
		$blocks[] = $pos1_clone;
		$blocks[] = $pos2_clone;

		foreach($level->getTiles() as $tile){
			if(in_region($tile, $pos1, $pos2)){
				$tiles[] = $tile;
			}
		}
	}

	public function setBlocks(Player $player, array $positions, array $tiles, Block $block):void{
		$level = $player->getLevel();

		foreach($positions as $pos){
			$level->setBlock($pos, $block);
		}
		Main::$undo->reportFillData($player, $positions, $tiles);
		$this->registerPlayer($player);
	}
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\utils;

use pocketmine\level\Position;


function sound(Position $pos):void{
	$level = $pos->getLevel();

	if(is_null($level)){
		return;
	}
	$level->broadcastLevelSoundEvent($pos, 81);
}<?php

declare(strict_types = 1);

namespace rark\simple_fill\utils;

use pocketmine\math\Vector3;


function sortPos(Vector3 &$pos1, Vector3 &$pos2):void{
	$x = [$pos1->x, $pos2->x];
	$y = [$pos1->y, $pos2->y];
	$z = [$pos1->z, $pos2->z];
	$pos1->x = min($x);
	$pos1->y = min($y);
	$pos1->z = min($z);
	$pos2->x = max($x);
	$pos2->y = max($y);
	$pos2->z = max($z);
}
<?php

declare(strict_types = 1);

namespace rark\simple_fill\utils;

use pocketmine\math\Vector3;

/**
 * sortPos関数を使用した状態でないと挙動が正確ではなくなります
 */
function in_region(Vector3 $v, Vector3 $pos1, Vector3 $pos2):bool{
	if($v->x >= $pos1->x and $v->x <= $pos2->x){
		if($v->y >= $pos1->y and $v->y <= $pos2->y){
			return $v->z >= $pos1->z and $v->z <= $pos2->z;
		}
	}
	return false;
}<?php

declare(strict_types = 1);

namespace rark\simple_fill;

use pocketmine\plugin\PluginBase;
use pocketmine\item\Item;
use pocketmine\event\Listener;
use pocketmine\utils\Config;
use rark\simple_fill\listener\{PlayerEventListener, BlockEventListener};
use rark\simple_fill\command\{FillCommand, UndoCommand};
use rark\simple_fill\utils\{Fill, Undo};


final class Main extends PluginBase{
	/** @var string */
	public const HEADER = '[SimpleFill]';
	/** @var self */
	public static $instance;
	/** @var Item */
	public static $item;
	/** @var Fill */
	public static $fill;
	/** @var Undo */
	public static $undo;
	/** @var Config */
	public static $config;

	public function onEnable(){
		$this->setObject();
		$this->createConfig();
		$this->registerListener();
		$this->registerCommand();
		$this->loadFile();
	}

	private function setObject():void{
		self::$instance = $this;
		self::$fill = new Fill;
		self::$undo = new Undo;
		$this->setItem();
	}

	private function createConfig():void{
		self::$config = new Config($this->getDataFolder().'Config.yaml', Config::YAML, [
			'UseType' => [
				'Sneak' => false,
				'Tap' => true
			],
			'SaveQueue' => 15
		]);
	}

	private function setItem():void{
		$item = Item::get(450);
		$item->setCustomName('§aSwitchFillMode');
		$item->setLore([
			'タップでON/OFF切り替え',
			'ON状態の時にブロックを',
			'二か所に設置で設置でFill'
		]);
		self::$item = $item;
	}

	private function registerListener():void{
		array_map(function(Listener $listener):void{
			$this->getServer()->getPluginManager()->registerEvents($listener, $this);
		}, [
			new PlayerEventListener,
			new BlockEventListener
		]);
	}

	private function registerCommand():void{
		$this->getServer()->getCommandMap()->registerAll('[Rark]SimpleFill', [
			new FillCommand($this),
			new UndoCommand($this)
		]);
	}

	private function loadFile():void{
		$path = __DIR__.'/utils/';
		require_once($path.'sound.php');
		require_once($path.'sortPos.php');
		require_once($path.'in_region.php');
	}
}n٣۽   GBMB