$blocksAfter
*/
public function __construct(int $worldId, array $chunks = [], array $blocksAfter = [])
{
$this->worldId = $worldId;
$this->chunks = $chunks;
$this->blocksAfter = $blocksAfter;
}
/**
* String representation of object
* @link http://php.net/manual/en/serializable.serialize.php
* @return string the string representation of the object or null
* @since 5.1.0
*/
public function serialize()
{
$chunks = [];
foreach ($this->chunks as $hash => $chunk) {
$chunks[$hash] = FastChunkSerializer::serialize($chunk);
}
return serialize([
$this->worldId,
$chunks,
$this->blocksAfter
]);
}
/**
* Constructs the object
* @link http://php.net/manual/en/serializable.unserialize.php
* @param string $serialized
* The string representation of the object.
*
* @return void
* @since 5.1.0
* @noinspection PhpMissingParamTypeInspection
*/
public function unserialize($serialized)
{
[
$this->worldId,
$chunks,
$this->blocksAfter
] = unserialize($serialized/*, ['allowed_classes' => [__CLASS__]]*/);//TODO test pm4
foreach ($chunks as $hash => $chunk)
$this->chunks[$hash] = FastChunkSerializer::deserialize($chunk);
}
}
================================================
FILE: src/xenialdan/MagicWE2/clipboard/SingleClipboard.php
================================================
position = $position->asVector3()->floor();
}
public function addEntry(int $x, int $y, int $z, BlockEntry $entry): void
{
$this->entries[World::blockHash($x, $y, $z)] = $entry;
}
public function clear(): void
{
$this->entries = [];
}
/**
* @param int|null $x
* @param int|null $y
* @param int|null $z
* @return Generator|BlockEntry[]
*/
public function iterateEntries(?int &$x, ?int &$y, ?int &$z): Generator
{
foreach ($this->entries as $hash => $entry) {
World::getBlockXYZ($hash, $x, $y, $z);
yield $entry;
}
}
public function getTotalCount(): int
{
return count($this->entries);
}
/**
* String representation of object
* @link https://php.net/manual/en/serializable.serialize.php
* @return string the string representation of the object or null
* @since 5.1
*/
public function serialize()
{
// TODO: Implement serialize() method.
return serialize([
$this->entries,
$this->selection,
$this->position
]);
}
/**
* Constructs the object
* @link https://php.net/manual/en/serializable.unserialize.php
* @param string $serialized
* The string representation of the object.
*
* @return void
* @since 5.1
* @noinspection PhpMissingParamTypeInspection
*/
public function unserialize($serialized)
{
// TODO: Implement unserialize() method.
[
$this->entries,
$this->selection,
$this->position
] = unserialize($serialized/*, ['allowed_classes' => [BlockEntry::class, Selection::class, Vector3::class]]*/);
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/DonateCommand.php
================================================
setPermission("we.command.donate");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$name = TF::DARK_PURPLE . "[" . TF::GOLD . "XenialDan" . TF::DARK_PURPLE . "] ";
$sender->sendMessage($name . "Greetings! Would you like to buy me an energy drink to stay awake during coding sessions?");
$sender->sendMessage($name . "Donations are welcomed! Consider donating on " . TF::DARK_AQUA . "Pay" . TF::AQUA . "Pal:");
$sender->sendMessage($name . TF::DARK_AQUA . "https://www.paypal.me/xenialdan");
$sender->sendMessage($name . "Thank you! With " . TF::BOLD . TF::RED . "<3" . TF::RESET . TF::DARK_PURPLE . " - MagicWE2 by https://github.com/thebigsmileXD");
$colorHeart = (random_int(0, 1) === 1 ? TF::DARK_RED : TF::DARK_PURPLE);
$sender->sendMessage(
TF::BOLD . $colorHeart . " **** **** " . TF::EOL .
TF::BOLD . $colorHeart . " ** ** ** ** " . TF::EOL .
TF::BOLD . $colorHeart . "** * **" . TF::EOL .
TF::BOLD . $colorHeart . " ** " . TF::GOLD . "MWE" . $colorHeart . " ** " . TF::EOL .
TF::BOLD . $colorHeart . " ** ** " . TF::EOL .
TF::BOLD . $colorHeart . " ** ** " . TF::EOL .
TF::BOLD . $colorHeart . " ** ** " . TF::EOL .
TF::BOLD . $colorHeart . " *** " . TF::EOL .
TF::BOLD . $colorHeart . " * "
);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/HelpCommand.php
================================================
registerArgument(0, new RawStringArgument("command", true));
$this->setPermission("we.command.help");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$cmds = [];
if (empty($args["command"])) {
foreach (array_filter(Loader::getInstance()->getServer()->getCommandMap()->getCommands(), static function (Command $command) use ($sender) {
return strpos($command->getName(), "/") !== false && $command->testPermissionSilent($sender);
}) as $cmd) {
/** @var Command $cmd */
$cmds[$cmd->getName()] = $cmd;
}
} else if (($cmd = Loader::getInstance()->getServer()->getCommandMap()->getCommand("/" . str_replace("/", "", TF::clean((string)$args["command"])))) instanceof Command) {
/** @var Command $cmd */
$cmds[$cmd->getName()] = $cmd;
} else {
$sender->sendMessage(TF::RED . str_replace("/", "//", $lang->translateString("%commands.generic.notFound")));
return;
}
foreach ($cmds as $command) {
$message = TF::LIGHT_PURPLE . "/" . $command->getName();
if (!empty(($aliases = $command->getAliases()))) {
foreach ($aliases as $i => $alias) {
$aliases[$i] = "/" . $alias;
}
$message .= TF::DARK_PURPLE . " [" . implode(",", $aliases) . "]";
}
$message .= TF::AQUA . " " . $command->getDescription() . TF::EOL . " - " . $command->getUsage();
$sender->sendMessage($message);
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/InfoCommand.php
================================================
setPermission("we.command.info");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$sender->sendMessage(rtrim(Loader::PREFIX, " ") . " " . $lang->translateString('command.info.title'));
foreach (Loader::getInfo() as $i => $line) {
if ($i <= 1) continue;
$sender->sendMessage($line);
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/LanguageCommand.php
================================================
registerArgument(0, new LanguageArgument("language", true));
$this->setPermission("we.command.language");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
if (isset($args["language"])) {
$session->setLanguage((string)$args["language"]);
return;
}
$languages = Loader::getInstance()->getLanguageList();
$form = new CustomForm(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $lang->translateString('ui.language.title'));
$form->addElement(new Label($lang->translateString('ui.language.label')));
$dropdown = new Dropdown($lang->translateString('ui.language.dropdown'), array_values($languages));
$dropdown->setOptionAsDefault($session->getLanguage()->getName());
$form->addElement($dropdown);
$form->setCallable(function (Player $player, $data) use ($session, $languages) {
$langShort = array_search($data[1], $languages, true);
if (!is_string($langShort)) throw new InvalidArgumentException("Invalid data received");
$session->setLanguage($langShort);
});
$sender->sendForm($form);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/LimitCommand.php
================================================
registerArgument(0, new IntegerArgument("limit", true));
$this->setPermission("we.command.limit");
$this->setUsage("//limit [limit: int|-1]");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
if (empty($args["limit"])) {
$limit = Loader::getInstance()->getConfig()->get("limit", -1);
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.limit.current', [($limit < 0 ? ucfirst(Loader::getInstance()->getLanguage()->translateString('disabled')) : $limit)]));
} else {
Loader::getInstance()->getConfig()->set("limit", (int)$args["limit"]);
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.limit.set', [(int)$args["limit"]]));
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/ReportCommand.php
================================================
registerArgument(0, new TextArgument("title", true));
$this->setPermission("we.command.report");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$url = "Please report your bug with this link (link also in console)" . TF::EOL;
$url .= "https://github.com/thebigsmileXD/MagicWE2/issues/new?labels=Bug&body=";
$url .= urlencode(
"### Description" . TF::EOL . "" .
TF::EOL .
TF::EOL . "" .
TF::EOL . "---" .
TF::EOL . TF::clean(implode(TF::EOL, Loader::getInfo())));
$url .= "&title=" . urlencode(TF::clean("[" . Loader::getInstance()->getDescription()->getVersion() . "] " . ((string)($args["title"] ?? ""))));
if (!$sender instanceof ConsoleCommandSender) $sender->sendMessage(Loader::PREFIX . $url);
Loader::getInstance()->getLogger()->alert($url);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/SetRangeCommand.php
================================================
registerArgument(0, new IntegerArgument("range", true));
$this->setPermission("we.command.setrange");
$this->setUsage("//setrange [range: int]");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
if (empty($args["range"])) {
$range = Loader::getInstance()->getToolDistance();
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.setrange.current', [$range]));
} else {
Loader::getInstance()->getConfig()->set("tool-range", (int)$args["range"]);
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.setrange.set', [(int)$args["range"]]));
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/TestCommand.php
================================================
setPermission("we.command.test");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
//TODO REMOVE DEBUG
$pluginSession = SessionHelper::createPluginSession(Loader::getInstance());
$selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 0, 0, 0);
$pluginSession->addSelection($selection);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$pluginSession->getUUID(),
$selection,
new TestAction(),
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"minecraft:snow_block",
"minecraft:tnt"
)
);
$selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 1, 1, 1);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$pluginSession->getUUID(),
$selection,
new TestAction(),
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"minecraft:snow_block",
"minecraft:tnt"
)
);
$selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 2, 2, 2);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$pluginSession->getUUID(),
$selection,
new TestAction(),
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"minecraft:snow_block",
"minecraft:tnt"
)
);
$selection = new Selection($pluginSession->getUUID(), Server::getInstance()->getWorldManager()->getDefaultWorld(), 0, 0, 0, 1, 2, 3);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$pluginSession->getUUID(),
$selection,
new TestAction(),
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"minecraft:snow_block",
"minecraft:tnt"
)
);
} catch (Exception $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/VersionCommand.php
================================================
setPermission("we.command.version");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$sender->sendMessage(Loader::PREFIX . TF::GREEN . Loader::getInstance()->getDescription()->getVersion());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/args/LanguageArgument.php
================================================
getLanguageList(), true);
}
public function getEnumValues(): array
{
return array_values(Loader::getInstance()->getLanguageList());
}
public function getEnumName(): string
{
return "language";
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/args/MirrorAxisArgument.php
================================================
"x", "z" => "z", "y" => "y", "xz" => "xz"];
public function getTypeName(): string
{
return "string";
}
public function getEnumName(): string
{
return "axis";
}
/**
* @param string $argument
* @param CommandSender $sender
* @return string //TODO consider changing to Axis
*/
public function parse(string $argument, CommandSender $sender)
{
return (string)$this->getValue($argument);
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/args/RotateAngleArgument.php
================================================
90, "180" => 180, "270" => 270];
public function getTypeName(): string
{
return "int";
}
public function getEnumName(): string
{
return "angle";
}
/**
* @param string $argument
* @param CommandSender $sender
* @return int
*/
public function parse(string $argument, CommandSender $sender)
{
return (int)$this->getValue($argument);
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/biome/BiomeInfoCommand.php
================================================
registerArgument(0, new TextArgument("flags", true));
$this->setPermission("we.command.biome.info");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$biomeNames = (new ReflectionClass(Biome::class))->getConstants();
$biomeNames = array_flip($biomeNames);
unset($biomeNames[Biome::MAX_BIOMES]);
array_walk($biomeNames, static function (&$value, $key) {
$value = BiomeRegistry::getInstance()->getBiome($key)->getName();
});
if (!empty(($flags = ltrim((string)($args["flags"] ?? ""), "-")))) {
$flagArray = str_split($flags);
if (in_array(self::FLAG_T, $flagArray, true)) {
$target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance());
if ($target === null) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget'));
return;
}
$biomeId = $target->getPos()->getWorld()->getOrLoadChunkAtPosition($target->getPos())->getBiomeId($target->getPos()->getX() % 16, $target->getPos()->getZ() % 16);
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.biomeinfo.attarget'));
$session->sendMessage(TF::AQUA . "ID: $biomeId Name: " . $biomeNames[$biomeId]);
}
if (in_array(self::FLAG_P, $flagArray, true)) {
$biomeId = $sender->getWorld()->getOrLoadChunkAtPosition($sender->getPosition())->getBiomeId($sender->getPosition()->getX() % 16, $sender->getPosition()->getZ() % 16);
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.biomeinfo.atposition'));
$session->sendMessage(TF::AQUA . "ID: $biomeId Name: " . $biomeNames[$biomeId]);
}
return;
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$touchedChunks = $selection->getShape()->getTouchedChunks($selection->getWorld());
$biomes = [];
foreach ($touchedChunks as $touchedChunk) {
for ($x = 0; $x < 16; $x++)
for ($z = 0; $z < 16; $z++)
$biomes[] = (FastChunkSerializer::deserialize($touchedChunk)->getBiomeId($x, $z));
}
$biomes = array_unique($biomes);
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.biomeinfo.result', [count($biomes)]));
foreach ($biomes as $biomeId) {
$session->sendMessage(TF::AQUA . $lang->translateString('command.biomeinfo.result.line', [$biomeId, $biomeNames[$biomeId]]));
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/biome/BiomeListCommand.php
================================================
setPermission("we.command.biome.list");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
/** @var Player $sender */
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.biomelist.title'));
foreach ((new ReflectionClass(Biome::class))->getConstants() as $name => $value) {
if ($value === Biome::MAX_BIOMES) continue;
$name = BiomeRegistry::getInstance()->getBiome($value)->getName();
$session->sendMessage(TF::AQUA . $lang->translateString('command.biomelist.result.line', [$value, $name]));
}
} catch (SessionException $e) {
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/biome/SetBiomeCommand.php
================================================
registerArgument(0, new IntegerArgument("biome", false));//TODO add BiomeArgument
//TODO flags
$this->setPermission("we.command.biome.set");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$biomeId = (int)$args["biome"];
API::setBiomeAsync($selection, $session, $biomeId);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/brush/BrushCommand.php
================================================
registerSubCommand(new BrushNameCommand("name", "Get name or rename a brush"));
$this->setPermission("we.command.brush");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$form = new SimpleForm(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $lang->translateString('ui.brush.title'), $lang->translateString('ui.brush.content'));
$form->addButton(new Button($lang->translateString('ui.brush.create')));
$form->addButton(new Button($lang->translateString('ui.brush.getsession')));
$form->addButton(new Button($lang->translateString('ui.brush.edithand')));
$form->setCallable(function (Player $player, $data) use ($lang, $session) {
try {
switch ($data) {
case $lang->translateString('ui.brush.create'):
{
$brush = new Brush(new BrushProperties());
if ($brush instanceof Brush) {
$player->sendForm($brush->getForm());
}
break;
}
case $lang->translateString('ui.brush.getsession'):
{
$menu = InvMenu::create(InvMenu::TYPE_DOUBLE_CHEST);
foreach ($session->getBrushes() as $brush) {
$menu->getInventory()->addItem($brush->toItem());
}
$menu->send($player, "Session brushes");
break;
}
case $lang->translateString('ui.brush.edithand'):
{
$brush = $session->getBrushFromItem($player->getInventory()->getItemInHand());
if ($brush instanceof Brush) {
$player->sendForm($brush->getForm(false));
}
break;
}
}
return null;
} catch (Exception $error) {
$session->sendMessage(TF::RED . $lang->translateString('error'));
$session->sendMessage(TF::RED . $error->getMessage());
}
});
$sender->sendForm($form);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
/**
* @param UIElement[] $elements
* @param array $data
* @return array
*/
public static function generateLore(array $elements, array $data): array
{
$return = [];
foreach ($elements as $i => $element) {
if ($element instanceof Label) continue;
if ($element instanceof Toggle) {
$return[] = ($element->getText() . ": " . ($data[$i] ? "Yes" : "No"));
continue;
}
$return[] = ($element->getText() . ": " . $data[$i]);
}
return $return;
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/brush/BrushNameCommand.php
================================================
registerArgument(0, new RawStringArgument("name", true));
$this->setPermission("we.command.brush.name");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$brush = $session->getBrushFromItem($sender->getInventory()->getItemInHand());
if ($brush instanceof Brush) {
if (empty($args["name"])) {
$sender->sendMessage($brush->getName());
return;
}
$brush->properties->setCustomName((string)$args["name"]);
$session->sendMessage(TF::GREEN . $lang->translateString('command.brushname.set', [$brush->getName()]));
$session->replaceBrush($brush);
}
} catch (Exception | TypeError $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsageMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/ClearClipboardCommand.php
================================================
setPermission("we.command.clipboard.clear");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$session->clearClipboard();
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.clearclipboard.cleared'));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/CopyCommand.php
================================================
registerArgument(0, new TextArgument("flags", true));//TODO add FlagArgument (parse returns array with flags)
$this->setPermission("we.command.clipboard.copy");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$hasFlags = isset($args["flags"]);
API::copyAsync($selection, $session, $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/Cut2Command.php
================================================
registerArgument(0, new TextArgument("flags", true));
$this->setPermission("we.command.clipboard.cut");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
#$hasFlags = isset($args["flags"]);
$action = new CutAction();
$offset = $selection->getShape()->getMinVec3()->subtractVector($session->getPlayer()->getPosition()->asVector3()->floor())->floor();
$action->setClipboardVector($offset);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$session->getUUID(),
$selection,
$action,
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"air",//TODO option
""
)
);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/CutCommand.php
================================================
registerArgument(0, new TextArgument("flags", true));
$this->setPermission("we.command.clipboard.cut");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$hasFlags = isset($args["flags"]);
//TODO Temp hack - add cutAsync - Update 9th Feb. 2020 LEAVE THAT ALONE! IT WORKS, DO NOT TOUCH IT!
$flags = $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE;
API::copyAsync($selection, $session, $flags);
API::fillAsync($selection, $session, [BlockFactory::getInstance()->get(BlockLegacyIds::AIR, 0)], $flags);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/FlipCommand.php
================================================
registerArgument(0, new MirrorAxisArgument("axis", false));
$this->setPermission("we.command.clipboard.flip");
//$this->setUsage("//flip ");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$axis = (string)$args["axis"];//TODO change to Axis[]
$sender->sendMessage(Loader::PREFIX . $lang->translateString('command.flip.try', [$axis]));
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$clipboard = $session->getCurrentClipboard();
if (!$clipboard instanceof SingleClipboard) {
throw new SessionException($lang->translateString('error.noclipboard'));
}
$action = new FlipAction($axis);
#$offset = $selection->getShape()->getMinVec3()->subtract($session->getPlayer()->asVector3()->floor())->floor();
#$action->setClipboardVector($offset);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncClipboardActionTask(
$session->getUUID(),
$clipboard->selection,
$action,
$clipboard
)
);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/PasteCommand.php
================================================
registerArgument(0, new TextArgument("flags", true));
$this->setPermission("we.command.clipboard.paste");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
* @throws AssumptionFailedError
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$clipboard = $session->getCurrentClipboard();
if (is_null($clipboard)) {
throw new SelectionException($lang->translateString('error.noclipboard'));
}
if (!$clipboard instanceof SingleClipboard) {//TODO check if i want to pass ANY clipboard instead
throw new SelectionException($lang->translateString('error.noclipboard'));
}
/*if (!API::hasFlag(API::flagParser(explode(" ", strval($args["flags"]))), API::FLAG_POSITION_RELATIVE)) {
$clipboard->setOffset(new Vector3(0,0,0));//TODO fix? Move to API
}*/
$hasFlags = isset($args["flags"]);
API::pasteAsync($clipboard, $session, $sender->getPosition(), $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/clipboard/RotateCommand.php
================================================
registerArgument(0, new RotateAngleArgument("angle", false));
$this->registerArgument(1, new BooleanArgument("aroundOrigin", true));
$this->setPermission("we.command.clipboard.rotate");
//$this->setUsage("//rotate ");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$angle = (int)$args["angle"];
$aroundOrigin = $args["aroundOrigin"] ?? true;
$sender->sendMessage(Loader::PREFIX . $lang->translateString('command.rotate.try', [$angle]));
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$clipboard = $session->getCurrentClipboard();
if (!$clipboard instanceof SingleClipboard) {
throw new SessionException($lang->translateString('error.noclipboard'));
}
$action = new RotateAction($angle/*, $aroundOrigin*/);//TODO reenable origin support if error fixed: does not rotate. Let's see if PHPStan find it for me!
#$offset = $selection->getShape()->getMinVec3()->subtract($session->getPlayer()->asVector3()->floor())->floor();
#$action->setClipboardVector($offset);
var_dump($action);
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncClipboardActionTask(
$session->getUUID(),
$clipboard->selection,
$action,
$clipboard
)
);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/debug/PlaceAllBlockstatesCommand.php
================================================
setPermission("we.command.test");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
BlockStatesParser::placeAllBlockstates($sender->getPosition());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/generation/CylinderCommand.php
================================================
registerArgument(0, new RawStringArgument("blocks", false));
$this->registerArgument(1, new IntegerArgument("diameter", false));
$this->registerArgument(2, new IntegerArgument("height", true));
$this->registerArgument(3, new TextArgument("flags", true));
$this->setPermission("we.command.generation.cyl");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
* @throws AssumptionFailedError
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$messages = [];
$error = false;
$blocks = (string)$args["blocks"];//TODO change to Palette
$diameter = (int)$args["diameter"];
$height = (int)($args["height"] ?? 1);
$newblocks = API::blockParser($blocks, $messages, $error);
foreach ($messages as $message) {
$sender->sendMessage($message);
}
if (!$error) {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$cyl = new Cylinder($sender->getPosition()->asVector3()->floor(), $height, $diameter);
$cylSelection = new Selection($session->getUUID(), $sender->getWorld());
$cylSelection->setShape($cyl);
$hasFlags = isset($args["flags"]);
API::fillAsync($cylSelection, $session, $newblocks, $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE);
} else {
throw new InvalidArgumentException("Could not fill with the selected blocks");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/history/ClearhistoryCommand.php
================================================
setPermission("we.command.history.clear");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$session->clearHistory();
$sender->sendMessage(Loader::PREFIX . TF::GREEN . $lang->translateString('command.history.cleared'));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/history/RedoCommand.php
================================================
setPermission("we.command.history.redo");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$session->redo();
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/history/UndoCommand.php
================================================
setPermission("we.command.history.undo");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$session->undo();
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/region/OverlayCommand.php
================================================
registerArgument(0, new RawStringArgument("blocks", false));
$this->setPermission("we.command.region.overlay");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$messages = [];
$error = false;
$blocks = API::blockParser((string)$args["blocks"], $messages, $error);//TODO change to Palette
foreach ($messages as $message) {
$sender->sendMessage($message);
}
$return = !$error;
if ($return) {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
#API::overlayReplaceAsync($selection, $session, [], $blocks, API::flagParser(explode(" ", strval($args["flags"]))));
} else {
throw new InvalidArgumentException("Could not replace with the selected blocks");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/region/ReplaceCommand.php
================================================
registerArgument(0, new RawStringArgument("findblocks", false));
$this->registerArgument(1, new RawStringArgument("replaceblocks", false));
$this->registerArgument(2, new TextArgument("flags", true));
$this->setPermission("we.command.region.replace");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$messages = [];
$error = false;
$findBlocks = API::blockParser((string)$args["findblocks"], $messages, $error);//TODO change to Palette
$replaceBlocks = API::blockParser((string)$args["replaceblocks"], $messages, $error);//TODO change to Palette
foreach ($messages as $message) {
$sender->sendMessage($message);
}
$return = !$error;
if ($return) {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$hasFlags = isset($args["flags"]);
API::replaceAsync($selection, $session, $findBlocks, $replaceBlocks, $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE);
} else {
throw new InvalidArgumentException("Could not replace with the selected blocks");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/region/SetCommand.php
================================================
registerArgument(0, new RawStringArgument("blocks", false));
$this->registerArgument(1, new TextArgument("flags", true));
$this->setPermission("we.command.region.set");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$messages = [];
$error = false;
$replaceBlocks = API::blockParser((string)$args["blocks"], $messages, $error);//TODO change to Palette
foreach ($messages as $message) {
$sender->sendMessage($message);
}
if (!$error) {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$hasFlags = isset($args["flags"]);
API::fillAsync($selection, $session, $replaceBlocks, $hasFlags ? API::flagParser(explode(" ", (string)$args["flags"])) : API::FLAG_BASE);
} else {
throw new InvalidArgumentException("Could not fill with the selected blocks");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/ChunkCommand.php
================================================
setPermission("we.command.selection.chunk");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates
if (is_null($selection)) {
throw new Error("No selection created - Check the console for errors");
}
$chunk = $sender->getWorld()->getOrLoadChunkAtPosition($sender->getPosition());
if (is_null($chunk)) {
throw new Error("Could not find a chunk at your position");
}
$x = $sender->getPosition()->x >> 4;
$z = $sender->getPosition()->x >> 4;
$selection->setPos1(Position::fromObject(new Vector3($x * 16, 0, $z * 16), $sender->getWorld()));
$selection->setPos2(Position::fromObject(new Vector3($x * 16 + 15, World::Y_MAX, $z * 16 + 15), $sender->getWorld()));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/HPos1Command.php
================================================
setPermission("we.command.selection.hpos");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates
if (is_null($selection)) {
throw new Error("No selection created - Check the console for errors");
}
$target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance());
if ($target === null) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget'));
return;
}
$selection->setPos1($target->getPos());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/HPos2Command.php
================================================
setPermission("we.command.selection.hpos");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates
if (is_null($selection)) {
throw new Error("No selection created - Check the console for errors");
}
$target = $sender->getTargetBlock(Loader::getInstance()->getToolDistance());
if ($target === null) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.notarget'));
return;
}
$selection->setPos2($target->getPos());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/Pos1Command.php
================================================
setPermission("we.command.selection.pos");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates
if (is_null($selection)) {
throw new Error("No selection created - Check the console for errors");
}
$selection->setPos1($sender->getPosition());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/Pos2Command.php
================================================
setPermission("we.command.selection.pos");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (!$session instanceof UserSession) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection() ?? $session->addSelection(new Selection($session->getUUID(), $sender->getWorld())); // TODO check if the selection inside of the session updates
if (is_null($selection)) {
throw new Error("No selection created - Check the console for errors");
}
$selection->setPos2($sender->getPosition());
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/info/CountCommand.php
================================================
registerArgument(0, new RawStringArgument("blocks", true));
$this->registerArgument(1, new TextArgument("flags", true));
$this->setPermission("we.command.selection.info.count");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$error = false;
if (!empty($args["blocks"])) {
$messages = [];
API::blockParser(($filterBlocks = (string)$args["blocks"]), $messages, $error);//TODO change to Palette
foreach ($messages as $message) {
$sender->sendMessage($message);
}
} else $filterBlocks = "";
if (!$error) {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$session->sendMessage(TF::GOLD . $lang->translateString('warning.differentworld'));
}
Server::getInstance()->getAsyncPool()->submitTask(
new AsyncActionTask(
$session->getUUID(),
$selection,
new CountAction(),
$selection->getShape()->getTouchedChunks($selection->getWorld()),
"",
$filterBlocks
)
);
} else {
throw new InvalidArgumentException("Could not count the selected blocks");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/info/ListChunksCommand.php
================================================
setPermission("we.command.selection.info.listchunks");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$touchedChunks = $selection->getShape()->getTouchedChunks($selection->getWorld());
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.listchunks.found', [count($touchedChunks)]));
foreach ($touchedChunks as $chunkHash => $touchedChunk) {
$chunk = FastChunkSerializer::deserialize($touchedChunk);
$biomes = [];
for ($x = 0; $x < 16; $x++)
for ($z = 0; $z < 16; $z++)
$biomes[] = (FastChunkSerializer::deserialize($touchedChunk)->getBiomeId($x, $z));
$biomes = array_unique($biomes);
$biomecount = count($biomes);
$biomes = implode(", ", $biomes);
World::getXZ($chunkHash, $cx, $cz);
$session->sendMessage(TF::AQUA . "ID: {$chunkHash} | X: {$cx} Z: {$cz} | Subchunks: {$chunk->getHeight()} | Biomes: ($biomecount) $biomes");
}
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/selection/info/SizeCommand.php
================================================
setPermission("we.command.selection.info.size");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$selection = $session->getLatestSelection();
if (is_null($selection)) {
throw new SelectionException($lang->translateString('error.noselection'));
}
if (!$selection->isValid()) {
throw new SelectionException($lang->translateString('error.selectioninvalid'));
}
if ($selection->getWorld() !== $sender->getWorld()) {
$sender->sendMessage(Loader::PREFIX . TF::GOLD . $lang->translateString('warning.differentworld'));
}
$session->sendMessage(TF::DARK_AQUA . $lang->translateString('command.size'));
$session->sendMessage(TF::AQUA . "Total: {$selection->getShape()->getTotalCount()} X: {$selection->getSizeX()} Y: {$selection->getSizeY()} Z: {$selection->getSizeZ()}");
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/tool/DebugCommand.php
================================================
setPermission("we.command.tool.debug");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$item = ItemFactory::getInstance()->get(ItemIds::STICK);
$item->addEnchantment(new EnchantmentInstance(Loader::$ench));
$item->setCustomName(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $lang->translateString('tool.debug'));
$item->setLore([
$lang->translateString('tool.debug.lore.1'),
$lang->translateString('tool.debug.lore.2'),
$lang->translateString('tool.debug.lore.3')
]);
$item->getNamedTag()->setTag(API::TAG_MAGIC_WE, CompoundTag::create());
$sender->getInventory()->addItem($item);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/tool/FloodCommand.php
================================================
setPermission("we.command.tool.floodfill");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$sender->sendMessage(TF::RED . "TEMPORARILY DISABLED!");
/*
if (!$sender instanceof Player) return;
/** @var Player $sender * /
$lang = Loader::getInstance()->getLanguage();
try {
if ($sender instanceof Player) {
$form = new CustomForm(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $lang->translateString('ui.flood.title'));
$form->addElement(new Slider($lang->translateString('ui.flood.options.limit'), 0, 5000, 500.0));
$form->addElement(new Input($lang->translateString('ui.flood.options.blocks'), $lang->translateString('ui.flood.options.blocks.placeholder')));
$form->addElement(new Label($lang->translateString('ui.flood.options.label.infoapply')));
$form->setCallable(function (Player $player, $data) use ($form) {
$item = ItemFactory::get(ItemIds::BUCKET, 1);
$item->addEnchantment(new EnchantmentInstance(Enchantment::getEnchantment(Loader::FAKE_ENCH_ID)));
$item->setCustomName(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . 'Flood');
$item->setLore(BrushCommand::generateLore($form->getContent(), $data));
$item->setNamedTagEntry(new CompoundTag(API::TAG_MAGIC_WE, [
new StringTag("blocks", $data[1]),
new FloatTag("limit", $data[0]),
]));
$player->getInventory()->addItem($item);
});
$sender->sendForm($form);
} else {
$sender->sendMessage(TF::RED . "Console can not use this command.");
}
} catch (\Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . Loader::getInstance()->getLanguage()->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (\ArgumentCountError $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . Loader::getInstance()->getLanguage()->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (\Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}*/
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/tool/ToggledebugCommand.php
================================================
setPermission("we.command.tool.toggledebug");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$sender->sendMessage($session->setDebugToolEnabled(!$session->isDebugToolEnabled()));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/tool/TogglewandCommand.php
================================================
setPermission("we.command.tool.togglewand");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$sender->sendMessage($session->setWandEnabled(!$session->isWandEnabled()));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/tool/WandCommand.php
================================================
setPermission("we.command.tool.wand");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
/** @var Durable $item */
$item = ItemFactory::getInstance()->get(ItemIds::WOODEN_AXE);
$item->addEnchantment(new EnchantmentInstance(Loader::$ench));
$item->setUnbreakable(true);
$item->setCustomName(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $lang->translateString('tool.wand'));
$item->setLore([
$lang->translateString('tool.wand.lore.1'),
$lang->translateString('tool.wand.lore.2'),
$lang->translateString('tool.wand.lore.3')
]);
$item->getNamedTag()->setTag(API::TAG_MAGIC_WE, CompoundTag::create());
if (!$sender->getInventory()->contains($item)) $sender->getInventory()->addItem($item);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
} catch (Error $error) {
Loader::getInstance()->getLogger()->logException($error);
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/utility/CalculateCommand.php
================================================
registerArgument(0, new TextArgument("expression", false));
$this->setPermission("we.command.utility.calculate");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
try {
$sender->sendMessage((string)$args["expression"] . " = " . API::evalAsMath((string)$args["expression"]));
} catch (CalculationException $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage(Loader::PREFIX . TF::RED . (string)$args["expression"]);
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/commands/utility/ToggleWailaCommand.php
================================================
setPermission("we.command.utility.togglewaila");
}
/**
* @param CommandSender $sender
* @param string $aliasUsed
* @param mixed[] $args
*/
public function onRun(CommandSender $sender, string $aliasUsed, array $args): void
{
$lang = Loader::getInstance()->getLanguage();
if ($sender instanceof Player && SessionHelper::hasSession($sender)) {
try {
$lang = SessionHelper::getUserSession($sender)->getLanguage();
} catch (SessionException $e) {
}
}
if (!$sender instanceof Player) {
$sender->sendMessage(TF::RED . $lang->translateString('error.runingame'));
return;
}
/** @var Player $sender */
try {
$session = SessionHelper::getUserSession($sender);
if (is_null($session)) {
throw new SessionException($lang->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$sender->sendMessage($session->setWailaEnabled(!$session->isWailaEnabled()));
} catch (Exception $error) {
$sender->sendMessage(Loader::PREFIX . TF::RED . $lang->translateString('error.command-error'));
$sender->sendMessage(Loader::PREFIX . TF::RED . $error->getMessage());
$sender->sendMessage($this->getUsage());
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/event/MWEEditEvent.php
================================================
oldBlocks = $oldBlocks;
$this->newBlocks = $newBlocks;
$this->session = $session;
}
/**
* @return null|Session
*/
public function getSession(): ?Session
{
return $this->session;
}
/**
* @return null|Player
*/
public function getPlayer(): ?Player
{
if (($session = $this->getSession()) instanceof UserSession)
/** @var UserSession $session */
$session->getPlayer();
return null;
}
/**
* @param null|Player $player
*/
public function setPlayer(?Player $player): void
{
if (($session = $this->getSession()) instanceof UserSession)
/** @var UserSession $session */
$session->setPlayer($player);
}
/**
* @return Block[]
*/
public function getOldBlocks(): array
{
return $this->oldBlocks;
}
/**
* @return Block[]
*/
public function getNewBlocks(): array
{
return $this->newBlocks;
}
/**
* @param Block[] $newBlocks
*/
public function setNewBlocks(array $newBlocks): void
{
$this->newBlocks = $newBlocks;
}
}
================================================
FILE: src/xenialdan/MagicWE2/event/MWEEvent.php
================================================
selection = $selection;
$this->type = $type;
try {
$this->session = SessionHelper::getSessionByUUID($selection->sessionUUID);
} catch (SessionException $e) {
}
}
/**
* @return Selection
*/
public function getSelection(): Selection
{
return $this->selection;
}
/**
* @param Selection $selection
*/
public function setSelection(Selection $selection): void
{
$this->selection = $selection;
}
/**
* @return null|Session
*/
public function getSession(): ?Session
{
return $this->session;
}
/**
* @return null|Player
*/
public function getPlayer(): ?Player
{
if (($session = $this->getSession()) instanceof UserSession)
/** @var UserSession $session */
return $session->getPlayer();
return null;
}
/**
* @return int
*/
public function getType(): int
{
return $this->type;
}
}
================================================
FILE: src/xenialdan/MagicWE2/event/MWESessionLoadEvent.php
================================================
session = $session;
}
/**
* @return null|Session
*/
public function getSession(): ?Session
{
return $this->session;
}
/**
* @return null|Player
*/
public function getPlayer(): ?Player
{
return $this->session instanceof UserSession ? $this->session->getPlayer() : null;
}
}
================================================
FILE: src/xenialdan/MagicWE2/event/MWESessionSettingChangeEvent.php
================================================
session = $session;
$this->type = $type;//TODO use
}
/**
* @return null|Session
*/
public function getSession(): ?Session
{
return $this->session;
}
/**
* @return null|Player
*/
public function getPlayer(): ?Player
{
if (($session = $this->getSession()) instanceof UserSession)
/** @var UserSession $session */
return $session->getPlayer();
return null;
}
/**
* @return int
*/
public function getType(): int
{
return $this->type;
}
}
================================================
FILE: src/xenialdan/MagicWE2/exception/ActionNotFoundException.php
================================================
getBlockAt($x, $y, $z)->getId(), $this->getBlockAt($x, $y, $z)->getMeta()];
}
/**
* @return Chunk[]
*/
public function getChunks(): array
{
return $this->chunks;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/BlockEntry.php
================================================
fullId = $fullId;
$this->nbt = $nbt;
}
public function validate(): bool
{
/** @var BlockFactory $instance */
$instance = BlockFactory::getInstance();
$block = $instance->fromFullBlock($this->fullId);
[$id, $meta] = [$block->getId(), $block->getMeta()];
if ($id === BlockLegacyIds::INFO_UPDATE) {
return false;
}
if ($this->nbt instanceof CompoundTag && !$this->nbt->valid()) {
return false;
}
return true;
}
public function __toString()
{
/** @var BlockFactory $instance */
$instance = BlockFactory::getInstance();
$block = $instance->fromFullBlock($this->fullId);
$str = __CLASS__ . " " . $this->fullId . " [{$block->getId()}:{$block->getMeta()}]";
if ($this->nbt instanceof CompoundTag) {
$str .= " " . str_replace("\n", "", $this->nbt->toString());
}
return $str;
}
public function toBlock(): Block
{
/** @var BlockFactory $instance */
$instance = BlockFactory::getInstance();
return $instance->fromFullBlock($this->fullId);
}
public static function fromBlock(Block $block): self
{
BlockFactory::getInstance();
return new BlockEntry($block->getFullId());
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/BlockPalette.php
================================================
getFullId();
return json_encode($e, JSON_THROW_ON_ERROR);
}
/**
* @param string $blocks
* @return array
* @throws JsonException
*/
public static function decode(string $blocks): array
{
$e = [];
foreach (json_decode($blocks, true, 512, JSON_THROW_ON_ERROR) as $block)
$e[] = BlockFactory::getInstance()->fromFullBlock($block);
return $e;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/BlockStatesEntry.php
================================================
blockIdentifier = $blockIdentifier;
$this->blockStates = $blockStates;
$this->block = $block;
try {
if ($this->blockStates !== null)
$this->blockFull = TextFormat::clean(BlockStatesParser::printStates($this, false));
else
$this->blockFull = $this->blockIdentifier;
} catch (Throwable $e) {
GlobalLogger::get()->logException($e);
$this->blockFull = $this->blockIdentifier;
}
}
/**
* @return string
*/
public function __toString()
{
return $this->blockFull;
}
/**
* TODO hacky AF. clean up
* @return Block
* @throws InvalidArgumentException
* @throws RuntimeException
* @throws InvalidBlockStateException
*/
public function toBlock(): Block
{
if ($this->block instanceof Block) return $this->block;
BlockFactory::getInstance();
$blocks = BlockStatesParser::getInstance()::fromString($this->blockFull, false);
$block = reset($blocks);
if($block instanceof Block) $this->block = $block;
return $this->block;
}
/**
* TODO Optimize (reduce getStateByBlock/fromString calls)
* @param int $amount any of [90,180,270]
* @return BlockStatesEntry
* @throws InvalidArgumentException
* @throws InvalidBlockStateException
* @throws RuntimeException
*/
public function rotate(int $amount): BlockStatesEntry
{
//TODO validate $amount
$clone = clone $this;
$block = $clone->toBlock();
$idMapName = str_replace("minecraft:", "", BlockStatesParser::getBlockIdMapName($block));
$key = $idMapName . ":" . $block->getMeta();
if (strpos($idMapName, "_door") !== false) {
$fromMap = BlockStatesParser::getDoorRotationFlipMap()[$block->getMeta()] ?? null;
} else {
$fromMap = BlockStatesParser::getRotationFlipMap()[$key] ?? null;
}
if ($fromMap === null) return $clone;
$rotatedStates = $fromMap[$amount] ?? null;
if ($rotatedStates === null) return $clone;
//ugly hack to keep current ones
//TODO use the states compound tag
$bsCompound = $clone->blockStates;
#$bsCompound->setName("minecraft:$key");//TODO this might cause issues with the parser since it stays same //seems to work ¯\_(ツ)_/¯
foreach ($rotatedStates as $tagName => $v) {
//TODO clean up.. new method?
$tag = $bsCompound->getTag($tagName);
if ($tag === null) {
throw new InvalidBlockStateException("Invalid state $tagName");
}
if ($tag instanceof StringTag) {
$bsCompound->setString($tagName, $v);
} else if ($tag instanceof IntTag) {
$bsCompound->setInt($tagName, (int)$v);
} else if ($tag instanceof ByteTag) {
if ($v === 1) $v = "true";
if ($v === 0) $v = "false";
if ($v !== "true" && $v !== "false") {
throw new InvalidBlockStateException("Invalid value $v for blockstate $tagName, must be \"true\" or \"false\"");
}
$bsCompound->setByte($tagName, $v === "true" ? 1 : 0);
} else {
throw new InvalidBlockStateException("Unknown tag of type " . get_class($tag) . " detected");
}
}
$clone->blockStates = $bsCompound;
$clone->blockFull = TextFormat::clean(BlockStatesParser::printStates($clone, false));
if (strpos($idMapName, "_door") !== false) {
$clone->block = BlockStatesParser::fromString($clone->blockFull, false)[0];
} else
$clone->block = null;
return $clone;
//TODO reduce useless calls. BSP::fromStates?
#$blockFull = TextFormat::clean(BlockStatesParser::printStates($clone, false));
#return BlockStatesParser::getStateByBlock(BlockStatesParser::fromString($blockFull)[0]);
}
/**
* TODO Optimize (reduce getStateByBlock/fromString calls)
* @param string $axis any of ["x","y","z","xz"]
* @return BlockStatesEntry
* @throws InvalidArgumentException
* @throws InvalidBlockStateException
* @throws RuntimeException
*/
public function mirror(string $axis): BlockStatesEntry
{
//TODO validate $axis
$clone = clone $this;
$block = $clone->toBlock();
$idMapName = str_replace("minecraft:", "", BlockStatesParser::getBlockIdMapName($block));
$key = $idMapName . ":" . $block->getMeta();
if ($axis !== FlipAction::AXIS_Y) {//ugly hack for y flip
$fromMap = BlockStatesParser::getRotationFlipMap()[$key] ?? null;
if ($fromMap === null) {
#var_dump("block not in mirror map");
return $clone;
}
$flippedStates = $fromMap[$axis] ?? null;
if ($flippedStates === null /*&& $axis !== FlipAction::AXIS_Y*/) {//ugly hack for y flip
#var_dump("axis not in mirror map");
return $clone;
}
}
//ugly hack to keep current ones
//TODO use the states compound tag
$bsCompound = clone $clone->blockStates;//TODO check if clone is necessary
#$bsCompound->setName("minecraft:$key");//TODO this might cause issues with the parser since it stays same //seems to work ¯\_(ツ)_/¯
if ($axis === FlipAction::AXIS_Y && !(//TODO maybe add vine + mushroom block directions
$bsCompound->hasTag("attachment") ||
$bsCompound->hasTag("facing_direction") ||
$bsCompound->hasTag("hanging") ||
$bsCompound->hasTag("lever_direction") ||
$bsCompound->hasTag("rail_direction") ||
$bsCompound->hasTag("top_slot_bit") ||
$bsCompound->hasTag("torch_facing_direction") ||
$bsCompound->hasTag("upper_block_bit") ||
$bsCompound->hasTag("upside_down_bit")
)) {//ugly hack for y flip
#var_dump("nothing can be flipped around y axis");
return $clone;
}
foreach ($bsCompound as $tagName => $tag) {
//TODO clean up.. new method?
if ($axis === FlipAction::AXIS_Y) {
$value = $tag->getValue();
switch ($tagName) {//TODO clean up oh my god
case "attachment":
{
if ($value === "standing") $value = "hanging";
else if ($value === "hanging") $value = "standing";
break;
}
case "hanging":
case "upside_down_bit":
case "upper_block_bit":
case "top_slot_bit":
case "facing_direction":
{
if ($value === 0) $value = 1;
else if ($value === 1) $value = 0;
break;
}
case "lever_direction":
{
if ($value === "down_east_west") $value = "up_east_west";
else if ($value === "up_east_west") $value = "down_east_west";
else if ($value === "down_north_south") $value = "up_north_south";
else if ($value === "up_north_south") $value = "down_north_south";
break;
}
case "rail_direction":
{
//TODO
break;
}
case "torch_facing_direction":
{
if ($value === "unknown") $value = "top";
else if ($value === "top") $value = "unknown";
break;
}/*
default:
{
$value = $flippedStates[$stateName];
}*/
}
} else if (isset($flippedStates)) $value = $flippedStates[$tagName] ?? $tag->getValue(); else throw new InvalidArgumentException("flippedStates is not set. Error should never occur, please use //report and send a stack trace");
if ($tag instanceof StringTag) {
$bsCompound->setString($tagName, $value);
} else if ($tag instanceof IntTag) {
$bsCompound->setInt($tagName, (int)$value);
} else if ($tag instanceof ByteTag) {
if ($value === 1) $value = "true";
if ($value === 0) $value = "false";
if ($value !== "true" && $value !== "false") {
throw new InvalidBlockStateException("Invalid value $value for blockstate $tagName, must be \"true\" or \"false\"");
}
$bsCompound->setByte($tagName, $value === "true" ? 1 : 0);
} else {
throw new InvalidBlockStateException("Unknown tag of type " . get_class($tag) . " detected");
}
}
$clone->blockStates = $bsCompound;
$clone->block = null;
$clone->blockFull = TextFormat::clean(BlockStatesParser::printStates($clone, false));
#var_dump($clone->blockFull);
return $clone;
//TODO reduce useless calls. BSP::fromStates?
#$blockFull = TextFormat::clean(BlockStatesParser::printStates($clone, false));
#return BlockStatesParser::getStateByBlock(BlockStatesParser::fromString($blockFull)[0]);
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/BlockStatesParser.php
================================================
loadRotationAndFlipData(Loader::getRotFlipPath());
// $this->loadDoorRotationAndFlipData(Loader::getDoorRotFlipPath());
$this->loadRotationAndFlipData(self::$rotPath);
$this->loadDoorRotationAndFlipData(self::$doorRotPath);
$this->loadLegacyMappings();
}
private function loadLegacyMappings(): void
{
/** @var R12ToCurrentBlockMapEntry[][] $legacyStateMap */
self::$legacyStateMap = [];
$contents = file_get_contents(RESOURCE_PATH . "vanilla/r12_to_current_block_map.bin");
if ($contents === false) throw new PluginException("Can not get contents of r12_to_current_block_map");
$legacyStateMapReader = new PacketSerializer($contents);
$nbtReader = new NetworkNbtSerializer();
while (!$legacyStateMapReader->feof()) {
$id = $legacyStateMapReader->getString();
$meta = $legacyStateMapReader->getLShort();
$offset = $legacyStateMapReader->getOffset();
$state = $nbtReader->read($legacyStateMapReader->getBuffer(), $offset)->mustGetCompoundTag();
$legacyStateMapReader->setOffset($offset);
$r12ToCurrentBlockMapEntry = new R12ToCurrentBlockMapEntry($id, $meta, $state);
self::$legacyStateMap[$id][$meta] = $r12ToCurrentBlockMapEntry;
}
ksort(self::$legacyStateMap, SORT_NUMERIC);
}
/**
* @param string|null $path
* @throws JsonException
* @throws PluginException
*/
protected function loadRotationAndFlipData(?string $path = null): void
{
if ($path !== null) {
$fileGetContents = file_get_contents($path);
if ($fileGetContents === false) {
throw new PluginException("rotation_flip_data.json could not be loaded! Rotation and flip support has been disabled!");
}
self::$rotationFlipMap = json_decode($fileGetContents, true, 512, JSON_THROW_ON_ERROR);
GlobalLogger::get()->debug("Successfully loaded rotation_flip_data.json");
}
}
/**
* @param string|null $path
* @throws JsonException
* @throws PluginException
*/
protected function loadDoorRotationAndFlipData(?string $path = null): void
{
if ($path !== null) {
$fileGetContents = file_get_contents($path);
if ($fileGetContents === false) {
throw new PluginException("door_data.json could not be loaded! Door rotation and flip support has been disabled!");
}
self::$doorRotationFlipMap = json_decode($fileGetContents, true, 512, JSON_THROW_ON_ERROR);
GlobalLogger::get()->debug("Successfully loaded door_data.json");
}
}
/**
* @return array
*/
public static function getRotationFlipMap(): array
{
return self::$rotationFlipMap;
}
/**
* @return array
*/
public static function getDoorRotationFlipMap(): array
{
return self::$doorRotationFlipMap;
}
/**
* @param string $namespacedSelectedBlockName
* @param CompoundTag $states
* @return Door
* @throws InvalidArgumentException
* @throws InvalidBlockStateException
* @throws RuntimeException
* @throws \pocketmine\block\utils\InvalidBlockStateException
*/
private static function buildDoor(string $namespacedSelectedBlockName, CompoundTag $states): Door
{
/** @var Door $door */
$door = self::fromString($namespacedSelectedBlockName)[0];
$door->setOpen($states->getByte("open_bit") === 1);
$door->setTop($states->getByte("upper_block_bit") === 1);
$door->setHingeRight($states->getByte("door_hinge_bit") === 1);
$direction = $states->getInt("direction");
$door->setFacing(Facing::rotateY(BlockDataSerializer::readLegacyHorizontalFacing($direction & 0x03), false));
return $door;
}
/**
* @param array $aliasMap
*/
public function setAliasMap(array $aliasMap): void
{
self::$aliasMap = $aliasMap;
}
/**
* @param Block $block
* @return string|null
*/
public static function getBlockIdMapName(Block $block): ?string
{
return LegacyBlockIdToStringIdMap::getInstance()->legacyToString($block->getId());
}
/**
* @param string $blockIdentifier
* @return CompoundTag
*/
protected static function getDefaultStates(string $blockIdentifier): CompoundTag
{
return self::$legacyStateMap[$blockIdentifier][0]->getBlockState()->getCompoundTag('states') ?? new CompoundTag();
}
/**
* @param string $query
* @param bool $multiple
* @return Block[]
* @throws InvalidArgumentException
* @throws InvalidBlockStateException
* @throws RuntimeException
*/
public static function fromString(string $query, bool $multiple = false): array
{
#if (!BlockFactory::isInit()) BlockFactory::init();
$blocks = [];
if ($multiple) {
$pregSplit = preg_split('/,(?![^\[]*])/', trim($query), -1, PREG_SPLIT_NO_EMPTY);
if (!is_array($pregSplit)) throw new InvalidArgumentException("Regex matching failed");
foreach ($pregSplit as $b) {
/** @noinspection SlowArrayOperationsInLoopInspection */
$blocks = array_merge($blocks, self::fromString($b, false));
}
return $blocks;
}
$blockData = strtolower(str_replace("minecraft:", "", $query));//TODO try to keep namespace "minecraft:" to support custom blocks
$re = '/([\w:]+)(?:\[([\w=,]*)\])?/m';
preg_match_all($re, $blockData, $matches, PREG_SET_ORDER, 0);
if (!isset($matches[0][1])) {
throw new InvalidArgumentException("Could not detect block id");
}
$selectedBlockName = $matches[0][1];
$namespacedSelectedBlockName = "minecraft:" . $selectedBlockName;//TODO try to keep namespace "minecraft:" to support custom blocks
/** @var LegacyStringToItemParser $legacyStringToItemParser */
$legacyStringToItemParser = LegacyStringToItemParser::getInstance();
$block = $legacyStringToItemParser->parse($selectedBlockName)->getBlock();
if (count($matches[0]) < 3) {
return [$block];
}
$defaultStatesNamedTag = self::getDefaultStates($namespacedSelectedBlockName);
if (!$defaultStatesNamedTag instanceof CompoundTag) {
throw new InvalidArgumentException("Could not find default block states for $namespacedSelectedBlockName");
}
$extraData = $matches[0][2] ?? "";
$statesExploded = explode(",", $extraData);
$finalStatesList = clone $defaultStatesNamedTag;
#var_dump($statesExploded, $finalStatesList->toString());
#$finalStatesList->setName("states");
$availableAliases = [];//TODO map in init()! No need to recreate every time! EDIT 2k20: uhm what? @ my past self, why can't you explain properly?!
foreach ($finalStatesList as $stateName => $state) {
if (array_key_exists($stateName, self::$aliasMap)) {
foreach (self::$aliasMap[$stateName]["alias"] as $alias) {
//todo maybe check for duplicated alias here? "block state mapping invalid: duplicated alias detected"
$availableAliases[$alias] = $stateName;
}
}
}
foreach ($statesExploded as $stateKeyValuePair) {
if (strpos($stateKeyValuePair, "=") === false) continue;
[$stateName, $value] = explode("=", $stateKeyValuePair);
$value = strtolower(trim((string)$value));
if ($value === '') {
throw new InvalidBlockStateException("Empty value for state $stateName");
}
//change blockstate alias to blockstate name
$stateName = $availableAliases[$stateName] ?? $stateName;
//TODO maybe validate wrong states here? i.e. stone[type=wrongtype] => Exception, "wrongtype" is invalid value
$tag = $finalStatesList->getTag($stateName);
if ($tag === null) {
throw new InvalidBlockStateException("Invalid state $stateName");
}
if ($tag instanceof StringTag) {
$finalStatesList->setString($stateName, $value);
} else if ($tag instanceof IntTag) {
$finalStatesList->setInt($stateName, (int)$value);
} else if ($tag instanceof ByteTag) {
if ($value === '1' || $value === 'true') $value = 'true';
if ($value === '0' || $value === 'false') $value = 'false';
if ($value !== "true" && $value !== "false") {
throw new InvalidBlockStateException("Invalid value $value for blockstate $stateName, must be \"true\" or \"false\"");
}
$finalStatesList->setByte($stateName, $value === "true" ? 1 : 0);
} else {
throw new InvalidBlockStateException("Unknown tag of type " . get_class($tag) . " detected");
}
}
#var_dump($finalStatesList->toString());
//print final list
//TODO remove. This crashes in AsyncTasks and is just for debug
#Loader::getInstance()->getLogger()->notice(self::printStates(new BlockStatesEntry($namespacedSelectedBlockName,$finalStatesList), false));
//return found block(s)
$blocks = [];
//doors.. special blocks annoying -.-
$isDoor = strpos($namespacedSelectedBlockName, "_door") !== false;
if ($isDoor) {
return [self::buildDoor($namespacedSelectedBlockName, $finalStatesList)];
}
#var_dump((string)$finalStatesList);
foreach (self::$legacyStateMap[$namespacedSelectedBlockName] as $meta => $r12ToCurrentBlockMapEntry) {
$clonedPrintedCompound = clone $r12ToCurrentBlockMapEntry->getBlockState()->getCompoundTag('states');
if ($clonedPrintedCompound->equals($finalStatesList)) {
#Server::getInstance()->getLogger()->notice("FOUND!");
/** @var BlockFactory $blockFactory */
$blockFactory = BlockFactory::getInstance();
$block = $blockFactory->get($block->getId(), $meta & 0xf);
#var_dump($oldNameAndMeta,$block);
#var_dump($block, $finalStatesList);
$blocks[] = $block;
#Server::getInstance()->getLogger()->debug(TF::GREEN . "Found block: " . TF::GOLD . $block);
#Server::getInstance()->getLogger()->notice(self::printStates(new BlockStatesEntry($namespacedSelectedBlockName, $clonedPrintedCompound), true));//might cause loop lol
}
}
#if (empty($blocks)) return [Block::get(0)];//no block found //TODO r12 map only has blocks up to id 255. On 4.0.0, return Item::fromString()?
if (empty($blocks)) throw new InvalidArgumentException("No block $namespacedSelectedBlockName matching $query could be found");//no block found //TODO r12 map only has blocks up to id 255. On 4.0.0, return Item::fromString()?
if (count($blocks) === 1) return $blocks;
//"Hack" to get just one block if multiple results have been found. Most times this results in the default one (meta:0)
$smallestMeta = PHP_INT_MAX;
$result = null;
foreach ($blocks as $block) {
if ($block->getMeta() < $smallestMeta) {
$smallestMeta = $block->getMeta();
$result = $block;
}
}
#Loader::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "Final block: " . TF::AQUA . $result);
/** @var Block $result */
return [$result];
}
public static function getStateByBlock(Block $block): ?BlockStatesEntry
{
$name = self::getBlockIdMapName($block);
if ($name === null) return null;
$damage = $block->getMeta();
$blockStates = clone self::$legacyStateMap[$name][$damage]->getBlockState()->getCompoundTag('states');
if ($blockStates === null) return null;
return new BlockStatesEntry($name, $blockStates, $block);
}
public static function getStateByCompound(CompoundTag $compoundTag): ?BlockStatesEntry
{
$namespacedSelectedBlockName = $compoundTag->getString('name', "");
if ($namespacedSelectedBlockName === "") return null;
$states = $compoundTag->getCompoundTag('states') ?? self::getDefaultStates($namespacedSelectedBlockName);
if (!$states instanceof CompoundTag) {
throw new InvalidArgumentException("Could not find default block states for $namespacedSelectedBlockName");
}
if (strpos($namespacedSelectedBlockName, "_door") !== false) {
$door = self::buildDoor($namespacedSelectedBlockName, $states);
//return self::getStateByBlock($door);
return new BlockStatesEntry($namespacedSelectedBlockName, $states, $door);
}
foreach (self::$legacyStateMap[$namespacedSelectedBlockName] ?? [] as $meta => $r12ToCurrentBlockMapEntry) {//??[] is to avoid crashes on newer blocks like light block
$clonedPrintedCompound = $r12ToCurrentBlockMapEntry->getBlockState()->getCompoundTag('states');
if ($clonedPrintedCompound->equals($states)) {
#Server::getInstance()->getLogger()->notice(self::printStates(new BlockStatesEntry($namespacedSelectedBlockName, $clonedPrintedCompound), true));//might cause loop lol//todo rem
return new BlockStatesEntry($namespacedSelectedBlockName, $clonedPrintedCompound);
}
}
return null;
}
/**
* @param BlockStatesEntry $entry
* @param bool $skipDefaults
* @return string
* @throws RuntimeException
*/
public static function printStates(BlockStatesEntry $entry, bool $skipDefaults): string
{
$printedCompound = $entry->blockStates;
$blockIdentifier = $entry->blockIdentifier;
$s = [];
foreach ($printedCompound as $statesTagEntryName => $statesTagEntry) {
/** @var CompoundTag $defaultStatesNamedTag */
$defaultStatesNamedTag = self::getDefaultStates($blockIdentifier);
$namedTag = $defaultStatesNamedTag->getTag($statesTagEntryName);
if (!$namedTag instanceof ByteTag && !$namedTag instanceof StringTag && !$namedTag instanceof IntTag) {
continue;
}
//skip defaults
/** @var ByteTag|IntTag|StringTag $namedTag */
if ($skipDefaults && $namedTag->equals($statesTagEntry)) continue;
//prepare string
if ($statesTagEntry instanceof ByteTag) {
$s[] = TF::RED . $statesTagEntryName . "=" . ($statesTagEntry->getValue() ? TF::GREEN . "true" : TF::RED . "false") . TF::RESET;
} else if ($statesTagEntry instanceof IntTag) {
$s[] = TF::BLUE . $statesTagEntryName . "=" . TF::BLUE . $statesTagEntry->getValue() . TF::RESET;
} else if ($statesTagEntry instanceof StringTag) {
$s[] = TF::LIGHT_PURPLE . $statesTagEntryName . "=" . TF::LIGHT_PURPLE . $statesTagEntry->getValue() . TF::RESET;
}
}
if (count($s) === 0) {
#Server::getInstance()->getLogger()->debug($blockIdentifier);
return $blockIdentifier;
}
#Server::getInstance()->getLogger()->debug($blockIdentifier . "[" . implode(",", $s) . "]");
return $blockIdentifier . "[" . implode(",", $s) . "]";
}
/**
* Prints all blocknames with states (without default states)
* @throws RuntimeException
*/
public static function printAllStates(): void
{
foreach (self::$legacyStateMap as $name => $v) {
foreach ($v as $meta => $legacyMapEntry) {
$currentoldName = $legacyMapEntry->getId();
$printedCompound = $legacyMapEntry->getBlockState()->getCompoundTag('states');
$bs = new BlockStatesEntry($currentoldName, $printedCompound);
try {
Server::getInstance()->getLogger()->debug(self::printStates($bs, true));
Server::getInstance()->getLogger()->debug((string)$bs);
} catch (RuntimeException $e) {
Server::getInstance()->getLogger()->logException($e);
}
}
}
}
public static function runTests(): void
{
var_dump("Running tests");
//testing blockstate parser
$tests = [
"minecraft:tnt",
#"minecraft:wood",
#"minecraft:log",
"minecraft:wooden_slab",
"minecraft:wooden_slab_wrongname",
"minecraft:wooden_slab[foo=bar]",
"minecraft:wooden_slab[top_slot_bit=]",
"minecraft:wooden_slab[top_slot_bit=true]",
"minecraft:wooden_slab[top_slot_bit=false]",
"minecraft:wooden_slab[wood_type=oak]",
#"minecraft:wooden_slab[wood_type=spruce]",
"minecraft:wooden_slab[wood_type=spruce,top_slot_bit=false]",
"minecraft:wooden_slab[wood_type=spruce,top_slot_bit=true]",
"minecraft:end_rod[]",
"minecraft:end_rod[facing_direction=1]",
"minecraft:end_rod[block_light_level=14]",
"minecraft:end_rod[block_light_level=13]",
"minecraft:light_block[block_light_level=14]",
"minecraft:stone[]",
"minecraft:stone[stone_type=granite]",
"minecraft:stone[stone_type=andesite]",
"minecraft:stone[stone_type=wrongtag]",//seems to just not find a block at all. neat!
#//alias testing
"minecraft:wooden_slab[top=true]",
"minecraft:wooden_slab[top=true,type=spruce]",
"minecraft:stone[type=granite]",
"minecraft:bedrock[burn=true]",
"minecraft:lever[direction=1]",
"minecraft:wheat[growth=3]",
"minecraft:stone_button[direction=1,pressed=true]",
"minecraft:stone_button[direction=0]",
"minecraft:stone_brick_stairs[direction=0]",
"minecraft:trapdoor[direction=0,open_bit=true,upside_down_bit=false]",
"minecraft:birch_door",
"minecraft:iron_door[direction=1]",
"minecraft:birch_door[upper_block_bit=true]",
"minecraft:birch_door[direction=1,door_hinge_bit=false,open_bit=false,upper_block_bit=true]",
"minecraft:birch_door[door_hinge_bit=false,open_bit=true,upper_block_bit=true]",
"minecraft:birch_door[direction=3,door_hinge_bit=false,open_bit=true,upper_block_bit=true]",
"minecraft:campfire",
];
foreach ($tests as $test) {
try {
Loader::getInstance()->getLogger()->debug(TF::GOLD . "Search query: " . TF::LIGHT_PURPLE . $test);
foreach (self::fromString($test) as $block) {
assert($block instanceof Block);
$blockStatesEntry = self::getStateByBlock($block);
Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . self::printStates($blockStatesEntry, true));
Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . self::printStates($blockStatesEntry, false));
Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "Final block: " . TF::AQUA . $block);
}
} catch (Exception $e) {
Server::getInstance()->getLogger()->debug($e->getMessage());
continue;
}
}
return;//TODO
//test flip+rotation
/** @noinspection PhpUnreachableStatementInspection */
// $tests2 = [
// #"minecraft:wooden_slab[wood_type=oak]",
// #"minecraft:wooden_slab[wood_type=spruce,top_slot_bit=true]",
// #"minecraft:end_rod[]",
// #"minecraft:end_rod[facing_direction=1]",
// #"minecraft:end_rod[facing_direction=2]",
// #"minecraft:stone_brick_stairs[direction=0]",
// #"minecraft:stone_brick_stairs[direction=1]",
// #"minecraft:stone_brick_stairs[direction=1,upside_down_bit=true]",
// #"stone_brick_stairs[direction=1,upside_down_bit=true]",
// #"minecraft:ladder[facing_direction=3]",
// #"minecraft:magenta_glazed_terracotta[facing_direction=2]",
// #"minecraft:trapdoor[direction=3,open_bit=true,upside_down_bit=false]",
// #"minecraft:birch_door",
// #"minecraft:birch_door[direction=1]",
// #"minecraft:birch_door[direction=1,door_hinge_bit=false,open_bit=false,upper_block_bit=true]",
// #"minecraft:birch_door[door_hinge_bit=false,open_bit=true,upper_block_bit=true]",
// "minecraft:birch_door[direction=3,door_hinge_bit=false,open_bit=true,upper_block_bit=true]",
// ];
// foreach ($tests2 as $test) {
// try {
// Server::getInstance()->getLogger()->debug(TF::GOLD . "Rotation query: " . TF::LIGHT_PURPLE . $test);
// $block = self::fromString($test)[0];
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "From block: " . TF::AQUA . $block);
// $state = self::getStateByBlock($block)->rotate(90);
// assert($state->toBlock() instanceof Block);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "Rotated block: " . TF::AQUA . $state->toBlock());
// Server::getInstance()->getLogger()->debug(TF::GOLD . "Mirror query x: " . TF::LIGHT_PURPLE . $test);
// $state = self::getStateByBlock($block)->mirror("x");
// assert($state->toBlock() instanceof Block);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "Flipped block x: " . TF::AQUA . $state->toBlock());
// Server::getInstance()->getLogger()->debug(TF::GOLD . "Mirror query y: " . TF::LIGHT_PURPLE . $test);
// $state = self::getStateByBlock($block)->mirror("y");
// assert($state->toBlock() instanceof Block);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . "Flipped block y: " . TF::AQUA . $state->toBlock());
// } catch (Exception $e) {
// Server::getInstance()->getLogger()->debug($e->getMessage());
// continue;
// }
// }
// //test doors because WTF they are weird
// try {
// for ($i = 0; $i < 15; $i++) {
// $block = BlockFactory::getInstance()->get(BlockLegacyIds::IRON_DOOR_BLOCK, $i);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . $block);
// $entry = self::getStateByBlock($block);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . $entry);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . $entry->blockStates);
// Server::getInstance()->getLogger()->debug(TF::LIGHT_PURPLE . self::printStates($entry, false));
// }
// } catch (Exception $e) {
// Server::getInstance()->getLogger()->debug($e->getMessage());
// }
}
public static function placeAllBlockstates(Position $position): void
{
$pasteY = $position->getFloorY();
$pasteX = $position->getFloorX();
$pasteZ = $position->getFloorZ();
$world = $position->getWorld();
$sorted = [];
foreach (self::$legacyStateMap as $name => $v) {
foreach ($v as $meta => $r12ToCurrentBlockMapEntry) {
try {
$sorted[] = (new BlockStatesEntry($name, $r12ToCurrentBlockMapEntry->getBlockState()->getCompoundTag('states')))->toBlock();
} catch (Exception $e) {
//skip blocks that pm does not know about
#$world->getServer()->broadcastMessage($e->getMessage());
}
}
}
$i = 0;
$limit = 50;
foreach ($sorted as $blockStatesEntry) {
/** @var BlockStatesEntry $blockStatesEntry */
$x = ($i % $limit) * 2;
$z = ($i - ($i % $limit)) / $limit * 2;
try {
$block = $blockStatesEntry->toBlock();
#if($block->getId() !== $id || $block->getMeta() !== $meta) var_dump("error, $id:$meta does not match {$block->getId()}:{$block->getMeta()}");
#$world->setBlock(new Vector3($pasteX + $x, $pasteY, $pasteZ + $z), $block);
$world->setBlockAt($pasteX + $x, $pasteY, $pasteZ + $z, $block, false);
} catch (Exception $e) {
$i++;
continue;
}
$i++;
}
var_dump("DONE");
}
/** @noinspection PhpUnusedPrivateMethodInspection */
private static function doorEquals(int $currentoldDamage, CompoundTag $defaultStatesNamedTag, CompoundTag $clonedPrintedCompound, CompoundTag $finalStatesList): bool
{
if (
/*(
$isUp &&
$currentoldDamage === 8 &&
$finalStatesList->getByte("door_hinge_bit") === $defaultStatesNamedTag->getByte("door_hinge_bit") &&
$finalStatesList->getByte("open_bit") === $defaultStatesNamedTag->getByte("open_bit") &&
$finalStatesList->getInt("direction") === $defaultStatesNamedTag->getInt("direction")
)
xor*/
(
#$finalStatesList->getByte("door_hinge_bit") === $clonedPrintedCompound->getByte("door_hinge_bit") &&
$finalStatesList->getByte("open_bit") === $clonedPrintedCompound->getByte("open_bit") &&
$finalStatesList->getInt("direction") === $clonedPrintedCompound->getInt("direction")
)
) return true;
return false;
}
/**
* Generates an alias map for blockstates
* Only call from main thread!
* @throws InvalidStateException
* @throws AssumptionFailedError
* @internal
* @noinspection PhpUnusedPrivateMethodInspection
*/
private static function generateBlockStateAliasMapJson(): void
{
Loader::getInstance()->saveResource("blockstate_alias_map.json");
$config = new Config(Loader::getInstance()->getDataFolder() . "blockstate_alias_map.json");
$config->setAll([]);
$config->save();
foreach (self::$legacyStateMap as $blockName => $v) {
foreach ($v as $meta => $legacyMapEntry) {
$states = clone $legacyMapEntry->getBlockState()->getCompoundTag('states');
foreach ($states as $stateName => $state) {
if (!$config->exists($stateName)) {
$alias = $stateName;
$fullReplace = [
"top" => "top",
"type" => "type",
"_age" => "age",
"age_" => "age",
"directions" => "vine_b",//hack for vine_directions => directions
"direction" => "direction",
"vine_b" => "directions",//hack for vine_directions => directions
"axis" => "axis",
"delay" => "delay",
"bite_counter" => "bites",
"count" => "count",
"pressed" => "pressed",
"upper_block" => "top",
"data" => "data",
"extinguished" => "off",
"color" => "color",
"block_light" => "light",
#"_lit"=>"lit",
#"lit_"=>"lit",
"liquid_depth" => "depth",
"upside_down" => "flipped",
"infiniburn" => "burn",
];
$partReplace = [
"_bit",
"piece",
"output_",
"level",
"amount",
"cauldron",
"allow",
"state",
"door",
"redstone",
"bamboo",
#"head",
"brewing_stand",
"item_frame",
"mushrooms",
"composter",
"coral",
"_2",
"_3",
"_4",
"end_portal",
];
foreach ($fullReplace as $stateAlias => $setTo)
if (strpos($alias, $stateAlias) !== false) {
$alias = $setTo;
}
foreach ($partReplace as $replace)
$alias = trim(trim(str_replace($replace, "", $alias), "_"));
$config->set($stateName, [
"alias" => [$alias],
]);
}
}
}
}
$all = $config->getAll();
/** @var array $all */
ksort($all);
$config->setAll($all);
$config->save();
unset($config);
}
/**
* Generates an alias map for blockstates
* Only call from main thread!
* @throws InvalidStateException
* @internal
*/
public static function generatePossibleStatesJson(): void
{
$config = new Config(Loader::getInstance()->getDataFolder() . "possible_blockstates.json");
$config->setAll([]);
$config->save();
$all = [];
foreach (self::$legacyStateMap as $blockName => $v) {
foreach ($v as $meta => $legacyMapEntry) {
$states = clone $legacyMapEntry->getBlockState()->getCompoundTag('states');
foreach ($states as $stateName => $state) {
if (!array_key_exists($stateName, $all)) {
$all[(string)$stateName] = [];
}
if (!in_array($state->getValue(), $all[$stateName], true)) {
$all[(string)$stateName][] = $state->getValue();
if (strpos($stateName, "_bit") !== false) {
var_dump("_bit");
} else {
var_dump("no _bit");
}
}
}
}
}
ksort($all);
$config->setAll($all);
$config->save();
unset($config);
}
/**
* Reads a value of an object, regardless of access modifiers
* @param object $object
* @param string $property
* @return mixed
*/
public static function &readAnyValue(object $object, string $property)
{
$invoke = Closure::bind(function & () use ($property) {
return $this->$property;
}, $object, $object)->__invoke();
/** @noinspection PhpUnnecessaryLocalVariableInspection */
$value = &$invoke;
return $value;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/Progress.php
================================================
progress = $progress;
$this->string = $info;
}
public function __toString()
{
return "Progress: " . $this->progress . " String: " . $this->string;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/Scoreboard.php
================================================
getPlayer();
if ($session->isSidebarEnabled()) {
ScoreFactory::setScore($player, Loader::PREFIX . TF::BOLD . TF::LIGHT_PURPLE . "Sidebar");
try {
if ($session->getLatestSelection() !== null) {
$line = 0;
$selection = $session->getLatestSelection();
ScoreFactory::setScoreLine($player, ++$line, TF::GOLD . $session->getLanguage()->translateString("spacer", ["Selection"]));
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Position: " . TF::RESET . "{$this->vecToString($selection->getPos1()->asVector3())} » {$this->vecToString($selection->getPos2()->asVector3())}");
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "World: " . TF::RESET . $selection->getWorld()->getFolderName());
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Shape: " . TF::RESET . (new ReflectionClass($selection->shape))->getShortName());
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Size: " . TF::RESET . "{$this->vecToString(new Vector3($selection->getSizeX(),$selection->getSizeY(),$selection->getSizeZ()))} ({$selection->getShape()->getTotalCount()})");
ScoreFactory::setScoreLine($player, ++$line, TF::GOLD . $session->getLanguage()->translateString("spacer", ["Settings"]));
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Tool Range: " . TF::RESET . Loader::getInstance()->getToolDistance());
$editLimit = Loader::getInstance()->getEditLimit();
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Limit: " . TF::RESET . ($editLimit === -1 ? $this->boolToString(false) : $editLimit));
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Wand Tool: " . TF::RESET . $this->boolToString($session->isWandEnabled()));
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Debug Tool: " . TF::RESET . $this->boolToString($session->isDebugToolEnabled()));
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "WAILA: " . TF::RESET . $this->boolToString($session->isWailaEnabled()));
if (($cb = $session->getCurrentClipboard()) instanceof SingleClipboard) {
ScoreFactory::setScoreLine($player, ++$line, TF::GOLD . $session->getLanguage()->translateString("spacer", ["Clipboard"]));
/** @var SingleClipboard $cb */
if ($cb->customName !== "")
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Name: " . TF::RESET . $cb->customName);
if ($cb->selection instanceof Selection) {
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Shape: " . TF::RESET . (new ReflectionClass($cb->selection->shape))->getShortName());
ScoreFactory::setScoreLine($player, ++$line, TF::ITALIC . "Size: " . TF::RESET . "{$this->vecToString(new Vector3($cb->selection->getSizeX(),$cb->selection->getSizeY(),$cb->selection->getSizeZ()))} ({$cb->getTotalCount()})");
}
}
//todo current block palette, schematics, brushes
}
} catch (BadFunctionCallException | OutOfBoundsException | ReflectionException $e) {
}
}
}
private function vecToString(Vector3 $v): string
{
return TF::RESET . "[" . TF::RED . $v->getFloorX() . TF::RESET . ":" . TF::GREEN . $v->getFloorY() . TF::RESET . ":" . TF::BLUE . $v->getFloorZ() . TF::RESET . "]";
}
private function boolToString(bool $b): string
{
return $b ? TF::RESET . TF::GREEN . "On" . TF::RESET : TF::RESET . TF::RED . "Off" . TF::RESET;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/SessionHelper.php
================================================
*/
private static $userSessions;
/** @var Map */
private static $pluginSessions;
public static function init(): void
{
if (!@mkdir($concurrentDirectory = Loader::getInstance()->getDataFolder() . "sessions") && !is_dir($concurrentDirectory)) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
}
self::$userSessions = new Map();
self::$pluginSessions = new Map();
}
/**
* @param Session $session
* @throws InvalidSkinException
*/
public static function addSession(Session $session): void
{
if ($session instanceof UserSession) {
self::$userSessions->put($session->getUUID(), $session);
if (!empty(Loader::getInstance()->donatorData) && (($player = $session->getPlayer())->hasPermission("we.donator") || in_array($player->getName(), Loader::getInstance()->donators))) {
$oldSkin = $player->getSkin();
$newSkin = new Skin($oldSkin->getSkinId(), $oldSkin->getSkinData(), Loader::getInstance()->donatorData, $oldSkin->getGeometryName(), $oldSkin->getGeometryData());
$player->setSkin($newSkin);
$player->sendSkin();
}
} else if ($session instanceof PluginSession) self::$pluginSessions->put($session->getUUID(), $session);
}
/**
* Destroys a session and removes it from cache. Saves to file if $save is true
* @param Session $session
* @param bool $save
* @throws JsonException
*/
public static function destroySession(Session $session, bool $save = true): void
{
if ($session instanceof UserSession) {
$session->cleanupInventory();
self::$userSessions->remove($session->getUUID());
} else if ($session instanceof PluginSession) self::$pluginSessions->remove($session->getUUID());
if ($save && $session instanceof UserSession) {
$session->save();
}
}
/**
* Creates an UserSession used to execute MagicWE2's functions
* @param Player $player
* @param bool $add If true, the session will be cached in SessionHelper
* @return UserSession
* @throws InvalidSkinException
* @throws RuntimeException
* @throws SessionException
*/
public static function createUserSession(Player $player, bool $add = true): UserSession
{
if (!$player->hasPermission("we.session")) throw new SessionException(TF::RED . "You do not have the permission \"magicwe.session\"");
$session = new UserSession($player);
if ($add) {
self::addSession($session);
(new MWESessionLoadEvent(Loader::getInstance(), $session))->call();
}
return $session;
}
/**
* Creates a PluginSession used to call API functions via a plugin
* @param Plugin $plugin
* @param bool $add If true, the session will be cached in SessionHelper
* @return PluginSession
* @throws InvalidSkinException
*/
public static function createPluginSession(Plugin $plugin, bool $add = true): PluginSession
{
$session = new PluginSession($plugin);
if ($add) self::addSession($session);
return $session;
}
/**
* @param Player $player
* @return bool
*/
public static function hasSession(Player $player): bool
{
try {
return self::getUserSession($player) instanceof UserSession;
} catch (SessionException $exception) {
return false;
}
}
/**
* @param Player $player
* @return null|UserSession
* @throws SessionException
*/
public static function getUserSession(Player $player): ?UserSession
{
if (self::$userSessions->isEmpty()) return null;
$filtered = self::$userSessions->filter(function (UUID $uuid, Session $session) use ($player) {
return $session instanceof UserSession && $session->getPlayer() === $player;
});
if ($filtered->isEmpty()) return null;
if (count($filtered) > 1) throw new SessionException("Multiple sessions found for player {$player->getName()}. This should never happen!");
return $filtered->values()->first();
}
/**
* TODO cleanup or optimize
* @param UUID $uuid
* @return null|Session
* @throws SessionException
*/
public static function getSessionByUUID(UUID $uuid): ?Session
{
$v = null;
if (self::$userSessions->hasKey($uuid)) {
$v = self::$userSessions->get($uuid, null);
} else if (self::$pluginSessions->hasKey($uuid)) {
$v = self::$pluginSessions->get($uuid, null);
} else {
/*
* Sadly, this part is necessary. If you use UUID::fromString, the object "id" in the map does not match anymore
*/
$userFiltered = self::$userSessions->filter(function (UUID $uuid2, Session $session) use ($uuid) {
return $uuid2->equals($uuid);
});
if (!$userFiltered->isEmpty()) $v = $userFiltered->values()->first();
else {
$pluginFiltered = self::$pluginSessions->filter(function (UUID $uuid2, Session $session) use ($uuid) {
return $uuid2->equals($uuid);
});
if (!$pluginFiltered->isEmpty()) $v = $pluginFiltered->values()->first();
}
}
if (!$v instanceof Session) throw new SessionException("Session with uuid {$uuid->toString()} not found");
return $v;
}
/**
* @return array|UserSession[]
*/
public static function getUserSessions(): array
{
return self::$userSessions->values()->toArray();
}
/**
* @return array|PluginSession[]
*/
public static function getPluginSessions(): array
{
return self::$pluginSessions->values()->toArray();
}
/**
* @param Player $player
* @return UserSession|null
* @throws AssumptionFailedError
* @throws InvalidSkinException
* @throws JsonException
* @throws RuntimeException
*/
public static function loadUserSession(Player $player): ?UserSession
{
$path = Loader::getInstance()->getDataFolder() . "sessions" . DIRECTORY_SEPARATOR .
$player->getName() . ".json";
if (!file_exists($path)) return null;
$contents = file_get_contents($path);
if ($contents === false) return null;
$data = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (is_null($data) || json_last_error() !== JSON_ERROR_NONE) {
Loader::getInstance()->getLogger()->error("Could not load user session from json file {$path}: " . json_last_error_msg());
#unlink($path);//TODO make safe
return null;
}
$session = new UserSession($player);
try {
$session->setUUID(UUID::fromString($data["uuid"]));
$session->setWandEnabled($data["wandEnabled"]);
$session->setDebugToolEnabled($data["debugToolEnabled"]);
$session->setWailaEnabled($data["wailaEnabled"]);
$session->setSidebarEnabled($data["sidebarEnabled"]);
$session->setLanguage($data["language"]);
foreach ($data["brushes"] as $brushUUID => $brushJson) {
try {
$properties = BrushProperties::fromJson($brushJson["properties"]);
$brush = new Brush($properties);
$session->addBrush($brush);
} catch (InvalidArgumentException $e) {
continue;
}
}
if (!is_null(($latestSelection = $data["latestSelection"] ?? null))) {
try {
$world = Server::getInstance()->getWorldManager()->getWorld($latestSelection["worldId"]);
if (is_null($world)) {
$session->sendMessage(TF::RED . "The world of the saved sessions selection is not loaded, the last selection was not restored.");//TODO translate better
} else {
$shapeClass = $latestSelection["shapeClass"] ?? Cuboid::class;
$pasteVector = $latestSelection["shape"]["pasteVector"];
unset($latestSelection["shape"]["pasteVector"]);
if (!is_null($pasteVector)) {
$pasteV = new Vector3(...array_values($pasteVector));
$shape = new $shapeClass($pasteV, ...array_values($latestSelection["shape"]));
}
$selection = new Selection(
$session->getUUID(),
Server::getInstance()->getWorldManager()->getWorld($latestSelection["worldId"]),
$latestSelection["pos1"]["x"],
$latestSelection["pos1"]["y"],
$latestSelection["pos1"]["z"],
$latestSelection["pos2"]["x"],
$latestSelection["pos2"]["y"],
$latestSelection["pos2"]["z"],
$shape ?? null
);
if ($selection instanceof Selection && $selection->isValid()) {
$session->addSelection($selection);
}
}
} catch (RuntimeException $e) {
}
}
//TODO clipboard
} catch (Exception $exception) {
return null;
}
self::addSession($session);
(new MWESessionLoadEvent(Loader::getInstance(), $session))->call();
return $session;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/StructureStore.php
================================================
getDataFolder() . 'structures');
@mkdir(Loader::getInstance()->getDataFolder() . 'schematics');
}
/**
* @param string $filename Filename without folder. Can have .mcstructure extension in the name
* @param bool $override Use this if you want to reload the file
* @return MCStructure
* @throws InvalidArgumentException
* @throws StructureFileException
* @throws StructureFormatException
*/
public function loadStructure(string $filename, bool $override = true): MCStructure
{
$id = pathinfo($filename, PATHINFO_FILENAME);
if (!$override && array_key_exists($id, $this->structures)) throw new InvalidArgumentException("Can not override $id");
$path = Loader::getInstance()->getDataFolder() . 'structures' . DIRECTORY_SEPARATOR . $id . '.mcstructure';//TODO redundant?
$structure = new MCStructure();
$structure->parse($path);
$this->structures[$id] = $structure;
return $this->structures[$id];
}
/**
* @param string $id
* @return MCStructure
* @throws InvalidArgumentException
*/
public function getStructure(string $id): MCStructure
{
$structure = $this->structures[$id] ?? null;
if ($structure === null) {
throw new InvalidArgumentException("Structure $id is not loaded");
}
return $structure;
}
/**
* @param string $filename Filename without folder. Can have .schematic extension in the name
* @param bool $override Use this if you want to reload the file
* @return Schematic
* @throws InvalidArgumentException
*/
public function loadSchematic(string $filename, bool $override = true): Schematic
{
$id = pathinfo($filename, PATHINFO_FILENAME);
if (!$override && array_key_exists($id, $this->schematics)) throw new InvalidArgumentException("Can not override $id");
$path = Loader::getInstance()->getDataFolder() . 'schematics' . DIRECTORY_SEPARATOR . $id . '.schematic';
$schematic = new Schematic();
$schematic->parse($path);
$this->schematics[$id] = $schematic;
return $this->schematics[$id];
}
/**
* @param string $id
* @return Schematic
* @throws InvalidArgumentException
*/
public function getSchematic(string $id): Schematic
{
$schematic = $this->schematics[$id] ?? null;
if ($schematic === null) {
throw new InvalidArgumentException("Structure $id is not loaded");
}
return $schematic;
}
}
================================================
FILE: src/xenialdan/MagicWE2/helper/blockstatesparsertest.log
================================================
2020-10-07 [20:44:07.359] [Server thread/DEBUG]: [MWE2] Search query: minecraft:tnt
2020-10-07 [20:44:07.365] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:tnt"
"states" => TAG_Compound: value={
"allow_underwater_bit" => TAG_Byte: value=0
"explode_bit" => TAG_Byte: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.365] [Server thread/DEBUG]: Final block: Block[TNT] (46:0)
2020-10-07 [20:44:07.366] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab
2020-10-07 [20:44:07.366] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=0
"wood_type" => TAG_String: value="oak"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.367] [Server thread/DEBUG]: Final block: Block[Oak Slab] (158:0)
2020-10-07 [20:44:07.367] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab_wrongname
2020-10-07 [20:44:07.368] [Server thread/DEBUG]: Unable to resolve "wooden_slab_wrongname" to a valid item
2020-10-07 [20:44:07.368] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[foo=bar]
2020-10-07 [20:44:07.371] [Server thread/DEBUG]: Invalid state foo
2020-10-07 [20:44:07.372] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[top_slot_bit=]
2020-10-07 [20:44:07.383] [Server thread/DEBUG]: Empty value for state top_slot_bit
2020-10-07 [20:44:07.384] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[top_slot_bit=true]
2020-10-07 [20:44:07.513] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=1
"wood_type" => TAG_String: value="oak"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.513] [Server thread/DEBUG]: Final block: Block[Oak Slab] (158:8)
2020-10-07 [20:44:07.513] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[top_slot_bit=false]
2020-10-07 [20:44:07.619] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=0
"wood_type" => TAG_String: value="oak"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.620] [Server thread/DEBUG]: Final block: Block[Oak Slab] (158:0)
2020-10-07 [20:44:07.620] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[wood_type=oak]
2020-10-07 [20:44:07.638] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=0
"wood_type" => TAG_String: value="oak"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.639] [Server thread/DEBUG]: Final block: Block[Oak Slab] (158:0)
2020-10-07 [20:44:07.639] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[wood_type=spruce,top_slot_bit=false]
2020-10-07 [20:44:07.650] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=0
"wood_type" => TAG_String: value="spruce"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.650] [Server thread/DEBUG]: Final block: Block[Spruce Slab] (158:1)
2020-10-07 [20:44:07.650] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[wood_type=spruce,top_slot_bit=true]
2020-10-07 [20:44:07.656] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=1
"wood_type" => TAG_String: value="spruce"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.656] [Server thread/DEBUG]: Final block: Block[Spruce Slab] (158:9)
2020-10-07 [20:44:07.657] [Server thread/DEBUG]: [MWE2] Search query: minecraft:end_rod[]
2020-10-07 [20:44:07.666] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:end_rod"
"states" => TAG_Compound: value={
"facing_direction" => TAG_Int: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.666] [Server thread/DEBUG]: Final block: Block[End Rod] (208:0)
2020-10-07 [20:44:07.666] [Server thread/DEBUG]: [MWE2] Search query: minecraft:end_rod[facing_direction=1]
2020-10-07 [20:44:07.671] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:end_rod"
"states" => TAG_Compound: value={
"facing_direction" => TAG_Int: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.671] [Server thread/DEBUG]: Final block: Block[End Rod] (208:1)
2020-10-07 [20:44:07.671] [Server thread/DEBUG]: [MWE2] Search query: minecraft:end_rod[block_light_level=14]
2020-10-07 [20:44:07.672] [Server thread/DEBUG]: Invalid state block_light_level
2020-10-07 [20:44:07.672] [Server thread/DEBUG]: [MWE2] Search query: minecraft:end_rod[block_light_level=13]
2020-10-07 [20:44:07.672] [Server thread/DEBUG]: Invalid state block_light_level
2020-10-07 [20:44:07.673] [Server thread/DEBUG]: [MWE2] Search query: minecraft:light_block[block_light_level=14]
2020-10-07 [20:44:07.673] [Server thread/DEBUG]: Unable to resolve "light_block" to a valid item
2020-10-07 [20:44:07.673] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone[]
2020-10-07 [20:44:07.730] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone"
"states" => TAG_Compound: value={
"stone_type" => TAG_String: value="stone"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.731] [Server thread/DEBUG]: Final block: Block[Stone] (1:0)
2020-10-07 [20:44:07.731] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone[stone_type=granite]
2020-10-07 [20:44:07.736] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone"
"states" => TAG_Compound: value={
"stone_type" => TAG_String: value="granite"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.736] [Server thread/DEBUG]: Final block: Block[Granite] (1:1)
2020-10-07 [20:44:07.736] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone[stone_type=andesite]
2020-10-07 [20:44:07.749] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone"
"states" => TAG_Compound: value={
"stone_type" => TAG_String: value="andesite"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.749] [Server thread/DEBUG]: Final block: Block[Andesite] (1:5)
2020-10-07 [20:44:07.749] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone[stone_type=wrongtag]
2020-10-07 [20:44:07.750] [Server thread/DEBUG]: No block minecraft:stone matching minecraft:stone[stone_type=wrongtag] could be found
2020-10-07 [20:44:07.750] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[top=true]
2020-10-07 [20:44:07.777] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=1
"wood_type" => TAG_String: value="oak"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.777] [Server thread/DEBUG]: Final block: Block[Oak Slab] (158:8)
2020-10-07 [20:44:07.777] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wooden_slab[top=true,type=spruce]
2020-10-07 [20:44:07.783] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:wooden_slab"
"states" => TAG_Compound: value={
"top_slot_bit" => TAG_Byte: value=1
"wood_type" => TAG_String: value="spruce"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.784] [Server thread/DEBUG]: Final block: Block[Spruce Slab] (158:9)
2020-10-07 [20:44:07.784] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone[type=granite]
2020-10-07 [20:44:07.794] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone"
"states" => TAG_Compound: value={
"stone_type" => TAG_String: value="granite"
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.794] [Server thread/DEBUG]: Final block: Block[Granite] (1:1)
2020-10-07 [20:44:07.794] [Server thread/DEBUG]: [MWE2] Search query: minecraft:bedrock[burn=true]
2020-10-07 [20:44:07.810] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:bedrock"
"states" => TAG_Compound: value={
"infiniburn_bit" => TAG_Byte: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.810] [Server thread/DEBUG]: Final block: Block[Bedrock] (7:1)
2020-10-07 [20:44:07.810] [Server thread/DEBUG]: [MWE2] Search query: minecraft:lever[direction=1]
2020-10-07 [20:44:07.811] [Server thread/DEBUG]: No block minecraft:lever matching minecraft:lever[direction=1] could be found
2020-10-07 [20:44:07.811] [Server thread/DEBUG]: [MWE2] Search query: minecraft:wheat[growth=3]
2020-10-07 [20:44:07.820] [Server thread/DEBUG]: Undefined offset: 3
2020-10-07 [20:44:07.820] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone_button[direction=1,pressed=true]
2020-10-07 [20:44:07.826] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone_button"
"states" => TAG_Compound: value={
"button_pressed_bit" => TAG_Byte: value=1
"facing_direction" => TAG_Int: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.826] [Server thread/DEBUG]: Final block: Block[Stone Button] (77:9)
2020-10-07 [20:44:07.827] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone_button[direction=0]
2020-10-07 [20:44:07.852] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone_button"
"states" => TAG_Compound: value={
"button_pressed_bit" => TAG_Byte: value=0
"facing_direction" => TAG_Int: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.852] [Server thread/DEBUG]: Final block: Block[Stone Button] (77:0)
2020-10-07 [20:44:07.853] [Server thread/DEBUG]: [MWE2] Search query: minecraft:stone_brick_stairs[direction=0]
2020-10-07 [20:44:07.858] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:stone_brick_stairs"
"states" => TAG_Compound: value={
"upside_down_bit" => TAG_Byte: value=0
"weirdo_direction" => TAG_Int: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.859] [Server thread/DEBUG]: Final block: Block[Stone Brick Stairs] (109:0)
2020-10-07 [20:44:07.859] [Server thread/DEBUG]: [MWE2] Search query: minecraft:trapdoor[direction=0,open_bit=true,upside_down_bit=false]
2020-10-07 [20:44:07.874] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:trapdoor"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"open_bit" => TAG_Byte: value=1
"upside_down_bit" => TAG_Byte: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.874] [Server thread/DEBUG]: Final block: Block[Oak Trapdoor] (96:8)
2020-10-07 [20:44:07.874] [Server thread/DEBUG]: [MWE2] Search query: minecraft:birch_door
2020-10-07 [20:44:07.875] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:birch_door"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"door_hinge_bit" => TAG_Byte: value=0
"open_bit" => TAG_Byte: value=0
"upper_block_bit" => TAG_Byte: value=0
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.875] [Server thread/DEBUG]: Final block: Block[Birch Door] (194:0)
2020-10-07 [20:44:07.875] [Server thread/DEBUG]: [MWE2] Search query: minecraft:iron_door[direction=1]
2020-10-07 [20:44:07.876] [Server thread/DEBUG]: No block minecraft:iron_door matching minecraft:iron_door[direction=1] could be found
2020-10-07 [20:44:07.876] [Server thread/DEBUG]: [MWE2] Search query: minecraft:birch_door[upper_block_bit=true]
2020-10-07 [20:44:07.877] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:birch_door"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"door_hinge_bit" => TAG_Byte: value=0
"open_bit" => TAG_Byte: value=0
"upper_block_bit" => TAG_Byte: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.877] [Server thread/DEBUG]: Final block: Block[Birch Door] (194:8)
2020-10-07 [20:44:07.877] [Server thread/DEBUG]: [MWE2] Search query: minecraft:birch_door[direction=1,door_hinge_bit=false,open_bit=false,upper_block_bit=true]
2020-10-07 [20:44:07.881] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:birch_door"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"door_hinge_bit" => TAG_Byte: value=0
"open_bit" => TAG_Byte: value=0
"upper_block_bit" => TAG_Byte: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.882] [Server thread/DEBUG]: Final block: Block[Birch Door] (194:8)
2020-10-07 [20:44:07.882] [Server thread/DEBUG]: [MWE2] Search query: minecraft:birch_door[door_hinge_bit=false,open_bit=true,upper_block_bit=true]
2020-10-07 [20:44:07.883] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:birch_door"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"door_hinge_bit" => TAG_Byte: value=0
"open_bit" => TAG_Byte: value=0
"upper_block_bit" => TAG_Byte: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.883] [Server thread/DEBUG]: Final block: Block[Birch Door] (194:8)
2020-10-07 [20:44:07.883] [Server thread/DEBUG]: [MWE2] Search query: minecraft:birch_door[direction=3,door_hinge_bit=false,open_bit=true,upper_block_bit=true]
2020-10-07 [20:44:07.885] [Server thread/DEBUG]: TAG_Compound: value={
"name" => TAG_String: value="minecraft:birch_door"
"states" => TAG_Compound: value={
"direction" => TAG_Int: value=0
"door_hinge_bit" => TAG_Byte: value=0
"open_bit" => TAG_Byte: value=0
"upper_block_bit" => TAG_Byte: value=1
}
"version" => TAG_Int: value=17825806
}
2020-10-07 [20:44:07.885] [Server thread/DEBUG]: Final block: Block[Birch Door] (194:8)
================================================
FILE: src/xenialdan/MagicWE2/selection/Selection.php
================================================
sessionUUID = $sessionUUID;
$this->worldId = $world->getId();
if (isset($minX, $minY, $minZ)) {
$this->pos1 = (new Vector3($minX, $minY, $minZ))->floor();
}
if (isset($maxX, $maxY, $maxZ)) {
$this->pos2 = (new Vector3($maxX, $maxY, $maxZ))->floor();
}
if ($shape !== null) $this->shape = $shape;
$this->setUUID(UUID::fromRandom());
}
/**
* @return World
* @throws Exception
*/
public function getWorld(): World
{
if (is_null($this->worldId)) {
throw new SelectionException("World is not set!");
}
$world = Server::getInstance()->getWorldManager()->getWorld($this->worldId);
if (is_null($world)) {
throw new SelectionException("World is not found!");
}
return $world;
}
/**
* @param World $world
*/
public function setWorld(World $world): void
{
$this->worldId = $world->getId();
try {
($ev = new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_WORLD))->call();
} catch (RuntimeException $e) {
}
}
/**
* @return Position
* @throws Exception
*/
public function getPos1(): Position
{
if (is_null($this->pos1)) {
throw new SelectionException("Position 1 is not set!");
}
return Position::fromObject($this->pos1, $this->getWorld());
}
/**
* @param Position $position
* @throws AssumptionFailedError
*/
public function setPos1(Position $position): void
{
$this->pos1 = $position->asVector3()->floor();
if ($this->pos1->y >= World::Y_MAX) $this->pos1->y = World::Y_MAX;
if ($this->pos1->y < 0) $this->pos1->y = 0;
if ($this->worldId !== $position->getWorld()->getId()) {//reset other position if in different world
$this->pos2 = null;
}
$this->setWorld($position->getWorld());
if (($this->shape instanceof Cuboid || $this->shape === null) && $this->isValid())//TODO test change
$this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2));
try {
$session = SessionHelper::getSessionByUUID($this->sessionUUID);
if ($session instanceof Session) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('selection.pos1.set', [$this->pos1->getX(), $this->pos1->getY(), $this->pos1->getZ()]));
try {
($ev = new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_POS1))->call();
} catch (RuntimeException $e) {
}
}
} catch (SessionException $e) {
//TODO log? kick?
}
}
/**
* @return Position
* @throws Exception
*/
public function getPos2(): Position
{
if (is_null($this->pos2)) {
throw new SelectionException("Position 2 is not set!");
}
return Position::fromObject($this->pos2, $this->getWorld());
}
/**
* @param Position $position
* @throws AssumptionFailedError
*/
public function setPos2(Position $position): void
{
$this->pos2 = $position->asVector3()->floor();
if ($this->pos2->y >= World::Y_MAX) $this->pos2->y = World::Y_MAX;
if ($this->pos2->y < 0) $this->pos2->y = 0;
if ($this->worldId !== $position->getWorld()->getId()) {
$this->pos1 = null;
}
$this->setWorld($position->getWorld());
if (($this->shape instanceof Cuboid || $this->shape === null) && $this->isValid())
$this->setShape(Cuboid::constructFromPositions($this->pos1, $this->pos2));
try {
$session = SessionHelper::getSessionByUUID($this->sessionUUID);
if ($session instanceof Session) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('selection.pos2.set', [$this->pos2->getX(), $this->pos2->getY(), $this->pos2->getZ()]));
try {
($ev = new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_POS2))->call();
} catch (RuntimeException $e) {
}
}
} catch (SessionException $e) {
//TODO log? kick?
}
}
/**
* @return Shape
* @throws Exception
*/
public function getShape(): Shape
{
if (!$this->shape instanceof Shape) throw new SelectionException("Shape is not valid");
return $this->shape;
}
/**
* @param Shape $shape
*/
public function setShape(Shape $shape): void
{
$this->shape = $shape;
try {
($ev = new MWESelectionChangeEvent($this, MWESelectionChangeEvent::TYPE_SHAPE))->call();
} catch (RuntimeException $e) {
}//might cause duplicated call
}
/**
* Checks if a Selection is valid. It is not valid if:
* - The world is not set
* - Any of the positions are not set
* - The shape is not set / not a shape
* - The positions are not in the same world
* @return bool
*/
public function isValid(): bool
{
try {
#$this->getShape();
$this->getWorld();
$this->getPos1();
$this->getPos2();
} catch (Exception $e) {
return false;
}
return true;
}
/**
* @return int
*/
public function getSizeX(): int
{
return (int)(abs($this->pos1->x - $this->pos2->x) + 1);
}
/**
* @return int
*/
public function getSizeY(): int
{
return (int)(abs($this->pos1->y - $this->pos2->y) + 1);
}
/**
* @return int
*/
public function getSizeZ(): int
{
return (int)(abs($this->pos1->z - $this->pos2->z) + 1);
}
/**
* @param UUID $uuid
*/
public function setUUID(UUID $uuid): void
{
$this->uuid = $uuid;
}
/**
* @return UUID
*/
public function getUUID(): UUID
{
return $this->uuid;
}
/**
* String representation of object
* @link http://php.net/manual/en/serializable.serialize.php
* @return string the string representation of the object or null
* @since 5.1.0
*/
public function serialize()
{
return serialize([
$this->worldId,
$this->pos1,
$this->pos2,
$this->uuid,
$this->sessionUUID,
$this->shape
]);
}
/**
* Constructs the object
* @link http://php.net/manual/en/serializable.unserialize.php
* @param string $serialized
* The string representation of the object.
*
* @return void
* @since 5.1.0
* @noinspection PhpMissingParamTypeInspection
*/
public function unserialize($serialized)
{
var_dump($serialized);
/** @var Vector3 $pos1 , $pos2 */
[
$this->worldId,
$this->pos1,
$this->pos2,
$this->uuid,
$this->sessionUUID,
$this->shape
] = unserialize($serialized/*, ['allowed_classes' => [__CLASS__, Vector3::class,UUID::class,Shape::class]]*/);//TODO test pm4
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by json_encode,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
$arr = (array)$this;
if ($this->shape !== null)
$arr["shapeClass"] = get_class($this->shape);
return $arr;
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Cone.php
================================================
pasteVector = $pasteVector;
$this->height = $height;
$this->diameter = $diameter;
$this->flipped = $flipped;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$reducePerLayer = ($this->diameter / $this->height);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) {
for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) {
for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
$vec3 = new Vector3($x, $y, $z);
if ($this->flipped)
$radiusLayer = ($this->diameter - $reducePerLayer * ($this->height - $ry)) / 2;
else
$radiusLayer = ($this->diameter - $reducePerLayer * $ry) / 2;
if ($vec2->distanceSquared($centerVec2) > ($radiusLayer ** 2) || (API::hasFlag($flags, API::FLAG_HOLLOW_CLOSED) && ($ry !== 0 && $ry !== $this->height - 1) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2))))
continue;
$block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO fuufufufuuu
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) {
for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
if ($vec2->distanceSquared($centerVec2) > (($this->diameter / 2) ** 2) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2))))
continue;
yield $vec2;
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{//TODO optimize to remove "corner" chunks
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
floor($this->pasteVector->x - $this->diameter / 2),
$this->pasteVector->y,
floor($this->pasteVector->z - $this->diameter / 2),
-1 + floor($this->pasteVector->x - $this->diameter / 2) + $this->diameter,
-1 + $this->pasteVector->y + $this->height,
-1 + floor($this->pasteVector->z - $this->diameter / 2) + $this->diameter
);
}
public function getTotalCount(): int
{
return (int)ceil((M_PI * (($this->diameter / 2) ** 2) * $this->height) / 3);
}
public static function getName(): string
{
return "Cone";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Cube.php
================================================
pasteVector = $pasteVector;
$this->width = $width;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
for ($x = (int)floor($this->getMinVec3()->x), $rx = 0; $x <= floor($this->getMaxVec3()->x); $x++, $rx++) {
for ($y = (int)floor($this->getMinVec3()->y), $ry = 0; $y <= floor($this->getMaxVec3()->y); $y++, $ry++) {
for ($z = (int)floor($this->getMinVec3()->z), $rz = 0; $z <= floor($this->getMaxVec3()->z); $z++, $rz++) {
$block = API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO check for removal because relative might be at other y
if (API::hasFlag($flags, API::FLAG_HOLLOW) && ($block->getPos()->x > $this->getMinVec3()->getX() && $block->getPos()->x < $this->getMaxVec3()->getX()) && ($block->getPos()->y > $this->getMinVec3()->getY() && $block->getPos()->y < $this->getMaxVec3()->getY()) && ($block->getPos()->z > $this->getMinVec3()->getZ() && $block->getPos()->z < $this->getMaxVec3()->getZ())) continue;
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
for ($x = (int)floor($this->getMinVec3()->x); $x <= floor($this->getMaxVec3()->x); $x++) {
for ($z = (int)floor($this->getMinVec3()->z); $z <= floor($this->getMaxVec3()->z); $z++) {
yield new Vector2($x, $z);
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
ceil($this->pasteVector->x - $this->width / 2),
$this->pasteVector->y,
ceil($this->pasteVector->z - $this->width / 2),
-1 + ceil($this->pasteVector->x - $this->width / 2) + $this->width,
-1 + $this->pasteVector->y + $this->width,
-1 + ceil($this->pasteVector->z - $this->width / 2) + $this->width
);
}
public function getTotalCount(): int
{
return $this->width ** 3;
}
public static function getName(): string
{
return "Cube";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Cuboid.php
================================================
pasteVector = $pasteVector;
$this->width = $width;
$this->height = $height;
$this->depth = $depth;
}
public static function constructFromPositions(Vector3 $pos1, Vector3 $pos2): self
{
$width = (int)abs($pos1->getX() - $pos2->getX()) + 1;
$height = (int)abs($pos1->getY() - $pos2->getY()) + 1;
$depth = (int)abs($pos1->getZ() - $pos2->getZ()) + 1;
return new Cuboid((new Vector3(($pos1->x + $pos2->x) / 2, min($pos1->y, $pos2->y), ($pos1->z + $pos2->z) / 2)), $width, $height, $depth);
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
for ($x = (int)floor($this->getMinVec3()->x); $x <= floor($this->getMaxVec3()->x); $x++) {
for ($y = (int)floor($this->getMinVec3()->y); $y <= floor($this->getMaxVec3()->y); $y++) {
for ($z = (int)floor($this->getMinVec3()->z); $z <= floor($this->getMaxVec3()->z); $z++) {
$block = API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z);
#var_dump("shape getblocks", $block);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO check for removal because relative might be at other y
if (API::hasFlag($flags, API::FLAG_HOLLOW) && ($block->getPos()->x > $this->getMinVec3()->getX() && $block->getPos()->x < $this->getMaxVec3()->getX()) && ($block->getPos()->y > $this->getMinVec3()->getY() && $block->getPos()->y < $this->getMaxVec3()->getY()) && ($block->getPos()->z > $this->getMinVec3()->getZ() && $block->getPos()->z < $this->getMaxVec3()->getZ())) continue;
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
for ($x = (int)floor($this->getMinVec3()->x); $x <= floor($this->getMaxVec3()->x); $x++) {
for ($z = (int)floor($this->getMinVec3()->z); $z <= floor($this->getMaxVec3()->z); $z++) {
yield new Vector2($x, $z);
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
ceil($this->pasteVector->x - $this->width / 2),
$this->pasteVector->y,
ceil($this->pasteVector->z - $this->depth / 2),
-1 + ceil($this->pasteVector->x - $this->width / 2) + $this->width,
-1 + $this->pasteVector->y + $this->height,
-1 + ceil($this->pasteVector->z - $this->depth / 2) + $this->depth
);
}
/**
* @return int
*/
public function getTotalCount(): int
{
return $this->width * $this->height * $this->depth;
}
public static function getName(): string
{
return "Cuboid";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Custom.php
================================================
pasteVector = $pasteVector;
$this->positions = $positions;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
foreach ($this->positions as $position) {
//TODO filterblocks
yield API::setComponents($manager->getBlockAt($position->getFloorX(), $position->getFloorY(), $position->getFloorZ()), (int)$position->x, (int)$position->y, (int)$position->z);
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
/* Mapping: $walked[$hash]=true */
$walked = [];
foreach ($this->positions as $position) {
$hash = World::chunkHash($position->getFloorX(), $position->getFloorZ());
if (isset($walked[$hash])) continue;
$walked[$hash] = true;
yield new Vector2($position->x, $position->z);
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{
$this->validateChunkManager($manager);
$touchedChunks = [];
foreach ($this->getLayer($manager) as $vector2) {
$x = $vector2->getFloorX() >> 4;
$z = $vector2->getFloorY() >> 4;
if (isset($touchedChunks[World::chunkHash($x, $z)]) || ($chunk = $manager->getChunk($x, $z)) === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
$minX = $maxX = $minY = $maxY = $minZ = $maxZ = null;
foreach ($this->positions as $position) {
if (is_null($minX)) {
$minX = $maxX = $position->x;
$minY = $maxY = $position->y;
$minZ = $maxZ = $position->z;
continue;
}
$minX = min($minX, $position->x);
$minY = min($minY, $position->y);
$minZ = min($minZ, $position->z);
$maxX = max($maxX, $position->x);
$maxY = max($maxY, $position->y);
$maxZ = max($maxZ, $position->z);
}
return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
}
public function getTotalCount(): int
{
return count($this->positions);
}
public static function getName(): string
{
return "Custom";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Cylinder.php
================================================
pasteVector = $pasteVector;
$this->height = $height;
$this->diameter = $diameter;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) {
for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) {
for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
$vec3 = new Vector3($x, $y, $z);
if ($vec2->distanceSquared($centerVec2) > (($this->diameter / 2) ** 2) || (API::hasFlag($flags, API::FLAG_HOLLOW_CLOSED) && ($ry !== 0 && $ry !== $this->height - 1) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2)) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2))))
continue;
$block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO fuufufufuuu
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) {
for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
if ($vec2->distanceSquared($centerVec2) > (($this->diameter / 2) ** 2) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2))))
continue;
yield $vec2;
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{//TODO optimize to remove "corner" chunks
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
floor($this->pasteVector->x - $this->diameter / 2),
$this->pasteVector->y,
floor($this->pasteVector->z - $this->diameter / 2),
-1 + floor($this->pasteVector->x - $this->diameter / 2) + $this->diameter,
-1 + $this->pasteVector->y + $this->height,
-1 + floor($this->pasteVector->z - $this->diameter / 2) + $this->diameter
);
}
public function getTotalCount(): int
{
return (int)ceil(M_PI * (($this->diameter / 2) ** 2) * $this->height);
}
public static function getName(): string
{
return "Cylinder";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Ellipsoid.php
================================================
pasteVector = $pasteVector;
$this->width = $width;
$this->height = $height;
$this->depth = $depth;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
$this->pasteVector = $this->getPasteVector()->add(0, -0.5, 0);
$xrad = $this->width / 2;
$yrad = $this->height / 2;
$zrad = $this->depth / 2;
$xradSquared = $xrad ** 2;
$yradSquared = $yrad ** 2;
$zradSquared = $zrad ** 2;
$targetX = $this->pasteVector->getX();
$targetY = $this->pasteVector->getY();
$targetZ = $this->pasteVector->getZ();
for ($x = (int)floor($centerVec2->x - $this->width / 2 /*- 1*/); $x <= floor($centerVec2->x + $this->width / 2 /*+ 1*/); $x++) {
$xSquared = ($targetX - $x) ** 2;
for ($y = (int)floor($this->getPasteVector()->y) + 1, $ry = 0; $y <= floor($this->getPasteVector()->y + $this->height); $y++, $ry++) {
$ySquared = ($targetY - $y + $yrad) ** 2;
for ($z = (int)floor($centerVec2->y - $this->depth / 2 /*- 1*/); $z <= floor($centerVec2->y + $this->depth / 2 /*+ 1*/); $z++) {
$zSquared = ($targetZ - $z) ** 2;
$vec3 = new Vector3($x, $y, $z);
//TODO hollow
if ($xSquared / $xradSquared + $ySquared / $yradSquared + $zSquared / $zradSquared >= 1) continue;
$block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO fuufufufuuu
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
$xrad = $this->width / 2;
$zrad = $this->depth / 2;
$xradSquared = $xrad ** 2;
$zradSquared = $zrad ** 2;
$targetX = $this->pasteVector->getX();
$targetZ = $this->pasteVector->getZ();
for ($x = (int)floor($centerVec2->x - $this->width / 2 /*- 1*/); $x <= floor($centerVec2->x + $this->width / 2 /*+ 1*/); $x++) {
$xSquared = ($targetX - $x) ** 2;
for ($z = (int)floor($centerVec2->y - $this->depth / 2 /*- 1*/); $z <= floor($centerVec2->y + $this->depth / 2 /*+ 1*/); $z++) {
$zSquared = ($targetZ - $z) ** 2;
if ($xSquared / $xradSquared + $zSquared / $zradSquared >= 1) continue;
//TODO hollow
yield new Vector2($x, $z);
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{//TODO optimize to remove "corner" chunks
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX - 1; $x <= $maxX + 1; $x++) {
for ($z = $minZ - 1; $z <= $maxZ + 1; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
floor($this->pasteVector->x - $this->width / 2),
$this->pasteVector->y,
floor($this->pasteVector->z - $this->depth / 2),
-1 + floor($this->pasteVector->x - $this->width / 2) + $this->width,
-1 + $this->pasteVector->y + $this->height,
-1 + floor($this->pasteVector->z - $this->depth / 2) + $this->depth
);
}
public function getTotalCount(): int
{
return (int)floor(4 * M_PI * (($this->width / 2) + 1) * (($this->height / 2) + 1) * (($this->depth / 2) + 1) / 3);
}
public static function getName(): string
{
return "Ellipsoid";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Pyramid.php
================================================
pasteVector = $pasteVector;
$this->width = $width;
$this->height = $height;
$this->depth = $depth;
$this->flipped = $flipped;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$reduceXPerLayer = -($this->width / $this->height);
$reduceZPerLayer = -($this->depth / $this->height);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++) {
for ($y = (int)floor($this->getPasteVector()->y), $ry = 0; $y < floor($this->getPasteVector()->y + $this->height); $y++, $ry++) {
for ($z = (int)floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
$vec3 = new Vector3($x, $y, $z);
if ($this->flipped) {
$radiusLayerX = ($this->width + $reduceXPerLayer * ($this->height - $ry)) / 2;
$radiusLayerZ = ($this->depth + $reduceZPerLayer * ($this->height - $ry)) / 2;
} else {
$radiusLayerX = ($this->width + $reduceXPerLayer * $ry) / 2;
$radiusLayerZ = ($this->depth + $reduceZPerLayer * $ry) / 2;
}
//TODO hollow
if (floor(abs($centerVec2->x - $vec2->x)) >= $radiusLayerX || floor(abs($centerVec2->y - $vec2->y)) >= $radiusLayerZ)
continue;
$block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO fuufufufuuu
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->width / 2 - 1); $x <= floor($centerVec2->x + $this->width / 2 + 1); $x++) {
for ($z = (int)floor($centerVec2->y - $this->depth / 2 - 1); $z <= floor($centerVec2->y + $this->depth / 2 + 1); $z++) {
//TODO hollow
yield new Vector2($x, $z);
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{//TODO optimize to remove "corner" chunks
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
floor($this->pasteVector->x - $this->width / 2),
$this->pasteVector->y,
floor($this->pasteVector->z - $this->depth / 2),
-1 + floor($this->pasteVector->x - $this->width / 2) + $this->width,
-1 + $this->pasteVector->y + $this->height,
-1 + floor($this->pasteVector->z - $this->depth / 2) + $this->depth
);
}
public function getTotalCount(): int
{
return (int)ceil((1 / 3) * ($this->width * $this->depth) * $this->height);
}
public static function getName(): string
{
return "Pyramid";
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/Shape.php
================================================
pasteVector;
}
public function setPasteVector(Vector3 $pasteVector): void
{
$this->pasteVector = $pasteVector->asVector3();
}
/**
* Creates a chunk manager used for async editing
* @param Chunk[] $chunks
* @return AsyncChunkManager
*/
public static function getChunkManager(array $chunks): AsyncChunkManager
{
$manager = new AsyncChunkManager();
foreach ($chunks as $hash => $chunk) {
World::getXZ($hash, $chunkX, $chunkZ);
$manager->setChunk($chunkX, $chunkZ, $chunk);
}
return $manager;
}
/**
* @param mixed $manager
* @throws InvalidArgumentException
*/
public function validateChunkManager($manager): void
{
if (!$manager instanceof World && !$manager instanceof AsyncChunkManager) throw new InvalidArgumentException(get_class($manager) . " is not an instance of World or AsyncChunkManager");
}
abstract public function getTotalCount(): int;
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
abstract public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator;
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
abstract public function getLayer($manager, int $flags = API::FLAG_BASE): Generator;
/**
* @param ChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
abstract public function getTouchedChunks(ChunkManager $manager): array;
abstract public function getAABB(): AxisAlignedBB;
/**
* @return Vector3
*/
public function getMinVec3(): Vector3
{
return new Vector3($this->getAABB()->minX, $this->getAABB()->minY, $this->getAABB()->minZ);
}
/**
* @return Vector3
*/
public function getMaxVec3(): Vector3
{
return new Vector3($this->getAABB()->maxX, $this->getAABB()->maxY, $this->getAABB()->maxZ);
}
abstract public static function getName(): string;
public function getShapeProperties(): array
{
return array_diff(get_object_vars($this), get_class_vars(__CLASS__));
}
/**
* String representation of object
* @link http://php.net/manual/en/serializable.serialize.php
* @return string the string representation of the object or null
* @since 5.1.0
*/
public function serialize()
{
return serialize((array)$this);
}
/**
* Constructs the object
* @link http://php.net/manual/en/serializable.unserialize.php
* @param string $serialized
* The string representation of the object.
*
* @return void
* @since 5.1.0
* @noinspection PhpMissingParamTypeInspection
*/
public function unserialize($serialized)
{
$unserialize = unserialize($serialized/*, ['allowed_classes' => [__CLASS__]]*/);//TODO test pm4
array_walk($unserialize, function ($value, $key) {
$this->$key = $value;
});
}
}
================================================
FILE: src/xenialdan/MagicWE2/selection/shape/ShapeRegistry.php
================================================
pasteVector = $pasteVector;
$this->diameter = $diameter;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
for ($x = (int)floor($this->pasteVector->x - $this->diameter / 2 - 1); $x <= floor($this->pasteVector->x + $this->diameter / 2 + 1); $x++) {
for ($y = (int)floor($this->pasteVector->y - $this->diameter / 2 - 1); $y <= floor($this->pasteVector->y + $this->diameter / 2 + 1); $y++) {
for ($z = (int)floor($this->pasteVector->z - $this->diameter / 2 - 1); $z <= floor($this->pasteVector->z + $this->diameter / 2 + 1); $z++) {
$vec3 = new Vector3($x, $y, $z);
if ($vec3->distanceSquared($this->getPasteVector()) > (($this->diameter / 2) ** 2) || (API::hasFlag($flags, API::FLAG_HOLLOW) && $vec3->distanceSquared($this->getPasteVector()) <= ((($this->diameter / 2) - 1) ** 2)))
continue;
$block = API::setComponents($manager->getBlockAt($vec3->getFloorX(), $vec3->getFloorY(), $vec3->getFloorZ()), (int)$vec3->x, (int)$vec3->y, (int)$vec3->z);
if (API::hasFlag($flags, API::FLAG_KEEP_BLOCKS) && $block->getId() !== BlockLegacyIds::AIR) continue;
if (API::hasFlag($flags, API::FLAG_KEEP_AIR) && $block->getId() === BlockLegacyIds::AIR) continue;
if ($block->getPos()->y >= World::Y_MAX || $block->getPos()->y < 0) continue;//TODO fufufufuuu
if (empty($filterblocks)) yield $block;
else {
foreach ($filterblocks as $filterblock) {
if (($block->getId() === $filterblock->getId()) && ((API::hasFlag($flags, API::FLAG_VARIANT) && $block->getIdInfo()->getVariant() === $filterblock->getIdInfo()->getVariant()) || (!API::hasFlag($flags, API::FLAG_VARIANT) && ($block->getMeta() === $filterblock->getMeta() || API::hasFlag($flags, API::FLAG_KEEP_META)))))
yield $block;
}
}
}
}
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$centerVec2 = new Vector2($this->getPasteVector()->getX(), $this->getPasteVector()->getZ());
for ($x = (int)floor($centerVec2->x - $this->diameter / 2 - 1); $x <= floor($centerVec2->x + $this->diameter / 2 + 1); $x++) {
for ($z = (int)floor($centerVec2->y - $this->diameter / 2 - 1); $z <= floor($centerVec2->y + $this->diameter / 2 + 1); $z++) {
$vec2 = new Vector2($x, $z);
if ($vec2->distanceSquared($centerVec2) > (($this->diameter / 2) ** 2) || ((API::hasFlag($flags, API::FLAG_HOLLOW) && $vec2->distanceSquared($centerVec2) <= ((($this->diameter / 2) - 1) ** 2))))
continue;
yield $vec2;
}
}
}
/**
* @param World|AsyncChunkManager $manager
* @return string[] fastSerialized chunks
* @throws Exception
*/
public function getTouchedChunks($manager): array
{//TODO optimize to remove "corner" chunks
$this->validateChunkManager($manager);
$maxX = ($this->getMaxVec3()->x + 1) >> 4;
$minX = $this->getMinVec3()->x >> 4;
$maxZ = ($this->getMaxVec3()->z + 1) >> 4;
$minZ = $this->getMinVec3()->z >> 4;
$touchedChunks = [];
for ($x = $minX; $x <= $maxX; $x++) {
for ($z = $minZ; $z <= $maxZ; $z++) {
$chunk = $manager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;
return $touchedChunks;
}
public function getAABB(): AxisAlignedBB
{
return new AxisAlignedBB(
floor($this->pasteVector->x - $this->diameter / 2),
$this->pasteVector->y,
floor($this->pasteVector->z - $this->diameter / 2),
-1 + floor($this->pasteVector->x - $this->diameter / 2) + $this->diameter,
-1 + $this->pasteVector->y + $this->diameter,
-1 + floor($this->pasteVector->z - $this->diameter / 2) + $this->diameter
);
}
public function getTotalCount(): int
{
return (int)ceil((4 / 3) * M_PI * (($this->diameter / 2) ** 3));
}
public static function getName(): string
{
return "Sphere";
}
}
================================================
FILE: src/xenialdan/MagicWE2/session/PluginSession.php
================================================
plugin = $plugin;
$this->setUUID(UUID::fromRandom());
$this->undoHistory = new Deque();
$this->redoHistory = new Deque();
}
public function getPlugin(): Plugin
{
return $this->plugin;
}
public function __toString()
{
return __CLASS__ .
" UUID: " . $this->getUUID()->__toString() .
" Plugin: " . $this->getPlugin()->getName() .
" Selections: " . count($this->getSelections()) .
" Latest: " . $this->getLatestSelectionUUID() .
" Clipboards: " . count($this->getClipboards()) .
" Current: " . $this->getCurrentClipboardIndex() .
" Undos: " . count($this->undoHistory) .
" Redos: " . count($this->redoHistory);
}
public function sendMessage(string $message): void
{
$this->plugin->getLogger()->info(Loader::PREFIX . $message);
}
}
================================================
FILE: src/xenialdan/MagicWE2/session/Session.php
================================================
*/
public $undoHistory;
/** @var Deque */
public $redoHistory;
/**
* @return UUID
*/
public function getUUID(): UUID
{
return $this->uuid;
}
/**
* @param UUID $uuid
*/
public function setUUID(UUID $uuid): void
{
$this->uuid = $uuid;
}
/**
* @param Selection $selection
* @return null|Selection
*/
public function &addSelection(Selection $selection): ?Selection
{
$this->selections[$selection->getUUID()->toString()] = $selection;
$this->setLatestSelectionUUID($selection->getUUID());
$selection = $this->getLatestSelection();
return $selection;
}
/**
* @param UUID $uuid
* @return null|Selection
*/
public function &getSelectionByUUID(UUID $uuid): ?Selection
{
$selection = $this->selections[$uuid->toString()] ?? null;
return $selection;
}
/**
* @param string $uuid
* @return null|Selection
*/
public function &getSelectionByString(string $uuid): ?Selection
{
$selection = $this->selections[$uuid] ?? null;
return $selection;
}
/**
* @return null|Selection
*/
public function &getLatestSelection(): ?Selection
{
$latestSelectionUUID = $this->getLatestSelectionUUID();
if (is_null($latestSelectionUUID)) {
$selection = null;
return $selection;
}
$selection = $this->selections[$latestSelectionUUID->toString()] ?? null;
return $selection;
}
/**
* @return Selection[]
*/
public function getSelections(): array
{
return $this->selections;
}
/**
* @param mixed $selections
*/
public function setSelections($selections): void
{
$this->selections = $selections;
}
/**
* @return UUID|null
*/
public function getLatestSelectionUUID(): ?UUID
{
return $this->latestselection;
}
/**
* @param UUID $latestselection
*/
public function setLatestSelectionUUID(UUID $latestselection): void
{
$this->latestselection = $latestselection;
}
/**
* @return int
*/
public function getCurrentClipboardIndex(): int
{
return $this->currentClipboard;
}
/**
* @return null|Clipboard
*/
public function getCurrentClipboard(): ?Clipboard
{
return $this->clipboards[$this->currentClipboard] ?? null;
}
/**
* @param string $name
* @return null|Clipboard
*/
public function getClipboardByName(string $name): ?Clipboard
{
foreach ($this->clipboards as $clipboard) {
if ($clipboard->getCustomName() === $name) return $clipboard;
}
return null;
}
/**
* @param int $id
* @return null|Clipboard
*/
public function getClipboardById(int $id): ?Clipboard
{
return $this->clipboards[$id] ?? null;
}
/**
* TODO
* @return Clipboard[]
*/
public function getClipboards(): array
{
return $this->clipboards;
}
/**
* TODO
* @param Clipboard[] $clipboards
* @return bool
*/
public function setClipboards(array $clipboards): bool
{
$this->clipboards = $clipboards;
return true;
}
/**
* @param Clipboard $clipboard
* @param bool $setAsCurrent
* @return int The index of the clipboard
*/
public function addClipboard(Clipboard $clipboard, bool $setAsCurrent = true): int
{
$amount = array_push($this->clipboards, $clipboard);
if ($amount > self::MAX_CLIPBOARDS) array_shift($this->clipboards);
$i = array_search($clipboard, $this->clipboards, true);
if ($i !== false) {
if ($setAsCurrent) $this->currentClipboard = (int)$i;
return (int)$i;
}
return -1;
}
/**
* @param RevertClipboard $revertClipboard
*/
public function addRevert(RevertClipboard $revertClipboard): void
{
$this->redoHistory->clear();
$this->undoHistory->push($revertClipboard);
while ($this->undoHistory->count() > self::MAX_HISTORY) {
$this->undoHistory->shift();
}
}
/**
* @throws Exception
*/
public function undo(): void
{
if ($this->undoHistory->count() === 0) {
$this->sendMessage(TF::RED . $this->getLanguage()->translateString('session.undo.none'));
return;
}
/** @var RevertClipboard $revertClipboard */
$revertClipboard = $this->undoHistory->pop();
$world = $revertClipboard->getWorld();
foreach ($revertClipboard->chunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$revertClipboard->chunks[$hash] = $world->getChunk($x, $z);
}
Server::getInstance()->getAsyncPool()->submitTask(new AsyncRevertTask($this->getUUID(), $revertClipboard, AsyncRevertTask::TYPE_UNDO));
$this->sendMessage(TF::GREEN . $this->getLanguage()->translateString('session.undo.left', [count($this->undoHistory)]));
}
/**
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function redo(): void
{
if ($this->redoHistory->count() === 0) {
$this->sendMessage(TF::RED . $this->getLanguage()->translateString('session.redo.none'));
return;
}
/** @var RevertClipboard $revertClipboard */
$revertClipboard = $this->redoHistory->pop();
Server::getInstance()->getAsyncPool()->submitTask(new AsyncRevertTask($this->getUUID(), $revertClipboard, AsyncRevertTask::TYPE_REDO));
$this->sendMessage(TF::GREEN . $this->getLanguage()->translateString('session.redo.left', [count($this->redoHistory)]));
}
public function clearHistory(): void
{
$this->undoHistory->clear();
$this->redoHistory->clear();
}
public function clearClipboard(): void
{
$this->setClipboards([]);
$this->currentClipboard = -1;
}
/**
* @return Language
*/
public function getLanguage(): Language
{
return Loader::getInstance()->getLanguage();
}
abstract public function sendMessage(string $message): void;
public function __toString()
{
return __CLASS__ .
" UUID: " . $this->getUUID()->__toString() .
" Selections: " . count($this->getSelections()) .
" Latest: " . $this->getLatestSelectionUUID() .
" Clipboards: " . count($this->getClipboards()) .
" Current: " . $this->getCurrentClipboardIndex() .
" Undos: " . count($this->undoHistory) .
" Redos: " . count($this->redoHistory);
}
/*
* TODO list:
* session storing/recovering from file/cleanup if too old
* session items
* recover session items + commands to get back already created/configured items/tool/brushes
* proper multi-selection-usage
* setState/getState on big actions, status bar/boss bar/texts/titles/popups
* inspect other player's sessions
* destroy session if owning player lost permission/gets banned
* optimise destroySession/__destruct of sessions
* clipboard selection (renaming?)
*/
}
================================================
FILE: src/xenialdan/MagicWE2/session/UserSession.php
================================================
setPlayer($player);
$this->cleanupInventory();
$this->setUUID($player->getUniqueId());
$this->bossBar = (new BossBar())->addPlayer($player);
$this->bossBar->hideFrom([$player]);
if (Loader::hasScoreboard()) {
$this->sidebar = new Scoreboard();
}
$this->undoHistory = new Deque();
$this->redoHistory = new Deque();
try {
if (is_null($this->lang))
$this->lang = new Language(Language::FALLBACK_LANGUAGE, Loader::getInstance()->getLanguageFolder());
} catch (LanguageNotFoundException $e) {
}
Loader::getInstance()->getLogger()->debug("Created new session for player {$player->getName()}");
}
public function __destruct()
{
Loader::getInstance()->getLogger()->debug("Destructing session {$this->getUUID()} for user " . $this->getPlayer()->getName());
$this->bossBar->removeAllPlayers();
if (Loader::hasScoreboard() && $this->sidebar !== null) {
ScoreFactory::removeScore($this->getPlayer());
}
}
/**
* @return Language
*/
public function getLanguage(): Language
{
return $this->lang;
}
/**
* Set the language for the user. Uses iso639-2 language code
* @param string $langShort iso639-2 conform language code (3 letter)
* @throws LanguageNotFoundException
*/
public function setLanguage(string $langShort): void
{
$langShort = strtolower($langShort);
if (isset(Loader::getInstance()->getLanguageList()[$langShort])) {
$this->lang = new Language($langShort, Loader::getInstance()->getLanguageFolder());
$this->sendMessage(TF::GREEN . $this->getLanguage()->translateString("session.language.set", [$this->getLanguage()->getName()]));
} else {
$this->lang = new Language(Language::FALLBACK_LANGUAGE, Loader::getInstance()->getLanguageFolder());
$this->sendMessage(TF::RED . $this->getLanguage()->translateString("session.language.notfound", [$langShort]));
}
}
/**
* @param null|Player $player
*/
public function setPlayer(?Player $player): void
{
$this->player = $player;
}
/**
* @return null|Player
*/
public function getPlayer(): ?Player
{
return $this->player;
}
/**
* @return bool
*/
public function isWandEnabled(): bool
{
return $this->wandEnabled;
}
/**
* @param bool $wandEnabled
* @return string
*/
public function setWandEnabled(bool $wandEnabled): string
{
$this->wandEnabled = $wandEnabled;
return Loader::PREFIX . $this->getLanguage()->translateString('tool.wand.setenabled', [($wandEnabled ? TF::GREEN . $this->getLanguage()->translateString('enabled') : TF::RED . $this->getLanguage()->translateString('disabled'))]);
}
/**
* @return bool
*/
public function isDebugToolEnabled(): bool
{
return $this->debugToolEnabled;
}
/**
* @param bool $debugToolEnabled
* @return string
*/
public function setDebugToolEnabled(bool $debugToolEnabled): string
{
$this->debugToolEnabled = $debugToolEnabled;
return Loader::PREFIX . $this->getLanguage()->translateString('tool.debug.setenabled', [($debugToolEnabled ? TF::GREEN . $this->getLanguage()->translateString('enabled') : TF::RED . $this->getLanguage()->translateString('disabled'))]);
}
/**
* @return bool
*/
public function isSidebarEnabled(): bool
{
return $this->sidebarEnabled;
}
/**
* @param bool $sidebarEnabled
* @return string
*/
public function setSidebarEnabled(bool $sidebarEnabled): string
{
$player = $this->getPlayer();
if (!$player instanceof Player) return TF::RED . "Session has no player";
$this->sidebarEnabled = $sidebarEnabled;
if ($sidebarEnabled) {
$this->sidebar->handleScoreboard($this);
} else {
ScoreFactory::removeScore($player);
}
return Loader::PREFIX . $this->getLanguage()->translateString('tool.sidebar.setenabled', [($sidebarEnabled ? TF::GREEN . $this->getLanguage()->translateString('enabled') : TF::RED . $this->getLanguage()->translateString('disabled'))]);
}
/**
* @return bool
*/
public function isWailaEnabled(): bool
{
return $this->wailaEnabled;
}
/**
* @param bool $wailaEnabled
* @return string
*/
public function setWailaEnabled(bool $wailaEnabled): string
{
$player = $this->getPlayer();
if (!$player instanceof Player) return TF::RED . "Session has no player";
$this->wailaEnabled = $wailaEnabled;
if ($wailaEnabled) {
Loader::getInstance()->wailaBossBar->showTo([$player]);
} else {
Loader::getInstance()->wailaBossBar->hideFrom([$player]);
}
return Loader::PREFIX . $this->getLanguage()->translateString('tool.waila.setenabled', [($wailaEnabled ? TF::GREEN . $this->getLanguage()->translateString('enabled') : TF::RED . $this->getLanguage()->translateString('disabled'))]);
}
/**
* @return BossBar
*/
public function getBossBar(): BossBar
{
return $this->bossBar;
}
/**
* TODO exception for not a brush
* @param Item $item
* @return Brush
* @throws Exception
*/
public function getBrushFromItem(Item $item): Brush
{
if ((($entry = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH))) instanceof CompoundTag) {
$version = $entry->getInt("version", 0);
if ($version !== BrushProperties::VERSION) {
throw new BrushException("Brush can not be restored - version mismatch");
}
/** @var BrushProperties $properties */
$properties = json_decode($entry->getString("properties"), false, 512, JSON_THROW_ON_ERROR);
$uuid = UUID::fromString($properties->uuid);
$brush = $this->getBrush($uuid);
if ($brush instanceof Brush) {
return $brush;
}
$brush = new Brush($properties);
$this->addBrush($brush);
return $brush;
}
throw new BrushException("The item is not a valid brush!");
}
/**
* TODO exception for not a brush
* @param UUID $uuid
* @return null|Brush
*/
public function getBrush(UUID $uuid): ?Brush
{
return $this->brushes[$uuid->toString()] ?? null;
}
/**
* TODO exception for not a brush
* @param Brush $brush UUID will be set automatically
* @return void
*/
public function addBrush(Brush $brush): void
{
$this->brushes[$brush->properties->uuid] = $brush;
$this->sendMessage($this->getLanguage()->translateString('session.brush.added', [$brush->getName()]));
}
/**
* @param Brush $brush UUID will be set automatically
* @param bool $delete If true, it will be removed from the session brushes
* @return void
*/
public function removeBrush(Brush $brush, bool $delete = false): void
{
if ($delete) unset($this->brushes[$brush->properties->uuid]);
foreach ($this->getPlayer()->getInventory()->getContents() as $slot => $item) {
if (($entry = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH)) instanceof CompoundTag) {
if ($entry->getString("id") === $brush->properties->uuid) {
$this->getPlayer()->getInventory()->clear($slot);
}
}
}
if ($delete) $this->sendMessage($this->getLanguage()->translateString('session.brush.deleted', [$brush->getName(), $brush->properties->uuid]));
else $this->sendMessage($this->getLanguage()->translateString('session.brush.removed', [$brush->getName(), $brush->properties->uuid]));
}
/**
* TODO exception for not a brush
* @param Brush $brush UUID will be set automatically
* @return void
* @throws ActionNotFoundException
* @throws InvalidArgumentException
* @throws ShapeNotFoundException
* @throws JsonException
* @throws TypeError
*/
public function replaceBrush(Brush $brush): void
{
$this->brushes[$brush->properties->uuid] = $brush;
$new = $brush->toItem();
foreach ($this->getPlayer()->getInventory()->getContents() as $slot => $item) {
if (($entry = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH)) instanceof CompoundTag) {
if ($entry->getString("id") === $brush->properties->uuid) {
$this->getPlayer()->getInventory()->setItem($slot, $new);
}
}
}
}
/**
* @return Brush[]
*/
public function getBrushes(): array
{
return $this->brushes;
}
public function cleanupInventory(): void
{
foreach ($this->getPlayer()->getInventory()->getContents() as $slot => $item) {
/** @var CompoundTag $entry */
if (!is_null(($entry = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE_BRUSH)))) {
$this->getPlayer()->getInventory()->clear($slot);
}
if (!is_null(($entry = $item->getNamedTag()->getCompoundTag(API::TAG_MAGIC_WE)))) {
$this->getPlayer()->getInventory()->clear($slot);
}
}
}
public function __toString()
{
return __CLASS__ .
" UUID: " . $this->getUUID()->__toString() .
" Player: " . $this->getPlayer()->getName() .
" Wand tool enabled: " . ($this->isWandEnabled() ? "enabled" : "disabled") .
" Debug tool enabled: " . ($this->isDebugToolEnabled() ? "enabled" : "disabled") .
" WAILA enabled: " . ($this->isWailaEnabled() ? "enabled" : "disabled") .
" Sidebar enabled: " . ($this->sidebarEnabled ? "enabled" : "disabled") .
" BossBar: " . $this->getBossBar()->entityId .
" Selections: " . count($this->getSelections()) .
" Latest: " . $this->getLatestSelectionUUID() .
" Clipboards: " . count($this->getClipboards()) .
" Current: " . $this->getCurrentClipboardIndex() .
" Undos: " . count($this->undoHistory) .
" Redos: " . count($this->redoHistory) .
" Brushes: " . count($this->brushes);
}
public function sendMessage(string $message): void
{
$this->player->sendMessage(Loader::PREFIX . $message);
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by json_encode,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
return [
"uuid" => $this->getUUID()->toString(),
"wandEnabled" => $this->wandEnabled,
"debugToolEnabled" => $this->debugToolEnabled,
"wailaEnabled" => $this->wailaEnabled,
"sidebarEnabled" => $this->sidebarEnabled,
"brushes" => $this->brushes,
"latestSelection" => $this->getLatestSelection(),
"currentClipboard" => $this->getCurrentClipboard(),
"language" => $this->getLanguage()->getLang()
];
}
public function save(): void
{
file_put_contents(Loader::getInstance()->getDataFolder() . "sessions" . DIRECTORY_SEPARATOR .
$this->getPlayer()->getName() . ".json",
json_encode($this, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT)
);
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncActionTask.php
================================================
start = microtime(true);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);
$this->action = $action;
$this->touchedChunks = serialize($touchedChunks);
$this->newBlocks = $newBlocks;
$this->blockFilter = $blockFilter;
try {
$session = SessionHelper::getSessionByUUID($sessionUUID);
if ($session instanceof UserSession) {
$player = $session->getPlayer();
/** @var Player $player */
$session->getBossBar()->showTo([$player]);
$session->getBossBar()->setTitle("Running {$action::getName()} action");//TODO better string
}
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
}
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress(new Progress(0, "Preparing {$this->action::getName()}"));
$touchedChunks = unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/);
$touchedChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, $touchedChunks);
$manager = Shape::getChunkManager($touchedChunks);
unset($touchedChunks);
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);
$oldBlocks = new SingleClipboard($this->action->clipboardVector ?? new Vector3(0, 0, 0));//TODO Test if null V3 is ok //TODO test if the vector works
$oldBlocks->selection = $selection;//TODO test. Needed to add this so that //paste works after //cut2
#$oldBlocks = [];
$messages = [];
$error = false;
$newBlocks = API::blockParser($this->newBlocks, $messages, $error);//TODO error handling
$blockFilter = API::blockParser($this->blockFilter, $messages, $error);//TODO error handling
/** @var Progress $progress */
foreach ($this->action->execute($this->sessionUUID, $selection, $manager, $changed, $newBlocks, $blockFilter, $oldBlocks, $messages) as $progress) {
$this->publishProgress($progress);
}
$resultChunks = $manager->getChunks();
$resultChunks = array_filter($resultChunks, static function (Chunk $chunk) {
return $chunk->isDirty();
});
$this->setResult(compact("resultChunks", "oldBlocks", "changed", "messages"));
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
* @throws Exception
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var Chunk[] $resultChunks */
$resultChunks = $result["resultChunks"];
$undoChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
/** @var SingleClipboard $oldBlocks *///TODO make sure changed everywhere
$oldBlocks = $result["oldBlocks"];
//TODO Test this new behaviour!
//TODO so here i turn SingleClipboard entries into the same $oldBlocks as before this commit
$oldBlocksBlocks = [];
$x = $y = $z = null;
foreach ($oldBlocks->iterateEntries($x, $y, $z) as $entry) {
$oldBlocksBlocks[] = API::setComponents($entry->toBlock(), (int)$x, (int)$y, (int)$z);//turn BlockEntry to blocks
}
$changed = $result["changed"];
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
$world = $selection->getWorld();
foreach ($resultChunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$world->setChunk($x, $z, $chunk, false);
}
if (!is_null($session)) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString($this->action->completionString, ["name" => trim($this->action->prefix . " " . $this->action::getName()), "took" => $this->generateTookString(), "changed" => $changed, "total" => $totalCount]));
foreach ($result["messages"] ?? [] as $message) $session->sendMessage($message);
if ($this->action->addRevert)
$session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, self::multipleBlocksToData($oldBlocksBlocks)));
if ($this->action->addClipboard)
$session->addClipboard($oldBlocks);
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncClipboardActionTask.php
================================================
start = microtime(true);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);//TODO check if needed, $clipboard already holds the selection
$this->clipboard = serialize($clipboard);//TODO check if this even needs to be serialized
$this->action = $action;
$this->rotPath = Loader::getRotFlipPath();
$this->doorRotPath = Loader::getDoorRotFlipPath();
try {
$session = SessionHelper::getSessionByUUID($sessionUUID);
if ($session instanceof UserSession) {
$player = $session->getPlayer();
/** @var Player $player */
$session->getBossBar()->showTo([$player]);
$session->getBossBar()->setTitle("Running {$action::getName()} clipboard action");//TODO better string
}
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
}
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress(new Progress(0, "Preparing {$this->action::getName()}"));
BlockStatesParser::$doorRotPath = $this->doorRotPath;
BlockStatesParser::$rotPath = $this->rotPath;
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
/** @var SingleClipboard $clipboard */
$clipboard = unserialize($this->clipboard/*, ['allowed_classes' => [SingleClipboard::class]]*/);//TODO test pm4
$clipboard->selection = $selection;//TODO test. Needed to add this so that //paste works after //cut2
$messages = [];
/** @var Progress $progress */
foreach ($this->action->execute($this->sessionUUID, $selection, $changed, $clipboard, $messages) as $progress) {
$this->publishProgress($progress);
}
//TODO $clipboard->selection shape might change when using rotate. Fix this, so //paste chunks are correct
$this->setResult(compact("clipboard", "changed", "messages"));
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var SingleClipboard $clipboard */
$clipboard = $result["clipboard"];
$changed = $result["changed"];
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
if (!is_null($session)) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString($this->action->completionString, ["name" => trim($this->action->prefix . " " . $this->action::getName()), "took" => $this->generateTookString(), "changed" => $changed, "total" => $totalCount]));
foreach ($result["messages"] ?? [] as $message) $session->sendMessage($message);
if ($this->action->addClipboard)
$session->addClipboard($clipboard);
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncCopyTask.php
================================================
start = microtime(true);
$this->chunks = serialize($chunks);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);
$this->offset = $offset->asVector3()->floor();
$this->flags = $flags;
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
$chunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->chunks/*, ['allowed_classes' => false]*/));//TODO test pm4
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
#var_dump("shape", $selection->getShape());
$manager = Shape::getChunkManager($chunks);
unset($chunks);
#var_dump($this->offset);
$clipboard = new SingleClipboard($this->offset);
$clipboard->selection = $selection;
#$clipboard->setCenter(unserialize($this->offset));
$totalCount = $selection->getShape()->getTotalCount();
$copied = $this->copyBlocks($selection, $manager, $clipboard);
#$clipboard->setShape($selection->getShape());
#$clipboard->chunks = $manager->getChunks();
$this->setResult(compact("clipboard", "copied", "totalCount"));
}
/**
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param SingleClipboard $clipboard
* @return int
* @throws Exception
*/
private function copyBlocks(Selection $selection, AsyncChunkManager $manager, SingleClipboard $clipboard): int
{
$blockCount = $selection->getShape()->getTotalCount();
$i = 0;
$lastprogress = 0;
$this->publishProgress([0, "Running, copied $i blocks out of $blockCount"]);
$min = $selection->getShape()->getMinVec3();
/** @var Block $block */
foreach ($selection->getShape()->getBlocks($manager, [], $this->flags) as $block) {
#var_dump("copy chunk X: " . ($block->getX() >> 4) . " Y: " . ($block->getY() >> 4));
$newv3 = $block->getPos()->subtractVector($min)->floor();
$clipboard->addEntry($newv3->getFloorX(), $newv3->getFloorY(), $newv3->getFloorZ(), new BlockEntry($block->getFullId()));//TODO test tiles
#var_dump("copied selection block", $block);
$i++;
$progress = floor($i / $blockCount * 100);
if ($lastprogress < $progress) {//this prevents spamming packets
$this->publishProgress([$progress, "Running, copied $i blocks out of $blockCount"]);
$lastprogress = $progress;
}
}
return $i;
}
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
$result = $this->getResult();
$copied = $result["copied"];
/** @var SingleClipboard $clipboard */
$clipboard = $result["clipboard"];
$totalCount = $result["totalCount"];
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.copy.success', [$this->generateTookString(), $copied, $totalCount]));
$session->addClipboard($clipboard);
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
} catch (InvalidArgumentException $e) {
Loader::getInstance()->getLogger()->logException($e);
} catch (AssumptionFailedError $e) {
Loader::getInstance()->getLogger()->logException($e);
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncCountTask.php
================================================
start = microtime(true);
$this->touchedChunks = serialize($touchedChunks);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);
$this->newBlocks = serialize($newBlocks);
$this->flags = $flags;
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
$chunks = unserialize($this->touchedChunks/*, ['allowed_classes' => [false]]*/);//TODO test pm4
foreach ($chunks as $hash => $data) {
$chunks[$hash] = FastChunkSerializer::deserialize($data);
}
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$manager = Shape::getChunkManager($chunks);
unset($chunks);
/** @var Block[] $newBlocks */
$newBlocks = unserialize($this->newBlocks/*, ['allowed_classes' => [Block::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
$counts = $this->countBlocks($selection, $manager, $newBlocks);
$this->setResult(compact("counts", "totalCount"));
}
/**
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param Block[] $newBlocks
* @return array
* @throws Exception
*/
private function countBlocks(Selection $selection, AsyncChunkManager $manager, array $newBlocks): array
{
$blockCount = $selection->getShape()->getTotalCount();
$changed = 0;
$this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]);
$lastchunkx = $lastchunkz = null;
$lastprogress = 0;
$counts = [];
/** @var Block $block */
foreach ($selection->getShape()->getBlocks($manager, $newBlocks, $this->flags) as $block) {
if (is_null($lastchunkx) || ($block->getPos()->x >> 4 !== $lastchunkx && $block->getPos()->z >> 4 !== $lastchunkz)) {
$lastchunkx = $block->getPos()->x >> 4;
$lastchunkz = $block->getPos()->z >> 4;
if (is_null($manager->getChunk($block->getPos()->x >> 4, $block->getPos()->z >> 4))) {
#print PHP_EOL . "Not found: " . strval($block->x >> 4) . ":" . strval($block->z >> 4) . PHP_EOL;
continue;
}
}
BlockFactory::getInstance();
$block1 = $manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ());
$tostring = (BlockFactory::getInstance()->get($block1[0], $block1[1]))->getName() . " " . $block1[0] . ":" . $block1[1];
if (!array_key_exists($tostring, $counts)) $counts[$tostring] = 0;
$counts[$tostring]++;
$changed++;
$progress = floor($changed / $blockCount * 100);
if ($lastprogress < $progress) {//this prevents spamming packets
$this->publishProgress([$progress, "Running, counting $changed blocks out of $blockCount"]);
$lastprogress = $progress;
}
}
return $counts;
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
$result = $this->getResult();
$counts = $result["counts"];
$totalCount = $result["totalCount"];
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.count.success', [$this->generateTookString()]));
$session->sendMessage(TF::DARK_AQUA . $session->getLanguage()->translateString('task.count.result', [count($counts), $totalCount]));
uasort($counts, static function ($a, $b) {
if ($a === $b) return 0;
return ($a > $b) ? -1 : 1;
});
foreach ($counts as $block => $count) {
$session->sendMessage(TF::AQUA . $count . "x | " . round($count / $totalCount * 100) . "% | " . $block);
}
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncFillTask.php
================================================
start = microtime(true);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = igbinary_serialize($selection);
$this->touchedChunks = igbinary_serialize($touchedChunks);
$this->newBlocks = BlockPalette::encode($newBlocks);
var_dump($this->newBlocks);
$this->flags = $flags;
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
$touchedChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, igbinary_unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
$manager = Shape::getChunkManager($touchedChunks);
unset($touchedChunks);
/** @var Selection $selection */
$selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
/** @var Block[] $newBlocks */
$newBlocks = BlockPalette::decode($this->newBlocks);//TODO test pm4
$oldBlocks = iterator_to_array($this->execute($selection, $manager, $newBlocks, $changed));
$resultChunks = $manager->getChunks();
$resultChunks = array_filter($resultChunks, static function (Chunk $chunk) {
return $chunk->isDirty();
});
#$this->setResult(compact("resultChunks", "oldBlocks", "changed"));
$this->setResult([
"resultChunks" => $resultChunks,
"oldBlocks" => $oldBlocks,
"changed" => $changed
]);
}
/**
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param Block[] $newBlocks
* @param null|int $changed
* @return Generator|array[]
* @phpstan-return Generator
* @throws Exception
*/
private function execute(Selection $selection, AsyncChunkManager $manager, array $newBlocks, ?int &$changed): Generator
{
$blockCount = $selection->getShape()->getTotalCount();
$lastchunkx = $lastchunkz = null;
$lastprogress = 0;
$i = 0;
$changed = 0;
$this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]);
/** @var Block $block */
foreach ($selection->getShape()->getBlocks($manager, [], $this->flags) as $block) {
/*if (API::hasFlag($this->flags, API::FLAG_POSITION_RELATIVE)){
$rel = $block->subtract($selection->shape->getPasteVector());
$block = API::setComponents($block,$rel->x,$rel->y,$rel->z);//TODO COPY TO ALL TASKS
}*/
if (is_null($lastchunkx) || ($block->getPos()->x >> 4 !== $lastchunkx && $block->getPos()->z >> 4 !== $lastchunkz)) {
$lastchunkx = $block->getPos()->x >> 4;
$lastchunkz = $block->getPos()->z >> 4;
if (is_null($manager->getChunk($block->getPos()->x >> 4, $block->getPos()->z >> 4))) {
#print PHP_EOL . "Not found: " . strval($block->x >> 4) . ":" . strval($block->z >> 4) . PHP_EOL;
continue;
}
}
$new = clone $newBlocks[array_rand($newBlocks)];
if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks
#yield self::undoBlockHackToArray($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()),$block->getPos());
yield self::singleBlockToData(API::setComponents($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()), (int)$block->getPos()->x, (int)$block->getPos()->y, (int)$block->getPos()->z));
#yield $block;//backup
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $new);
if ($manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()) !== [$block->getId(), $block->getMeta()]) {
$changed++;
}
///
$i++;
$progress = floor($i / $blockCount * 100);
if ($lastprogress < $progress) {//this prevents spamming packets
$this->publishProgress([$progress, "Running, changed $changed blocks out of $blockCount"]);
$lastprogress = $progress;
}
}
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
* @throws Exception
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var Chunk[] $resultChunks */
$resultChunks = $result["resultChunks"];
$undoChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, igbinary_unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4)
#$oldBlocks = igbinary_unserialize($result["oldBlocks"]);
$oldBlocks = $result["oldBlocks"];//this is already a data map
// $oldBlocks2 = [];
// /**
// * @var int $fullId
// * @var Vector3 $pos
// */
// foreach ($oldBlocks as [$fullId, $pos]) {
// $b = BlockFactory::getInstance()->fromFullBlock($fullId);
// $b->getPos()->x = $pos->x;
// $b->getPos()->y = $pos->y;
// $b->getPos()->z = $pos->z;
// $oldBlocks2[] = $b;
// }
// var_dump($oldBlocks2);
$changed = $result["changed"];
/** @var Selection $selection */
$selection = igbinary_unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
$world = $selection->getWorld();
foreach ($resultChunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$world->setChunk($x, $z, $chunk, false);
}
if (!is_null($session)) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.fill.success', [$this->generateTookString(), $changed, $totalCount]));
$session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, $oldBlocks));
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncPasteTask.php
================================================
start = microtime(true);
$this->offset = $selection->getShape()->getPasteVector()->addVector($clipboard->position)->floor();
#var_dump("paste", $selection->getShape()->getPasteVector(), "cb position", $clipboard->position, "offset", $this->offset, $clipboard);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);
$this->touchedChunks = serialize($touchedChunks);
$this->clipboard = serialize($clipboard);
}
/**
* Actions to execute when run
*
* @return void
* @throws InvalidArgumentException
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
$touchedChunks = array_map(static function ($chunk) {//todo add hash as key
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
$manager = Shape::getChunkManager($touchedChunks);
unset($touchedChunks);
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
/** @var SingleClipboard $clipboard */
$clipboard = unserialize($this->clipboard/*, ['allowed_classes' => [SingleClipboard::class]]*/);//TODO test pm4
$oldBlocks = iterator_to_array($this->execute($selection, $manager, $clipboard, $changed));
$resultChunks = $manager->getChunks();
$resultChunks = array_filter($resultChunks, static function (Chunk $chunk) {
return $chunk->isDirty();
});
$this->setResult(compact("resultChunks", "oldBlocks", "changed"));
}
/**
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param SingleClipboard $clipboard
* @param null|int $changed
* @return Generator|array[]
* @phpstan-return Generator
* @throws InvalidArgumentException
*/
private function execute(Selection $selection, AsyncChunkManager $manager, SingleClipboard $clipboard, ?int &$changed): Generator
{
$blockCount = $clipboard->getTotalCount();
$lastchunkx = $lastchunkz = $x = $y = $z = null;
$lastprogress = 0;
$i = 0;
$changed = 0;
$this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]);
/** @var BlockEntry $entry */
foreach ($clipboard->iterateEntries($x, $y, $z) as $entry) {
#var_dump("at cb xyz $x $y $z: $entry");
$x += $this->offset->getFloorX();
$y += $this->offset->getFloorY();
$z += $this->offset->getFloorZ();
#var_dump("add offset xyz $x $y $z");
if (($x >> 4 !== $lastchunkx && $z >> 4 !== $lastchunkz) || is_null($lastchunkx)) {
$lastchunkx = $x >> 4;
$lastchunkz = $z >> 4;
if (is_null($manager->getChunk($x >> 4, $z >> 4))) {
print PHP_EOL . "Paste chunk not found in async paste manager: " . ($x >> 4) . ":" . ($z >> 4) . PHP_EOL;
continue;
}
}
/*if (API::hasFlag($this->flags, API::FLAG_POSITION_RELATIVE)){
$rel = $block->subtract($selection->shape->getPasteVector());
$block = API::setComponents($block,$rel->x,$rel->y,$rel->z);//TODO COPY TO ALL TASKS
}*/
$new = $entry->toBlock();
#$new->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ());
#$old->position(($pos = Position::fromObject(new Vector3($x, $y, $z)))->getWorld(), $pos->getX(), $pos->getY(), $pos->getZ());
#var_dump("old", $old, "new", $new);
yield self::singleBlockToData(API::setComponents($manager->getBlockAt($x, $y, $z), (int)$x, (int)$y, (int)$z));
$manager->setBlockAt($x, $y, $z, $new);
if ($manager->getBlockArrayAt($x, $y, $z) !== [$manager->getBlockAt($x, $y, $z)->getId(), $manager->getBlockAt($x, $y, $z)->getMeta()]) {//TODO remove? Just useless waste imo
$changed++;
}
///
$i++;
$progress = floor($i / $blockCount * 100);
if ($lastprogress < $progress) {//this prevents spamming packets
$this->publishProgress([$progress, "Running, changed $changed blocks out of $blockCount"]);
$lastprogress = $progress;
}
}
}
/**
* @throws AssumptionFailedError
* @throws InvalidArgumentException
* @throws Exception
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var Chunk[] $resultChunks */
$resultChunks = $result["resultChunks"];
$undoChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
$oldBlocks = $result["oldBlocks"];//already data array
$changed = $result["changed"];
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
$world = $selection->getWorld();
foreach ($resultChunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$world->setChunk($x, $z, $chunk, false);
}
if (!is_null($session)) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.fill.success', [$this->generateTookString(), $changed, $totalCount]));
$session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, $oldBlocks));
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncReplaceTask.php
================================================
start = microtime(true);
$this->sessionUUID = $sessionUUID->toString();
$this->selection = serialize($selection);
$this->touchedChunks = serialize($touchedChunks);
$this->replaceBlocks = serialize($replaceBlocks);
$this->newBlocks = serialize($newBlocks);
$this->flags = $flags;
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
$touchedChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
$manager = Shape::getChunkManager($touchedChunks);
unset($touchedChunks);
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
/** @var Block[] $replaceBlocks */
$replaceBlocks = unserialize($this->replaceBlocks/*, ['allowed_classes' => [Block::class]]*/);//TODO test pm4
/** @var Block[] $newBlocks */
$newBlocks = unserialize($this->newBlocks/*, ['allowed_classes' => [Block::class]]*/);//TODO test pm4
$oldBlocks = iterator_to_array($this->execute($selection, $manager, $replaceBlocks, $newBlocks, $changed));
$resultChunks = $manager->getChunks();
$resultChunks = array_filter($resultChunks, static function (Chunk $chunk) {
return $chunk->isDirty();
});
$this->setResult(compact("resultChunks", "oldBlocks", "changed"));
}
/**
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param array $replaceBlocks
* @param Block[] $newBlocks
* @param null|int $changed
* @return Generator|array[]
* @phpstan-return Generator
* @throws Exception
*/
private function execute(Selection $selection, AsyncChunkManager $manager, array $replaceBlocks, array $newBlocks, ?int &$changed): Generator
{
$blockCount = $selection->getShape()->getTotalCount();
$lastchunkx = $lastchunkz = null;
$lastprogress = 0;
$i = 0;
$changed = 0;
$this->publishProgress([0, "Running, changed $changed blocks out of $blockCount"]);
/** @var Block $block */
foreach ($selection->getShape()->getBlocks($manager, $replaceBlocks, $this->flags) as $block) {
if (is_null($lastchunkx) || ($block->getPos()->x >> 4 !== $lastchunkx && $block->getPos()->z >> 4 !== $lastchunkz)) {
$lastchunkx = $block->getPos()->x >> 4;
$lastchunkz = $block->getPos()->z >> 4;
if (is_null($manager->getChunk($block->getPos()->x >> 4, $block->getPos()->z >> 4))) {
#print PHP_EOL . "Not found: " . strval($block->x >> 4) . ":" . strval($block->z >> 4) . PHP_EOL;
continue;
}
}
$new = clone $newBlocks[array_rand($newBlocks)];
if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks
yield self::singleBlockToData(API::setComponents($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()), (int)$block->getPos()->x, (int)$block->getPos()->y, (int)$block->getPos()->z));
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $new);
if ($manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()) !== [$block->getId(), $block->getMeta()]) {
$changed++;
}
///
$i++;
$progress = floor($i / $blockCount * 100);
if ($lastprogress < $progress) {//this prevents spamming packets
$this->publishProgress([$progress, "Running, changed $changed blocks out of $blockCount"]);
$lastprogress = $progress;
}
}
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
* @throws Exception
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var Chunk[] $resultChunks */
$resultChunks = $result["resultChunks"];
$undoChunks = array_map(static function ($chunk) {
return FastChunkSerializer::deserialize($chunk);
}, unserialize($this->touchedChunks/*, ['allowed_classes' => false]*/));//TODO test pm4
$oldBlocks = $result["oldBlocks"];//this is already as data
$changed = $result["changed"];
/** @var Selection $selection */
$selection = unserialize($this->selection/*, ['allowed_classes' => [Selection::class]]*/);//TODO test pm4
$totalCount = $selection->getShape()->getTotalCount();
$world = $selection->getWorld();
foreach ($resultChunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$world->setChunk($x, $z, $chunk, false);
}
if (!is_null($session)) {
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.replace.success', [$this->generateTookString(), $changed, $totalCount]));
$session->addRevert(new RevertClipboard($selection->worldId, $undoChunks, $oldBlocks));
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/AsyncRevertTask.php
================================================
sessionUUID = $sessionUUID->toString();
$this->start = microtime(true);
$this->clipboard = serialize($clipboard);
$this->type = $type;
}
/**
* Actions to execute when run
*
* @return void
* @throws Exception
*/
public function onRun(): void
{
$this->publishProgress([0, "Start"]);
/** @var RevertClipboard $clipboard */
$clipboard = unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4
$totalCount = count($clipboard->blocksAfter);
$manager = $clipboard::getChunkManager($clipboard->chunks);
$oldBlocks = [];
if ($this->type === self::TYPE_UNDO)
$oldBlocks = iterator_to_array($this->undoChunks($manager, $clipboard));
if ($this->type === self::TYPE_REDO)
$oldBlocks = iterator_to_array($this->redoChunks($manager, $clipboard));
$chunks = $manager->getChunks();
$this->setResult(compact("chunks", "oldBlocks", "totalCount"));
}
/**
* @param AsyncChunkManager $manager
* @param RevertClipboard $clipboard
* @return Generator|array[]
* @phpstan-return Generator
* @throws InvalidArgumentException
*/
private function undoChunks(AsyncChunkManager $manager, RevertClipboard $clipboard): Generator
{
$count = count($clipboard->blocksAfter);
$changed = 0;
$this->publishProgress([0, "Reverted $changed blocks out of $count"]);
//$block is "data" array
foreach ($clipboard->blocksAfter as $block) {
yield $block;
$block = self::singleDataToBlock($block);//turn data into real block
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $block);
$changed++;
$this->publishProgress([$changed / $count, "Reverted $changed blocks out of $count"]);
}
}
/**
* @param AsyncChunkManager $manager
* @param RevertClipboard $clipboard
* @return Generator|array[]
* @phpstan-return Generator
* @throws InvalidArgumentException
*/
private function redoChunks(AsyncChunkManager $manager, RevertClipboard $clipboard): Generator
{
$count = count($clipboard->blocksAfter);
$changed = 0;
$this->publishProgress([0, "Redone $changed blocks out of $count"]);
//$block is "data" array
foreach ($clipboard->blocksAfter as $block) {
yield $block;
$block = self::singleDataToBlock($block);//turn data into real block
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $block);
$changed++;
$this->publishProgress([$changed / $count, "Redone $changed blocks out of $count"]);
}
}
/**
* @throws InvalidArgumentException
* @throws AssumptionFailedError
* @throws Exception
*/
public function onCompletion(): void
{
try {
$session = SessionHelper::getSessionByUUID(UUID::fromString($this->sessionUUID));
if ($session instanceof UserSession) $session->getBossBar()->hideFromAll();
} catch (SessionException $e) {
Loader::getInstance()->getLogger()->logException($e);
$session = null;
}
$result = $this->getResult();
/** @var RevertClipboard $clipboard */
$clipboard = unserialize($this->clipboard/*, ['allowed_classes' => [RevertClipboard::class]]*/);//TODO test pm4
$clipboard->chunks = $result["chunks"];
$totalCount = $result["totalCount"];
$changed = count($result["oldBlocks"]);
$clipboard->blocksAfter = $result["oldBlocks"];//already is a array of data
$world = $clipboard->getWorld();
foreach ($clipboard->chunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$world->setChunk($x, $z, $chunk, false);
}
if (!is_null($session)) {
switch ($this->type) {
case self::TYPE_UNDO:
{
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.revert.undo.success', [$this->generateTookString(), $changed, $totalCount]));
$session->redoHistory->push($clipboard);
break;
}
case self::TYPE_REDO:
{
$session->sendMessage(TF::GREEN . $session->getLanguage()->translateString('task.revert.redo.success', [$this->generateTookString(), $changed, $totalCount]));
$session->undoHistory->push($clipboard);
break;
}
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/MWEAsyncTask.php
================================================
sessionUUID));
/** @var Progress $progress */
if ($session instanceof UserSession) $session->getBossBar()->setPercentage($progress->progress)->setSubTitle(str_replace("%", "%%%%", $progress->string . " | " . floor($progress->progress * 100) . "%"));
else $session->sendMessage($progress->string . " | " . floor($progress->progress * 100) . "%");//TODO remove, debug
} catch (SessionException $e) {
//TODO log?
}
}
public function generateTookString(): string
{
return date("i:s:", (int)(microtime(true) - $this->start)) . round(microtime(true) - $this->start, 1, PHP_ROUND_HALF_DOWN);
}
/**
* Turns A block into an array that doesn't get fucked by anonymous classes when serialized
* @param Block $block
* @param Position|null $position
* @return array{int, Position|null}
*/
public static function singleBlockToData(Block $block, ?Position $position = null): array
{
/** @noinspection PhpInternalEntityUsedInspection */
return [$block->getFullId(), $position ?? $block->getPos()];
}
/**
* Turns ALL blocks into an array that doesn't get fucked by anonymous classes when serialized
* @param Block[] $blocks
* @return array
*/
public static function multipleBlocksToData(array $blocks): array
{
$a = [];
foreach ($blocks as $block)
$a[] = self::singleBlockToData($block);
return $a;
}
/**
* Turns a SINGLE array from singleBlockToData back into a block
* @param array{int, Position|null} $data
* @return Block
*/
protected static function singleDataToBlock(array $data): Block
{
$block = BlockFactory::getInstance()->fromFullBlock($data[0]);
/** @var Position $pos */
$pos = $data[1];
$block->getPos()->world = $pos->world;
$block->getPos()->x = $pos->x;
$block->getPos()->y = $pos->y;
$block->getPos()->z = $pos->z;
return $block;
}
/**
* Turns back MULTIPLE data from singleBlockToData into blocks
* @param array $hackedBlockData
* @return Block[]
*/
public static function multipleDataToBlocks(array $hackedBlockData): array
{
$a = [];
foreach ($hackedBlockData as $datum) {
$a[] = self::singleDataToBlock($datum);
}
return $a;
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/ActionRegistry.php
================================================
asVector3()->floor();
$this->clipboardVector = $clipboardVector;
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/CountAction.php
================================================
getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
$counts = [];
BlockFactory::getInstance();
foreach ($selection->getShape()->getBlocks($manager, $newBlocks) as $block) {
$block1 = $manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ());
$tostring = (BlockFactory::getInstance()->get($block1[0], $block1[1]))->getName() . " " . $block1[0] . ":" . $block1[1];
if (!array_key_exists($tostring, $counts)) $counts[$tostring] = 0;
$counts[$tostring]++;
$changed++;
$progress = new Progress($changed / $count, "$changed blocks out of $count");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
$messages[] = TF::DARK_AQUA . count($counts) . " blocks found in a total of $count blocks";
uasort($counts, static function ($a, $b) {
if ($a === $b) return 0;
return ($a > $b) ? -1 : 1;
});
foreach ($counts as $block => $countb) {
$messages[] = TF::AQUA . $countb . "x | " . round($countb / $count * 100) . "% | " . $block;
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/CutAction.php
================================================
getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
$min = $selection->getShape()->getMinVec3();
foreach ($selection->getShape()->getBlocks($manager, $blockFilter) as $block) {
$new = clone $newBlocks[array_rand($newBlocks)];
if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks
#$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()),$block->x, $block->y, $block->z);
$newv3 = $block->getPos()->subtractVector($min)->floor();//TODO check if only used for clipboard
$oldBlocksSingleClipboard->addEntry($newv3->getFloorX(), $newv3->getFloorY(), $newv3->getFloorZ(), BlockEntry::fromBlock($block));
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $new);
if ($manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()) !== [$block->getId(), $block->getMeta()]) {
$changed++;
}
$i++;
$progress = new Progress($i / $count, "Changed {$changed} blocks out of {$count}");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/FlipAction.php
================================================
axis = $axis;
}
public static function getName(): string
{
return "Flip";
}
/**
* @param string $sessionUUID
* @param Selection $selection
* @param null|int $changed
* @param SingleClipboard $clipboard
* @param string[] $messages
* @return Generator|Progress[]
* @throws Exception
*/
public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []): Generator
{
//TODO modify position. For now, just flip the blocks around their own axis
$changed = 0;
#$oldBlocks = [];
$count = $selection->getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
BlockFactory::getInstance();
$clonedClipboard = clone $clipboard;
$x = $y = $z = null;
$maxX = $clipboard->selection->getSizeX() - 1;
$maxY = $clipboard->selection->getSizeY() - 1;
$maxZ = $clipboard->selection->getSizeZ() - 1;
foreach ($clipboard->iterateEntries($x, $y, $z) as $blockEntry) {
#var_dump("$x $y $z");
if ($this->axis === self::AXIS_Z || $this->axis === self::AXIS_XZ)
$x = $maxX - $x;
if ($this->axis === self::AXIS_X || $this->axis === self::AXIS_XZ)
$z = $maxZ - $z;
if ($this->axis === self::AXIS_Y)
$y = $maxY - $y;
#var_dump("$x $y $z");
$block1 = $blockEntry->toBlock();
$blockStatesEntry = BlockStatesParser::getInstance()::getStateByBlock($block1);
$mirrored = $blockStatesEntry->mirror($this->axis);
$block = $mirrored->toBlock();
$entry = BlockEntry::fromBlock($block);
//var_dump($blockStatesEntry->__toString(), $mirrored->__toString(), $block);
/** @var int $x */
/** @var int $y */
/** @var int $z */
$clonedClipboard->addEntry($x, $y, $z, $entry);
$changed++;
$progress = new Progress($changed / $count, "$changed/$count");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
$clipboard = $clonedClipboard;
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/RotateAction.php
================================================
rotation = $rotation;
$this->addClipboard = $aroundOrigin;
}
public static function getName(): string
{
return "Rotate";
}
/**
* @param string $sessionUUID
* @param Selection $selection
* @param null|int $changed
* @param SingleClipboard $clipboard
* @param string[] $messages
* @return Generator|Progress[]
* @throws Exception
*/
public function execute(string $sessionUUID, Selection $selection, ?int &$changed, SingleClipboard &$clipboard, array &$messages = []): Generator
{
//TODO modify position. For now, just flip the blocks around their own axis
$changed = 0;
#$oldBlocks = [];
$count = $selection->getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
BlockFactory::getInstance();
$clonedClipboard = clone $clipboard;
$clonedClipboard->clear();
$x = $y = $z = null;
$maxX = $clipboard->selection->getSizeX() - 1;
$maxZ = $clipboard->selection->getSizeZ() - 1;
foreach ($clipboard->iterateEntries($x, $y, $z) as $blockEntry) {//only fully works if xyz is positive //TODO make sure this is always positive, see next comment
#var_dump("$x $y $z");
$newX = $x;
$newZ = $z;
//TODO if aroundOrigin is true (or false, unsure right now), modify the paste vector instead, and always keep the blocks in the positive range?
if ($this->rotation === self::ROTATE_90) {
$newX = -$z;
$newZ = $x;
if ($this->aroundOrigin) {
$newX += $maxZ;
}
}
if ($this->rotation === self::ROTATE_180) {
$newX = -$x;
$newZ = -$z;
if ($this->aroundOrigin) {
$newX += $maxX;
$newZ += $maxZ;
}
}
if ($this->rotation === self::ROTATE_270) {
$newX = $z;
$newZ = -$x;
if ($this->aroundOrigin) {
$newZ += $maxX;
}
}
#var_dump("$newX $y $newZ");
$block1 = $blockEntry->toBlock();
/** @var BlockStatesParser $instance */
$instance = BlockStatesParser::getInstance();
$blockStatesEntry = $instance::getStateByBlock($block1);
$rotated = $blockStatesEntry->rotate($this->rotation);
$block = $rotated->toBlock();
$entry = BlockEntry::fromBlock($block);
#var_dump($blockStatesEntry->__toString(), $rotated->__toString(), $entry);
/** @var int $y */
$clonedClipboard->addEntry($newX, $y, $newZ, $entry);
$changed++;
$progress = new Progress($changed / $count, "$changed/$count");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
$clonedSelection = $clonedClipboard->selection;
$pos1 = $clonedSelection->pos1;
$pos2 = $clonedSelection->pos2;
if ($this->rotation === self::ROTATE_90) {//TODO rewrite to be cleaner
#$pos2 = $pos2->setComponents($pos1->x, $pos2->y, $pos1->z + $maxX);
$pos2 = new Vector3($pos1->x, $pos2->y, $pos1->z + $maxX);
$pos1 = $pos1->subtract($maxZ, 0, 0);
if ($this->aroundOrigin) {
$pos1 = $pos1->add($maxZ, 0, 0);
$pos2 = $pos2->add($maxZ, 0, 0);
}
}
if ($this->rotation === self::ROTATE_180) {
if (!$this->aroundOrigin) {
$pos1 = $pos1->subtract($maxX, 0, $maxZ);
$pos2 = $pos2->subtract($maxX, 0, $maxZ);
}
}
if ($this->rotation === self::ROTATE_270) {//TODO rewrite to be cleaner
#$pos2 = $pos2->setComponents($pos1->x + $maxZ, $pos2->y, $pos1->z);
$pos2 = new Vector3($pos1->x + $maxZ, $pos2->y, $pos1->z);
$pos1 = $pos1->subtract(0, 0, $maxX);
if ($this->aroundOrigin) {
$pos1 = $pos1->add(0, 0, $maxX);
$pos2 = $pos2->add(0, 0, $maxX);
}
}
$clonedSelection->shape = (Cuboid::constructFromPositions($pos1, $pos2));//TODO figure out how to keep the shape (not always Cuboid)
$clonedClipboard->selection = $clonedSelection;
$clipboard = $clonedClipboard;
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/SetBiomeAction.php
================================================
biomeId = $biomeId;
}
public static function getName(): string
{
return "Set biome";
}
/**
* @param string $sessionUUID
* @param Selection $selection
* @param AsyncChunkManager $manager
* @param null|int $changed
* @param Block[] $newBlocks
* @param Block[] $blockFilter
* @param SingleClipboard $oldBlocksSingleClipboard blocks before the change
* @param string[] $messages
* @return Generator|Progress[]
* @throws Exception
*/
public function execute(string $sessionUUID, Selection $selection, AsyncChunkManager $manager, ?int &$changed, array $newBlocks, array $blockFilter, SingleClipboard $oldBlocksSingleClipboard, array &$messages = []): Generator
{
$changed = 0;
#$oldBlocks = [];
$count = null;
$lastProgress = new Progress(0, "");
foreach (($all = $selection->getShape()->getLayer($manager)) as $vec2) {
if (is_null($count)) $count = count(iterator_to_array($all));
$manager->getChunk($vec2->x >> 4, $vec2->y >> 4)->setBiomeId($vec2->x % 16, $vec2->y % 16, $this->biomeId);
$changed++;
$progress = new Progress($changed / $count, "Changed Biome for $changed/$count blocks");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/SetBlockAction.php
================================================
getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
foreach ($selection->getShape()->getBlocks($manager, $blockFilter) as $block) {
$new = clone $newBlocks[array_rand($newBlocks)];
if ($new->getId() === $block->getId() && $new->getMeta() === $block->getMeta()) continue;//skip same blocks
#$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()),$block->x, $block->y, $block->z);
$oldBlocksSingleClipboard->addEntry($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), BlockEntry::fromBlock($block));
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $new);
if ($manager->getBlockArrayAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()) !== [$block->getId(), $block->getMeta()]) {
$changed++;
}
$i++;
$progress = new Progress($i / $count, "Changed {$changed} blocks out of {$count}");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/TaskAction.php
================================================
asVector3()->floor();
$this->clipboardVector = $clipboardVector;
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/TestAction.php
================================================
getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
BlockFactory::getInstance();
foreach ($selection->getShape()->getBlocks($manager, []) as $block) {
$changed++;
$messages[] = $block->getPos()->asVector3()->__toString() . " " . $block->getName();
$progress = new Progress($changed / $count, "$changed/$count");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/task/action/ThawAction.php
================================================
getShape()->getTotalCount();
$lastProgress = new Progress(0, "");
$m = [];
$e = false;
$blockFilter = API::blockParser("snow_block,snow_layer,ice", $m, $e);
$newBlocks = API::blockParser("air,air,water", $m, $e);
foreach ($blockFilter as $ib => $blockF) {
foreach ($selection->getShape()->getBlocks($manager, [$blockF]) as $block) {
$new = clone $newBlocks[$ib];
#$oldBlocks[] = API::setComponents($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ()),$block->x, $block->y, $block->z);
$oldBlocksSingleClipboard->addEntry($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), BlockEntry::fromBlock($block));
$manager->setBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ(), $new);
if ($manager->getBlockAt($block->getPos()->getFloorX(), $block->getPos()->getFloorY(), $block->getPos()->getFloorZ())->getId() !== $block->getId()) {
$changed++;
}
$i++;
$progress = new Progress($i / $count, "Changed {$changed} blocks out of {$count}");
if (floor($progress->progress * 100) > floor($lastProgress->progress * 100)) {
yield $progress;
$lastProgress = $progress;
}
}
}
}
}
================================================
FILE: src/xenialdan/MagicWE2/tool/Brush.php
================================================
properties = $properties;
}
public function getName(): string
{
return $this->properties->getName();
}
/**
* @return Item
* @throws ActionNotFoundException
* @throws InvalidArgumentException
* @throws ShapeNotFoundException
* @throws JsonException
* @throws TypeError
*/
public function toItem(): Item
{
/** @var Durable $item */
$item = ItemFactory::getInstance()->get(ItemIds::WOODEN_SHOVEL);
$item->addEnchantment(new EnchantmentInstance(Loader::$ench));
$uuid = $this->properties->uuid ?? UUID::fromRandom()->toString();
$this->properties->uuid = $uuid;
$properties = json_encode($this->properties, JSON_THROW_ON_ERROR);
if (!is_string($properties)) throw new InvalidArgumentException("Brush properties could not be decoded");
$item->getNamedTag()->setTag(API::TAG_MAGIC_WE_BRUSH,
CompoundTag::create()
->setString("id", $uuid)
->setInt("version", $this->properties->version)
->setString("properties", $properties)
);
$item->setCustomName(Loader::PREFIX . TF::BOLD . TF::DARK_PURPLE . $this->getName());
$item->setLore($this->properties->generateLore());
$item->setUnbreakable();
return $item;
}
/**
* @param bool $new true if creating new brush
* @param array $errors
* @return CustomForm
* @throws Exception
* @throws AssumptionFailedError
*/
public function getForm(bool $new = true, array $errors = []): CustomForm
{
try {
$errors = array_map(static function ($value): string {
return TF::EOL . TF::RED . $value;
}, $errors);
$brushProperties = $this->properties ?? new BrushProperties();
$form = new CustomForm("Brush settings");
// Shape
#$form->addElement(new Label((isset($errors['shape']) ? TF::RED : "") . "Shape" . ($errors['shape'] ?? "")));
if ($new) {
$dropdownShape = new Dropdown((isset($errors['shape']) ? TF::RED : "") . "Shape" . ($errors['shape'] ?? ""));
foreach (Loader::getShapeRegistry()::getShapes() as $name => $class) {
if ($name === ShapeRegistry::CUSTOM) continue;
$dropdownShape->addOption($name, $class === $brushProperties->shape);
}
$form->addElement($dropdownShape);
} else {
$form->addElement(new Label($brushProperties->getShapeName()));
}
// Action
$dropdownAction = new Dropdown("Action");
foreach (ActionRegistry::getActions() as $name => $class) {
$dropdownAction->addOption($name, $class === $brushProperties->action);
}
$form->addElement($dropdownAction);
// Name
$form->addElement(new Input("Name", "Name", $new ? "" : $this->getName()));
// Blocks
$form->addElement(new Input((isset($errors['blocks']) ? TF::RED : "") . "Blocks" . ($errors['blocks'] ?? ""), "grass,stone:1", $brushProperties->blocks));
// Filter
$form->addElement(new Input((isset($errors['filter']) ? TF::RED : "") . "Filter" . ($errors['filter'] ?? ""), "air", $brushProperties->filter));
// Biome
$dropdownBiome = new Dropdown((isset($errors['biome']) ? TF::RED : "") . "Biome" . ($errors['biome'] ?? ""));
foreach ((new ReflectionClass(BiomeIds::class))->getConstants() as $name => $value) {
if ($value === BiomeIds::HELL) continue;
$dropdownBiome->addOption(BiomeRegistry::getInstance()->getBiome($value)->getName(), $value === $brushProperties->biomeId);
}
$form->addElement($dropdownBiome);
// Hollow
$form->addElement(new Toggle("Hollow", $brushProperties->hollow));
// Extra properties
if (!$new) {
foreach ($this->getExtradataForm($brushProperties->shape)->getContent() as $element) {
$form->addElement($element);
}
}
// Function
$form->setCallable(function (Player $player, $data) use ($form, $new) {
#var_dump(__LINE__, $data);
#$data = array_slice($data, 0, 7);
[$shape, $action, $name, $blocks, $filter, $biome, $hollow] = $data;
$extraData = [];
#var_dump(__LINE__, array_slice($data, 7));
$base = ShapeRegistry::getDefaultShapeProperties(ShapeRegistry::getShape($shape));
foreach (array_slice($data, 7, null, true) as $i => $value) {
#var_dump($i, $value, gettype($value), gettype($base[lcfirst($form->getElement($i)->getText())]));
if (is_int($base[lcfirst($form->getElement($i)->getText())])) $value = (int)$value;
$extraData[lcfirst($form->getElement($i)->getText())] = $value;//TODO
}
#var_dump(__LINE__, $extraData);
//prepare data
$blocks = trim(TF::clean($blocks));
$filter = trim(TF::clean($filter));
$biomeNames = (new ReflectionClass(BiomeIds::class))->getConstants();
$biomeNames = array_flip($biomeNames);
unset($biomeNames[BiomeIds::HELL]);
array_walk($biomeNames, static function (&$value, $key) {
$value = BiomeRegistry::getInstance()->getBiome($key)->getName();
});
$biomeId = array_search($biome, $biomeNames, true);
//error checks
$error = [];
try {
$m = [];
$e = false;
API::blockParser($blocks, $m, $e);
if ($e) throw new InvalidArgumentException(implode(TF::EOL, $m));
if (empty($blocks)) throw new AssumptionFailedError("Blocks cannot be empty!");
} catch (Exception $ex) {
$error['blocks'] = $ex->getMessage();
}
try {
$m = [];
$e = false;
API::blockParser($filter, $m, $e);
if ($e) throw new InvalidArgumentException(implode(TF::EOL, $m));
} catch (Exception $ex) {
$error['filter'] = $ex->getMessage();
}
try {
$shape = Loader::getShapeRegistry()::getShape($shape);
} catch (Exception $ex) {
$error['shape'] = $ex->getMessage();
}
try {
$action = Loader::getActionRegistry()::getAction($action);
} catch (Exception $ex) {
$error['action'] = $ex->getMessage();
}
try {
if (!is_int($biomeId)) throw new AssumptionFailedError("Biome not found");
} catch (Exception $ex) {
$error['biome'] = $ex->getMessage();
}
//Set properties (called before resending, so form contains errors)
if (!empty(trim(TF::clean($name)))) $this->properties->customName = $name;
if (!isset($error['shape'])) {
$this->properties->shape = $shape;
if (!$new && !empty($extraData))
$this->properties->shapeProperties = $extraData;
}
if (!isset($error['action'])) $this->properties->action = $action;
/*if (!isset($error['blocks']))*/
$this->properties->blocks = $blocks;
/*if (!isset($error['filter']))*/
$this->properties->filter = $filter;
$this->properties->hollow = $hollow;
//Resend form upon error
if (!empty($error)) {
$player->sendForm($this->getForm($new, $error));
return;
}
//Debug
#print_r($extraData);
try {
$brush = $this;
$session = SessionHelper::getUserSession($player);
if (!$session instanceof UserSession) {
throw new SessionException(Loader::getInstance()->getLanguage()->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
if (!$new) {
$session->replaceBrush($brush);
} else {
$player->sendForm($this->getExtradataForm($this->properties->shape));
}
} catch (Exception $ex) {
$player->sendMessage($ex->getMessage());
Loader::getInstance()->getLogger()->logException($ex);
}
});
return $form;
} catch (Exception $e) {
throw new AssumptionFailedError("Could not create brush form");
}
}
private function getExtradataForm(string $shapeClass): CustomForm
{
$form = new CustomForm("Shape settings");
#foreach (($defaultReplaced = array_merge(ShapeRegistry::getDefaultShapeProperties($shapeClass), $this->properties->shapeProperties)) as $name => $value) {
$base = ShapeRegistry::getDefaultShapeProperties($shapeClass);
foreach (($defaultReplaced = array_replace($base, array_intersect_key($this->properties->shapeProperties, $base))) as $name => $value) {
if (is_bool($value)) $form->addElement(new Toggle(ucfirst($name), $value));
else $form->addElement(new Input(ucfirst($name), $name . " (" . gettype($value) . ")", (string)$value));
}
#var_dump($this->properties->shapeProperties);
#var_dump('Base', $base);
#var_dump('Default Replaced', $defaultReplaced);
$form->setCallable(function (Player $player, $data) use ($defaultReplaced, $base) {
//TODO validation, resending etc.
$extraData = [];
$names = array_keys($defaultReplaced);
foreach ($data as $index => $value) {
if (is_int($base[$names[$index]])) $value = (int)$value;
$extraData[$names[$index]] = $value;
}
$this->properties->shapeProperties = $extraData;
$brush = $this;
$session = SessionHelper::getUserSession($player);
if (!$session instanceof UserSession) {
throw new SessionException(Loader::getInstance()->getLanguage()->translateString('error.nosession', [Loader::getInstance()->getName()]));
}
$this->properties->uuid = UUID::fromRandom()->toString();
$session->addBrush($brush);
$player->getInventory()->addItem($brush->toItem());
});
return $form;
}
}
================================================
FILE: src/xenialdan/MagicWE2/tool/BrushProperties.php
================================================
json_encode,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
return (array)$this;
}
/**
* @param array $json
* @return BrushProperties
* @throws InvalidArgumentException
*/
public static function fromJson(array $json): BrushProperties
{
if (($json["version"] ?? 0) !== self::VERSION) throw new InvalidArgumentException("Version mismatch");
$properties = new self;
foreach ($json as $key => $value) {
$properties->$key = $value;
}
return $properties;
}
public function getName(): string
{
$str = "";
try {
$str = trim(($this->hasCustomName() ? $this->customName : $this->getShapeName()) /*. " " . $this->action->getName() . */);
} catch (ShapeNotFoundException $e) {
}
if (stripos(TF::clean($str), "brush") === false) {
$str .= " Brush";
}
return $str;
}
/**
* @return string
* @throws ShapeNotFoundException
*/
public function getShapeName(): string
{
return is_subclass_of($this->shape, Shape::class) ? ShapeRegistry::getShapeName($this->shape) : "";
}
/**
* @return string
* @throws ActionNotFoundException
*/
public function getActionName(): string
{
return is_subclass_of($this->action, TaskAction::class) ? ActionRegistry::getActionName($this->action) : "";
}
public function hasCustomName(): bool
{
return !empty($this->customName);
}
/**
* @param string $customName If empty, the name will be reset
*/
public function setCustomName(string $customName = ""): void
{
$this->customName = $customName;
}
/**
* @return array
* @throws ActionNotFoundException
* @throws ShapeNotFoundException
* @noinspection NestedTernaryOperatorInspection
*/
public function generateLore(): array
{
$shapeProperties = array_map(static function ($k, $v): string {
return TF::GOLD . " " . ucfirst($k) . " = " . (is_bool($v) ? ($v ? "Yes" : "No") : $v);
}, array_keys($this->shapeProperties), $this->shapeProperties);
$actionProperties = array_map(static function ($k, $v): string {
return TF::GOLD . " " . ucfirst($k) . " = " . (is_bool($v) ? ($v ? "Yes" : "No") : $v);
}, array_keys($this->actionProperties), $this->actionProperties);
return array_merge(
[
TF::GOLD . "Shape: {$this->getShapeName()}",
],
$shapeProperties,
[
TF::GOLD . "Action: {$this->getActionName()}",
],
$actionProperties,
[
TF::GOLD . "Blocks: {$this->blocks}",
TF::GOLD . "Filter: {$this->filter}",
TF::GOLD . "Biome: {$this->biomeId}",
TF::GOLD . "Hollow: " . ($this->hollow ? "Yes" : "No"),
//TF::GOLD . "UUID: {$this->uuid}",
]
);
}
}
================================================
FILE: src/xenialdan/MagicWE2/tool/Flood.php
================================================
limit = $limit;
}
/**
* Returns the blocks by their actual position
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param Block[] $filterblocks If not empty, applying a filter on the block list
* @param int $flags
* @return Generator|Block[]
* @throws Exception
*/
public function getBlocks($manager, array $filterblocks = [], int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
$this->y = $this->getCenter()->getFloorY();
$block = $manager->getBlockAt($this->getCenter()->getFloorX(), $this->getCenter()->getFloorY(), $this->getCenter()->getFloorZ());
//$block = API::setComponents($block,$this->getCenter()->getFloorX(), $this->getCenter()->getFloorY(), $this->getCenter()->getFloorZ());
$this->walked[] = $block;
$this->nextToCheck = $this->walked;
foreach ($this->walk($manager) as $block) {
yield $block;
}
}
/**
* Returns a flat layer of all included x z positions in selection
* @param World|AsyncChunkManager $manager The world or AsyncChunkManager
* @param int $flags
* @return Generator|Vector2[]
* @throws Exception
*/
public function getLayer($manager, int $flags = API::FLAG_BASE): Generator
{
$this->validateChunkManager($manager);
foreach ($this->getBlocks($manager, []) as $block) {
yield new Vector2($block->getPos()->x, $block->getPos()->z);
}
}
/**
* @param World|AsyncChunkManager $manager
* @return Block[]
* @throws InvalidArgumentException
* @noinspection SlowArrayOperationsInLoopInspection
*/
private function walk($manager): array
{
$this->validateChunkManager($manager);
/** @var Block[] $walkTo */
$walkTo = [];
foreach ($this->nextToCheck as $next) {
$sides = iterator_to_array($this->getHorizontalSides($manager, $next->getPos()));
$walkTo = array_merge($walkTo, array_filter($sides, function (Block $side) use ($walkTo) {
return $side->getId() === 0 && !in_array($side, $walkTo, true) && !in_array($side, $this->walked, true) && !in_array($side, $this->nextToCheck, true) && $side->getPos()->distanceSquared($this->getCenter()) <= ($this->limit / M_PI);
}));
}
$this->walked = array_merge($this->walked, $walkTo);
$this->nextToCheck = $walkTo;
if (!empty($this->nextToCheck)) $this->walk($manager);
return $this->walked;
}
/**
* @param World|AsyncChunkManager $manager
* @param Vector3 $vector3
* @return Generator|Block[]
* @throws InvalidArgumentException
*/
private function getHorizontalSides($manager, Vector3 $vector3): Generator
{
$this->validateChunkManager($manager);
foreach ([Facing::NORTH, Facing::SOUTH, Facing::WEST, Facing::EAST] as $vSide) {
$side = $vector3->getSide($vSide);
if ($manager->getChunk($side->x >> 4, $side->z >> 4) === null) continue;
//$block = API::setComponents($block,$side->x, $side->y, $side->z);
yield $manager->getBlockAt($side->getFloorX(), $side->getFloorY(), $side->getFloorZ());
}
}
public function getTotalCount(): int
{
return $this->limit;
}
/**
* @param World|AsyncChunkManager $chunkManager
* @return array
* @throws InvalidArgumentException
*/
public function getTouchedChunks($chunkManager): array
{
$this->validateChunkManager($chunkManager);
$maxRadius = sqrt($this->limit / M_PI);
$v2center = new Vector2($this->getCenter()->x, $this->getCenter()->z);
$cv2center = new Vector2($this->getCenter()->x >> 4, $this->getCenter()->z >> 4);
$maxX = ($v2center->x + $maxRadius) >> 4;
$minX = ($v2center->x - $maxRadius) >> 4;
$maxZ = ($v2center->y + $maxRadius) >> 4;
$minZ = ($v2center->y - $maxRadius) >> 4;
$cmaxRadius = $cv2center->distanceSquared($minX - 0.5, $minZ - 0.5);
#print "from $minX:$minZ to $maxX:$maxZ" . PHP_EOL;
$touchedChunks = [];
for ($x = $minX - 1; $x <= $maxX + 1; $x++) {
for ($z = $minZ - 1; $z <= $maxZ + 1; $z++) {
if ($cv2center->distanceSquared($x, $z) > $cmaxRadius) continue;
$chunk = $chunkManager->getChunk($x, $z);
if ($chunk === null) {
continue;
}
#print "Touched Chunk at: $x:$z" . PHP_EOL;
$touchedChunks[World::chunkHash($x, $z)] = FastChunkSerializer::serialize($chunk);
}
}
#print "Touched chunks count: " . count($touchedChunks) . PHP_EOL;;
return $touchedChunks;
}
public function getName(): string
{
return "Flood Fill";
}
/**
* @param mixed $manager
* @throws InvalidArgumentException
*/
public function validateChunkManager($manager): void
{
if (!$manager instanceof World && !$manager instanceof AsyncChunkManager) throw new InvalidArgumentException(get_class($manager) . " is not an instance of World or AsyncChunkManager");
}
private function getCenter(): Vector3
{
//UGLY HACK TO IGNORE ERRORS FOR NOW
return new Vector3(0, 0, 0);
}
/**
* Creates a chunk manager used for async editing
* @param Chunk[] $chunks
* @phpstan-param array $chunks
* @return AsyncChunkManager
*/
public static function getChunkManager(array $chunks): AsyncChunkManager
{
$manager = new AsyncChunkManager();
foreach ($chunks as $hash => $chunk) {
World::getXZ($hash, $x, $z);
$manager->setChunk($x, $z, $chunk);
}
return $manager;
}
}
================================================
FILE: src/xenialdan/MagicWE2/tool/WETool.php
================================================