Created
September 9, 2023 07:58
-
-
Save Muqsit/f98bb998dbc34a34b3a7dd30a04e99fc to your computer and use it in GitHub Desktop.
Terraforming regions in PocketMine-MP worlds using Scripter plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
use cosmicpe\CosmicPE; | |
use pocketmine\block\Block; | |
use pocketmine\block\BlockTypeIds; | |
use pocketmine\block\Liquid; | |
use pocketmine\block\VanillaBlocks; | |
use pocketmine\event\EventPriority; | |
use pocketmine\event\HandlerListManager; | |
use pocketmine\event\player\PlayerItemUseEvent; | |
use pocketmine\item\ItemTypeIds; | |
use pocketmine\math\Facing; | |
use pocketmine\player\Player; | |
use pocketmine\Server; | |
use pocketmine\world\World; | |
$server = Server::getInstance(); | |
$player = $server->getPlayerExact("NeedleGalaxy"); | |
/** @var CosmicPE $plugin */ | |
$plugin = $server->getPluginManager()->getPlugin("Scripter"); | |
$execute = function(Player $player) : void{ | |
$test_for_top_block = static fn(Block $block) => $block->blocksDirectSkyLight(); | |
$origin = $player->getTargetBlock(100); | |
if($origin === null){ | |
return; | |
} | |
if(!$test_for_top_block($origin)){ | |
$origin = $origin->getSide(Facing::DOWN); | |
if(!$test_for_top_block($origin)){ | |
return; | |
} | |
} | |
$radius = mt_rand(16, 24); | |
$position = $origin->getPosition(); | |
$diff = []; | |
$blocks = []; | |
for($i = -$radius; $i <= $radius; $i++){ | |
for($j = -$radius; $j <= $radius; $j++){ | |
$column_height = $position->y; | |
for($y = $column_height; $y > 0; $y--){ | |
if($test_for_top_block($position->world->getBlockAt($position->x + $i, $y, $position->z + $j))){ | |
$column_height = $y; | |
break; | |
} | |
} | |
$diff[] = $position->y - $column_height; | |
$blocks[World::blockHash($position->x + $i, 0, $position->z + $j)] = $position->world->getBlockAt($position->x + $i, $y, $position->z + $j); | |
} | |
} | |
// Define a kernel for smoothing. This one is a simple 3x3 averaging kernel. | |
// Adjust the weights as you like. | |
$kernel = [ | |
[0.05, 0.1, 0.05], | |
[0.1, 0.4, 0.1], | |
[0.05, 0.1, 0.05] | |
]; | |
$kernelSize = 3; | |
$halfKernel = intdiv($kernelSize, 2); | |
// Create a 2D array for $diff for easier access. | |
$diff2D = []; | |
for($i = 0; $i < 2 * $radius + 1; $i++){ | |
for($j = 0; $j < 2 * $radius + 1; $j++){ | |
$diff2D[$i][$j] = array_shift($diff); | |
} | |
} | |
$adjustTerrainHeight = function($x, $targetY, $z, $originalDiff) use ($blocks ,$position){ | |
$block = $blocks[World::blockHash($x, 0, $z)]; | |
if($block instanceof Liquid){ | |
return; | |
} | |
$currentY = $position->y - $originalDiff; | |
$world = $position->world; | |
if($currentY > $targetY){ | |
// Remove blocks to reach targetY | |
for($y = $currentY; $y > $targetY; $y--){ | |
$world->setBlockAt($x, $y, $z, VanillaBlocks::AIR()); // 0 is usually Air in Minecraft. | |
if($world->getBlockAt($x, $y - 1, $z)->getTypeId() === BlockTypeIds::DIRT){ | |
$world->setBlockAt($x, $y - 1, $z, VanillaBlocks::GRASS(), false); | |
} | |
} | |
}else if($currentY < $targetY){ | |
// Add blocks to reach targetY, for simplicity let's use Dirt blocks | |
for($y = $currentY + 1; $y <= $targetY; $y++){ | |
if($block->getTypeId() === BlockTypeIds::DIRT){ | |
$block = VanillaBlocks::GRASS(); | |
} | |
$world->setBlockAt($x, $y, $z, $block, false); | |
if($world->getBlockAt($x, $y - 1, $z)->getTypeId() === BlockTypeIds::GRASS){ | |
$world->setBlockAt($x, $y - 1, $z, VanillaBlocks::DIRT(), false); | |
} | |
} | |
} | |
}; | |
// Smooth using the kernel | |
for($i = 0; $i < 2 * $radius + 1; $i++){ | |
for($j = 0; $j < 2 * $radius + 1; $j++){ | |
$sum = 0; | |
$weightSum = 0; | |
for($ki = -$halfKernel; $ki <= $halfKernel; $ki++){ | |
for($kj = -$halfKernel; $kj <= $halfKernel; $kj++){ | |
if(isset($diff2D[$i + $ki][$j + $kj])){ | |
$sum += $kernel[$ki + $halfKernel][$kj + $halfKernel] * $diff2D[$i + $ki][$j + $kj]; | |
$weightSum += $kernel[$ki + $halfKernel][$kj + $halfKernel]; | |
} | |
} | |
} | |
$smoothedValue = $sum / $weightSum; | |
// Adjust the block heights in the region based on the smoothed value. | |
$adjustedHeight = $position->y - $smoothedValue; | |
$adjustTerrainHeight($position->x + $i - $radius, $adjustedHeight, $position->z + $j - $radius, $diff2D[$i][$j]); | |
} | |
} | |
}; | |
$listener = $plugin->getServer()->getPluginManager()->registerEvent(PlayerItemUseEvent::class, function(PlayerItemUseEvent $event) use(&$listener, $player, $execute) : void{ | |
if($event->getPlayer() === $player){ | |
if($event->getItem()->getTypeId() !== ItemTypeIds::STICK){ | |
HandlerListManager::global()->getListFor(PlayerItemUseEvent::class)->unregister($listener); | |
return; | |
} | |
$execute($player); | |
} | |
}, EventPriority::NORMAL, $plugin); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a script that can be executed using Scripter.
NeedleGalaxy
to your gamertag/script test.php