0
0
mirror of https://github.com/pmmp/PocketMine-MP.git synced 2024-11-23 11:36:14 +00:00
PocketMine-MP/tools/simulate-chunk-selector.php
Dylan K. Taylor b5dc72b0ee
tools/simulate-chunk-selector: fixed the script being completely broken
getopt() behaviour is really, really dumb
2023-04-16 16:47:17 +01:00

179 lines
5.8 KiB
PHP

<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\tools\simulate_chunk_selector;
use pocketmine\player\ChunkSelector;
use pocketmine\utils\Utils;
use pocketmine\world\format\Chunk;
use pocketmine\world\World;
use Symfony\Component\Filesystem\Path;
use function count;
use function dirname;
use function fwrite;
use function getopt;
use function imagearc;
use function imagecolorallocate;
use function imagecreatetruecolor;
use function imagefill;
use function imagefilledrectangle;
use function imagepng;
use function imagerectangle;
use function imagesavealpha;
use function is_dir;
use function is_string;
use function mkdir;
use function realpath;
use function scandir;
use function str_pad;
use function strval;
use const SCANDIR_SORT_NONE;
use const STDERR;
use const STR_PAD_LEFT;
require dirname(__DIR__) . '/vendor/autoload.php';
function newImage(int $scale, int $radius) : \GdImage{
$image = Utils::assumeNotFalse(imagecreatetruecolor($scale * $radius * 2, $scale * $radius * 2));
imagesavealpha($image, true);
$black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0));
imagefill($image, 0, 0, $black);
return $image;
}
function render(int $radius, int $baseX, int $baseZ, int $chunksPerStep, int $scale, \GdImage $image, int $chunkColor, int $offsetX, int $offsetZ, string $outputFolder) : void{
echo "Render start: radius $radius, chunks per step $chunksPerStep\n";
$iterator = (new ChunkSelector())->selectChunks($radius, $baseX, $baseZ);
$middleOffsetX = $scale * ($radius + $offsetX);
$middleOffsetZ = $scale * ($radius + $offsetZ);
$black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0));
$yellow = Utils::assumeNotFalse(imagecolorallocate($image, 255, 255, 51));
$red = Utils::assumeNotFalse(imagecolorallocate($image, 255, 0, 0));
$frame = 0;
$seen = [];
while($iterator->valid()){
$frame++;
for($i = 0; $i < $chunksPerStep; ++$i){
$chunkHash = $iterator->current();
if(!isset($seen[$chunkHash])){
$color = $chunkColor;
$seen[$chunkHash] = true;
}else{
$color = $yellow;
}
World::getXZ($chunkHash, $chunkX, $chunkZ);
$imageX = $middleOffsetX + (($chunkX - $baseX) * $scale);
$imageZ = $middleOffsetZ + (($chunkZ - $baseZ) * $scale);
imagefilledrectangle($image, $imageX, $imageZ, $imageX + $scale, $imageZ + $scale, $color);
imagerectangle($image, $imageX, $imageZ, $imageX + $scale, $imageZ + $scale, $black);
$iterator->next();
if(!$iterator->valid()){
break;
}
}
imagearc($image, $middleOffsetX, $middleOffsetZ, $radius * $scale * 2, $radius * $scale * 2, 0, 360, $red);
imagepng($image, Path::join($outputFolder, "frame" . str_pad(strval($frame), 5, "0", STR_PAD_LEFT) . ".png"));
echo "\rRendered step $frame";
}
echo "\n";
}
$radius = null;
$baseX = 10000 >> Chunk::COORD_BIT_SIZE;
$baseZ = 10000 >> Chunk::COORD_BIT_SIZE;
$nChunksPerStep = 32;
$scale = 10;
if(count(getopt("", ["help"])) !== 0){
echo "Required parameters:\n";
echo "--output=path/to/dir: Output folder to put the generated images into (will attempt to create if it doesn't exist)\n";
echo "--radius=N: Radius of chunks to render (default $radius)\n";
echo "\n";
echo "Optional parameters:\n";
echo "--baseX=N: Base X coordinate to use for simulation (default $baseX\n";
echo "--baseZ=N: Base Z coordinate to use for simulation (default $baseZ)\n";
echo "--scale=N: Height/width of square of pixels to use for each chunk (default $scale)\n";
echo "--chunksPerStep=N: Number of chunks to process in each frame (default $nChunksPerStep)\n";
exit(0);
}
$opts = getopt("", ["radius:", "baseX:", "baseZ:", "scale:", "chunksPerStep:", "output:"]);
foreach(["radius", "baseX", "baseZ", "scale", "chunksPerStep"] as $name){
$value = $opts[$name] ?? null;
if($value === null){
continue;
}
if(!is_string($value) || (string) ((int) $value) !== $value){
fwrite(STDERR, "Value for --$name must be an integer\n");
exit(1);
}
$value = (int) $value;
match($name){
"radius" => ($radius = $value),
"baseX" => ($baseX = $value),
"baseZ" => ($baseZ = $value),
"scale" => ($scale = $value),
"chunksPerStep" => ($nChunksPerStep = $value)
};
}
if($radius === null){
fwrite(STDERR, "Please specify a radius using --radius\n");
exit(1);
}
$outputDirectory = null;
if(isset($opts["output"])){
$value = $opts["output"];
if(!is_string($value)){
fwrite(STDERR, "Value for --output be a string\n");
exit(1);
}
if(!@mkdir($value) && !is_dir($value)){
fwrite(STDERR, "Output directory $value could not be created\n");
exit(1);
}
$files = scandir($value, SCANDIR_SORT_NONE);
if($files !== false && count($files) > 2){ //always returns . and ..
fwrite(STDERR, "Output directory $value is not empty\n");
exit(1);
}
$outputDirectory = Utils::assumeNotFalse(realpath($value), "We just created this directory, we should be able to get its realpath");
}
if($outputDirectory === null){
fwrite(STDERR, "Please specify an output directory using --output\n");
exit(1);
}
$image = newImage($scale, $radius);
$green = Utils::assumeNotFalse(imagecolorallocate($image, 0, 220, 0));
render($radius, $baseX, $baseZ, $nChunksPerStep, $scale, $image, $green, 0, 0, $outputDirectory);