├── phpstan.neon ├── icon.png ├── .gitignore ├── .github ├── .media │ ├── logo.png │ └── screenshots │ │ ├── void.png │ │ ├── candyland.png │ │ ├── pirateislands.png │ │ └── winterwonder.png ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE │ ├── feature-request.md │ └── bug-report.md ├── .poggit.yml ├── plugin.yml ├── src └── surva │ └── fancygenerators │ ├── generator │ ├── exception │ │ └── ChunkPopulateException.php │ ├── candyland │ │ ├── object │ │ │ └── CandyTree.php │ │ ├── populator │ │ │ └── CandyTreePopulator.php │ │ └── CandyLand.php │ ├── pirateislands │ │ ├── populator │ │ │ └── JungleTreePopulator.php │ │ └── PirateIslands.php │ ├── winterwonder │ │ ├── populator │ │ │ ├── GiftPopulator.php │ │ │ └── ChristmasTreePopulator.php │ │ ├── WinterWonder.php │ │ └── object │ │ │ ├── Gift.php │ │ │ └── ChristmasTree.php │ └── void │ │ └── VoidGenerator.php │ └── FancyGenerators.php ├── CONTRIBUTING.md ├── LICENSE ├── composer.json ├── CODE_OF_CONDUCT.md ├── .circleci └── config.yml ├── README.md └── composer.lock /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | paths: 4 | - src 5 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE project folder 2 | /.idea 3 | 4 | # Composer dependencies 5 | /vendor 6 | -------------------------------------------------------------------------------- /.github/.media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/.github/.media/logo.png -------------------------------------------------------------------------------- /.github/.media/screenshots/void.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/.github/.media/screenshots/void.png -------------------------------------------------------------------------------- /.github/.media/screenshots/candyland.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/.github/.media/screenshots/candyland.png -------------------------------------------------------------------------------- /.github/.media/screenshots/pirateislands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/.github/.media/screenshots/pirateislands.png -------------------------------------------------------------------------------- /.github/.media/screenshots/winterwonder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/survanetwork/FancyGenerators/HEAD/.github/.media/screenshots/winterwonder.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### 📋 What's this pull request about? 2 | 3 | [ ... ] 4 | 5 | ### 🔧 Is this pull request related to an issue? 6 | 7 | [ ... ] 8 | -------------------------------------------------------------------------------- /.poggit.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | - main 3 | 4 | projects: 5 | FancyGenerators: 6 | path: "" 7 | icon: "icon.png" 8 | lint: 9 | phpstan: false 10 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | name: FancyGenerators 2 | main: surva\fancygenerators\FancyGenerators 3 | version: 1.2.1 4 | api: 5.0.0 5 | 6 | author: survanetwork 7 | description: A collection of new level Generators 8 | website: https://dev.surva.net/plugins/#fancygenerators 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature of a change for this plugin 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 💭 What should be added or changed regarding this plugin? 11 | 12 | [ ... ] 13 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/exception/ChunkPopulateException.php: -------------------------------------------------------------------------------- 1 | setColor(CandyLand::getRandomBlockColor()); 23 | 24 | parent::__construct($quartz, $stainedClay, $treeHeight); 25 | } 26 | 27 | protected function placeTrunk( 28 | int $x, 29 | int $y, 30 | int $z, 31 | Random $random, 32 | int $trunkHeight, 33 | BlockTransaction $transaction 34 | ): void { 35 | parent::placeTrunk($x, $y, $z, $random, $trunkHeight, $transaction); 36 | 37 | $transaction->addBlockAt($x, $y - 1, $z, $this->trunkBlock); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "survanetwork/fancygenerators", 3 | "description": "A collection of new level Generators", 4 | "version": "1.2.1", 5 | "type": "project", 6 | "keywords": [ 7 | "world", 8 | "generator", 9 | "pocketmine", 10 | "void", 11 | "islands" 12 | ], 13 | "homepage": "https://dev.surva.net/plugins/#fancygenerators", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Jarne", 18 | "homepage": "https://github.com/jarne", 19 | "role": "Developer" 20 | } 21 | ], 22 | "support": { 23 | "issues": "https://github.com/survanetwork/FancyGenerators/issues", 24 | "source": "https://github.com/survanetwork/FancyGenerators" 25 | }, 26 | "require-dev": { 27 | "phpstan/phpstan": "^2.1.16", 28 | "pocketmine/pocketmine-mp": "^5.28.2", 29 | "squizlabs/php_codesniffer": "^3.13.0" 30 | }, 31 | "scripts": { 32 | "code-analyze": "./vendor/bin/phpstan analyze -c phpstan.neon", 33 | "code-analyze-save-report": "./vendor/bin/phpstan analyze -c phpstan.neon --error-format junit > test-results/phpstan-result/junit.xml", 34 | "check-format": "./vendor/bin/phpcs --standard=PSR12 src", 35 | "check-format-save-report": "./vendor/bin/phpcs --standard=PSR12 --report=junit src > test-results/phpcs-result/junit.xml", 36 | "fix-format": "./vendor/bin/phpcbf --standard=PSR12 src" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/FancyGenerators.php: -------------------------------------------------------------------------------- 1 | registerGenerators(); 29 | } 30 | 31 | /** 32 | * Register all custom generators of this plugin 33 | */ 34 | private function registerGenerators(): void 35 | { 36 | GeneratorManager::getInstance()->addGenerator(VoidGenerator::class, VoidGenerator::NAME, fn() => null); 37 | GeneratorManager::getInstance()->addGenerator(CandyLand::class, CandyLand::NAME, fn() => null); 38 | GeneratorManager::getInstance()->addGenerator(WinterWonder::class, WinterWonder::NAME, fn() => null); 39 | GeneratorManager::getInstance()->addGenerator(PirateIslands::class, PirateIslands::NAME, fn() => null); 40 | } 41 | 42 | /** 43 | * @return \surva\fancygenerators\FancyGenerators 44 | */ 45 | public static function getInstance(): FancyGenerators 46 | { 47 | if (self::$instance === null) { 48 | throw new RuntimeException("Plugin main class instance not initialized"); 49 | } 50 | 51 | return self::$instance; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/candyland/populator/CandyTreePopulator.php: -------------------------------------------------------------------------------- 1 | nextRange(0, $this->randomAmount) + $this->baseAmount; 26 | 27 | for ($i = 0; $i < $amount; ++$i) { 28 | $chunkXCoord = $chunkX << 4; 29 | $chunkZCoord = $chunkZ << 4; 30 | 31 | $treeX = $random->nextRange($chunkXCoord, $chunkXCoord + 15); 32 | $treeZ = $random->nextRange($chunkZCoord, $chunkZCoord + 15); 33 | $treeY = $this->getHighestTreeBlock($world, $treeX, $treeZ); 34 | 35 | if ($treeY === null) { 36 | continue; 37 | } 38 | 39 | $tree = new CandyTree(); 40 | $transaction = $tree->getBlockTransaction($world, $treeX, $treeY, $treeZ, $random); 41 | $transaction?->apply(); 42 | } 43 | } 44 | 45 | /** 46 | * Get the y + 1 coordinate of the highest block at a specific position 47 | * 48 | * @param \pocketmine\world\ChunkManager $world 49 | * @param int $x 50 | * @param int $z 51 | * 52 | * @return int|null 53 | */ 54 | private function getHighestTreeBlock(ChunkManager $world, int $x, int $z): ?int 55 | { 56 | for ($y = 127; $y >= 0; --$y) { 57 | $block = $world->getBlockAt($x, $y, $z); 58 | $blockId = $block->getTypeId(); 59 | 60 | if ($blockId === BlockTypeIds::STAINED_CLAY) { 61 | return $y + 1; 62 | } 63 | 64 | if ($blockId !== BlockTypeIds::AIR) { 65 | return null; 66 | } 67 | } 68 | 69 | return null; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/pirateislands/populator/JungleTreePopulator.php: -------------------------------------------------------------------------------- 1 | nextRange(0, $this->randomAmount) + $this->baseAmount; 27 | 28 | for ($i = 0; $i < $amount; ++$i) { 29 | $chunkXCoord = $chunkX << 4; 30 | $chunkZCoord = $chunkZ << 4; 31 | 32 | $treeX = $random->nextRange($chunkXCoord, $chunkXCoord + 15); 33 | $treeZ = $random->nextRange($chunkZCoord, $chunkZCoord + 15); 34 | $treeY = $this->getHighestTreeBlock($world, $treeX, $treeZ); 35 | 36 | if ($treeY === null) { 37 | continue; 38 | } 39 | 40 | $tree = TreeFactory::get($random, TreeType::JUNGLE); 41 | $transaction = $tree?->getBlockTransaction($world, $treeX, $treeY, $treeZ, $random); 42 | $transaction?->apply(); 43 | } 44 | } 45 | 46 | /** 47 | * Get the y + 1 coordinate of the highest block at a specific position 48 | * 49 | * @param \pocketmine\world\ChunkManager $world 50 | * @param int $x 51 | * @param int $z 52 | * 53 | * @return int|null 54 | */ 55 | private function getHighestTreeBlock(ChunkManager $world, int $x, int $z): ?int 56 | { 57 | for ($y = 127; $y >= 0; --$y) { 58 | $block = $world->getBlockAt($x, $y, $z); 59 | $blockId = $block->getTypeId(); 60 | 61 | if ($blockId === BlockTypeIds::SANDSTONE) { 62 | return $y + 1; 63 | } 64 | 65 | if ($blockId !== BlockTypeIds::AIR) { 66 | return null; 67 | } 68 | } 69 | 70 | return null; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/winterwonder/populator/GiftPopulator.php: -------------------------------------------------------------------------------- 1 | nextRange(0, $this->randomAmount) + $this->baseAmount; 26 | 27 | for ($i = 0; $i < $amount; ++$i) { 28 | $chunkXCoord = $chunkX << 4; 29 | $chunkZCoord = $chunkZ << 4; 30 | 31 | $treeX = $random->nextRange($chunkXCoord, $chunkXCoord + 15); 32 | $treeZ = $random->nextRange($chunkZCoord, $chunkZCoord + 15); 33 | $treeY = $this->getHighestTreeBlock($world, $treeX, $treeZ); 34 | 35 | if ($treeY === null) { 36 | continue; 37 | } 38 | 39 | $gift = new Gift(); 40 | $transaction = $gift->getBlockTransaction($world, $treeX, $treeY, $treeZ); 41 | $transaction?->apply(); 42 | } 43 | } 44 | 45 | /** 46 | * Get the y + 1 coordinate of the highest block at a specific position 47 | * 48 | * @param \pocketmine\world\ChunkManager $world 49 | * @param int $x 50 | * @param int $z 51 | * 52 | * @return int|null 53 | */ 54 | private function getHighestTreeBlock(ChunkManager $world, int $x, int $z): ?int 55 | { 56 | for ($y = 127; $y >= 0; --$y) { 57 | $block = $world->getBlockAt($x, $y, $z); 58 | $blockId = $block->getTypeId(); 59 | 60 | if ( 61 | $blockId === BlockTypeIds::SNOW || 62 | $blockId === BlockTypeIds::SPRUCE_WOOD || 63 | $blockId === BlockTypeIds::WOOL 64 | ) { 65 | return $y + 1; 66 | } 67 | 68 | if ($blockId !== BlockTypeIds::AIR) { 69 | return null; 70 | } 71 | } 72 | 73 | return null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/winterwonder/populator/ChristmasTreePopulator.php: -------------------------------------------------------------------------------- 1 | nextRange(0, $this->randomAmount) + $this->baseAmount; 26 | 27 | for ($i = 0; $i < $amount; ++$i) { 28 | $chunkXCoord = $chunkX << 4; 29 | $chunkZCoord = $chunkZ << 4; 30 | 31 | $treeX = $random->nextRange($chunkXCoord, $chunkXCoord + 15); 32 | $treeZ = $random->nextRange($chunkZCoord, $chunkZCoord + 15); 33 | $treeY = $this->getHighestTreeBlock($world, $treeX, $treeZ); 34 | 35 | if ($treeY === null) { 36 | continue; 37 | } 38 | 39 | $tree = new ChristmasTree(); 40 | $transaction = $tree->getBlockTransaction($world, $treeX, $treeY, $treeZ); 41 | $transaction?->apply(); 42 | } 43 | } 44 | 45 | /** 46 | * Get the y + 1 coordinate of the highest block at a specific position 47 | * 48 | * @param \pocketmine\world\ChunkManager $world 49 | * @param int $x 50 | * @param int $z 51 | * 52 | * @return int|null 53 | */ 54 | private function getHighestTreeBlock(ChunkManager $world, int $x, int $z): ?int 55 | { 56 | for ($y = 127; $y >= 0; --$y) { 57 | $block = $world->getBlockAt($x, $y, $z); 58 | $blockId = $block->getTypeId(); 59 | 60 | if ( 61 | $blockId === BlockTypeIds::SNOW || 62 | $blockId === BlockTypeIds::SPRUCE_WOOD || 63 | $blockId === BlockTypeIds::WOOL 64 | ) { 65 | return $y + 1; 66 | } 67 | 68 | if ($blockId !== BlockTypeIds::AIR) { 69 | return null; 70 | } 71 | } 72 | 73 | return null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## 📃 Our Pledge 4 | In the interest of fostering an open and welcoming environment, we as 5 | contributors and maintainers pledge to making participation in our project and 6 | our community a harassment-free experience for everyone, regardless of age, body 7 | size, disability, ethnicity, gender identity and expression, level of experience, 8 | education, socio-economic status, nationality, personal appearance, race, 9 | religion, or sexual identity and orientation. 10 | 11 | ## 😉 Our Standards 12 | Examples of behavior that contributes to creating a positive environment 13 | include: 14 | 15 | * Using welcoming and inclusive language 16 | * Being respectful of differing viewpoints and experiences 17 | * Gracefully accepting constructive criticism 18 | * Focusing on what is best for the community 19 | * Showing empathy towards other community members 20 | 21 | Examples of unacceptable behavior by participants include: 22 | 23 | * The use of sexualized language or imagery and unwelcome sexual attention or 24 | advances 25 | * Trolling, insulting/derogatory comments, and personal or political attacks 26 | * Public or private harassment 27 | * Publishing others' private information, such as a physical or electronic 28 | address, without explicit permission 29 | * Other conduct which could reasonably be considered inappropriate in a 30 | professional setting 31 | 32 | ## 👮‍ Our Responsibilities 33 | Project maintainers are responsible for clarifying the standards of acceptable 34 | behavior and are expected to take appropriate and fair corrective action in 35 | response to any instances of unacceptable behavior. 36 | 37 | Project maintainers have the right and responsibility to remove, edit, or 38 | reject comments, commits, code, wiki edits, issues, and other contributions 39 | that are not aligned to this Code of Conduct, or to ban temporarily or 40 | permanently any contributor for other behaviors that they deem inappropriate, 41 | threatening, offensive, or harmful. 42 | 43 | ## 📍 Scope 44 | This Code of Conduct applies both within project spaces and in public spaces 45 | when an individual is representing the project or its community. Examples of 46 | representing a project or community include using an official project e-mail 47 | address, posting via an official social media account, or acting as an appointed 48 | representative at an online or offline event. Representation of a project may be 49 | further defined and clarified by project maintainers. 50 | 51 | ## 👨‍⚖️ Enforcement 52 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 53 | reported by contacting the project team at [opensource@surva.net](mailto:opensource@surva.net). All 54 | complaints will be reviewed and investigated and will result in a response that 55 | is deemed necessary and appropriate to the circumstances. The project team is 56 | obligated to maintain confidentiality with regard to the reporter of an incident. 57 | Further details of specific enforcement policies may be posted separately. 58 | 59 | Project maintainers who do not follow or enforce the Code of Conduct in good 60 | faith may face temporary or permanent repercussions as determined by other 61 | members of the project's leadership. 62 | 63 | ## 🏷 Attribution 64 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 65 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 66 | 67 | [homepage]: https://www.contributor-covenant.org 68 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/candyland/CandyLand.php: -------------------------------------------------------------------------------- 1 | noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 64); 42 | 43 | $treePop = new CandyTreePopulator(); 44 | $this->populators[] = $treePop; 45 | } 46 | 47 | public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 48 | { 49 | $noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16); 50 | 51 | $chunk = $world->getChunk($chunkX, $chunkZ); 52 | 53 | if ($chunk === null) { 54 | FancyGenerators::getInstance()->getLogger()->error("Cannot generate chunk: chunk to generate is null"); 55 | 56 | return; 57 | } 58 | 59 | $bedrock = VanillaBlocks::BEDROCK()->getStateId(); 60 | 61 | for ($x = 0; $x < 16; ++$x) { 62 | for ($z = 0; $z < 16; ++$z) { 63 | for ($y = 0; $y < 128; ++$y) { 64 | if ($y === 0) { 65 | $chunk->setBlockStateId($x, $y, $z, $bedrock); 66 | 67 | continue; 68 | } 69 | 70 | $noiseValue = $noise[$x][$z][$y] - 1 / self::EMPTY_HEIGHT * ($y - self::EMPTY_HEIGHT 71 | - self::MIN_HEIGHT); 72 | 73 | if ($noiseValue > 0) { 74 | $stainedClay = VanillaBlocks::STAINED_CLAY(); 75 | $stainedClay->setColor(self::getRandomBlockColor()); 76 | 77 | $chunk->setBlockStateId($x, $y, $z, $stainedClay->getStateId()); 78 | } 79 | } 80 | } 81 | } 82 | } 83 | 84 | public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 85 | { 86 | foreach ($this->populators as $populator) { 87 | $populator->populate($world, $chunkX, $chunkZ, $this->random); 88 | } 89 | } 90 | 91 | /** 92 | * Get a random color for a block 93 | * 94 | * @return \pocketmine\block\utils\DyeColor 95 | */ 96 | public static function getRandomBlockColor(): DyeColor 97 | { 98 | $colId = rand(self::COLOR_MIN, self::COLOR_MAX); 99 | 100 | return DyeColor::cases()[$colId]; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/winterwonder/WinterWonder.php: -------------------------------------------------------------------------------- 1 | noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 32); 46 | 47 | $this->fullSnow = VanillaBlocks::SNOW()->getStateId(); 48 | $this->fullWood = VanillaBlocks::SPRUCE_WOOD()->getStateId(); 49 | $this->fullRedWool = VanillaBlocks::WOOL()->setColor(DyeColor::RED())->getStateId(); 50 | $this->fullGreenWool = VanillaBlocks::WOOL()->setColor(DyeColor::GREEN())->getStateId(); 51 | 52 | $treePop = new ChristmasTreePopulator(); 53 | $giftPop = new GiftPopulator(); 54 | 55 | $this->populators = [$treePop, $giftPop]; 56 | } 57 | 58 | public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 59 | { 60 | $noise = $this->noiseBase->getFastNoise3D(16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16); 61 | 62 | $chunk = $world->getChunk($chunkX, $chunkZ); 63 | 64 | if ($chunk === null) { 65 | FancyGenerators::getInstance()->getLogger()->error("Cannot generate chunk: chunk to generate is null"); 66 | 67 | return; 68 | } 69 | 70 | $bedrock = VanillaBlocks::BEDROCK()->getStateId(); 71 | 72 | for ($x = 0; $x < 16; ++$x) { 73 | for ($z = 0; $z < 16; ++$z) { 74 | for ($y = 0; $y < 128; ++$y) { 75 | if ($y === 0) { 76 | $chunk->setBlockStateId($x, $y, $z, $bedrock); 77 | 78 | continue; 79 | } 80 | 81 | $noiseValue = $noise[$x][$z][$y] - 1 / self::EMPTY_HEIGHT * ($y - self::EMPTY_HEIGHT 82 | - self::MIN_HEIGHT); 83 | 84 | if ($noiseValue > 0) { 85 | $chunk->setBlockStateId($x, $y, $z, $this->getRandomWinterBlock()); 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 93 | { 94 | foreach ($this->populators as $populator) { 95 | $populator->populate($world, $chunkX, $chunkZ, $this->random); 96 | } 97 | } 98 | 99 | /** 100 | * Get random block for winter ground 101 | * 102 | * @return int 103 | */ 104 | public function getRandomWinterBlock(): int 105 | { 106 | $randId = rand(0, 10); 107 | 108 | if ($randId < 7) { 109 | return $this->fullSnow; 110 | } elseif ($randId < 8) { 111 | return $this->fullWood; 112 | } elseif ($randId < 9) { 113 | return $this->fullRedWool; 114 | } else { 115 | return $this->fullGreenWool; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | aws-cli: circleci/aws-cli@5.4.1 5 | aws-s3: circleci/aws-s3@4.1.2 6 | 7 | jobs: 8 | phpstan: 9 | docker: 10 | - image: cimg/php:8.4 11 | steps: 12 | # Checkout branch 13 | - checkout 14 | 15 | # Install Composer dependencies 16 | - restore_cache: 17 | key: composer-{{ checksum "composer.json" }} 18 | - run: composer install --ignore-platform-reqs 19 | - save_cache: 20 | key: composer-{{ checksum "composer.json" }} 21 | paths: 22 | - vendor 23 | 24 | # Create result folder 25 | - run: mkdir -p test-results/phpstan-result 26 | 27 | # Run code analysis with PHPStan 28 | - run: composer code-analyze-save-report 29 | 30 | # Save code analysis results 31 | - store_test_results: 32 | path: test-results 33 | phpcs: 34 | docker: 35 | - image: cimg/php:8.4 36 | steps: 37 | # Checkout branch 38 | - checkout 39 | 40 | # Install Composer dependencies 41 | - restore_cache: 42 | key: composer-{{ checksum "composer.json" }} 43 | - run: composer install --ignore-platform-reqs 44 | - save_cache: 45 | key: composer-{{ checksum "composer.json" }} 46 | paths: 47 | - vendor 48 | 49 | # Create result folder 50 | - run: mkdir -p test-results/phpcs-result 51 | 52 | # Run code style check with PHP_CodeSniffer 53 | - run: composer check-format-save-report 54 | 55 | # Save code style check results 56 | - store_test_results: 57 | path: test-results 58 | build-phar: 59 | docker: 60 | - image: cimg/php:8.4 61 | steps: 62 | # Checkout branch 63 | - checkout 64 | 65 | # Install dependencies of PHP extensions 66 | - run: sudo apt-get update && sudo apt-get install -y libyaml-dev 67 | 68 | # Manually install PHP extensions 69 | - run: (yes "" || true) | sudo pecl install yaml 70 | 71 | # Clone DevTools sources 72 | - run: git clone https://github.com/pmmp/DevTools.git 73 | 74 | # Create build output folder 75 | - run: mkdir -p build-output 76 | 77 | # Build PHAR with DevTools 78 | - run: php -d phar.readonly=0 DevTools/src/ConsoleScript.php --make plugin.yml,src --out build-output/$CIRCLE_PROJECT_REPONAME$CIRCLE_SHA1.phar 79 | 80 | # Create workspace folder 81 | - run: mkdir -p workspace 82 | 83 | # Copy build output folder into workspace 84 | - run: cp -r build-output workspace/ 85 | 86 | # Save workspace with built PHAR file for release job 87 | - persist_to_workspace: 88 | root: workspace 89 | paths: 90 | - build-output 91 | 92 | # Save built PHAR file as artifact 93 | - store_artifacts: 94 | path: build-output 95 | release-plugin: 96 | docker: 97 | - image: cimg/python:3.13-node 98 | steps: 99 | # Restore workspace with built PHAR file 100 | - attach_workspace: 101 | at: /tmp/workspace 102 | 103 | # Rename PHAR file to release name 104 | - run: cp /tmp/workspace/build-output/$CIRCLE_PROJECT_REPONAME$CIRCLE_SHA1.phar /tmp/workspace/build-output/$CIRCLE_PROJECT_REPONAME$CIRCLE_TAG.phar 105 | 106 | # Upload files to AWS S3 107 | - aws-cli/install 108 | - aws-s3/copy: 109 | from: /tmp/workspace/build-output/$CIRCLE_PROJECT_REPONAME$CIRCLE_TAG.phar 110 | to: "s3://static.surva.net/osplugins/dl/" 111 | 112 | # Update plugin info in CMS 113 | - run: | 114 | curl --location --request PATCH "$CONTENT_URL/items/plugin_info/$PL_INFO_ID" \ 115 | --header "Authorization: Bearer $CONTENT_TOKEN" \ 116 | --header "Content-Type: application/json" \ 117 | --data-raw "{\"version\": \"$CIRCLE_TAG\",\"download_url\": \"https://static.surva.net/osplugins/dl/$CIRCLE_PROJECT_REPONAME$CIRCLE_TAG.phar\"}" 118 | 119 | workflows: 120 | version: 2 121 | code_checks: 122 | jobs: 123 | - phpstan 124 | - phpcs 125 | deploy: 126 | jobs: 127 | - build-phar: 128 | filters: 129 | tags: 130 | only: /.*/ 131 | - release-plugin: 132 | context: os-plugins-deploy 133 | requires: 134 | - build-phar 135 | filters: 136 | tags: 137 | only: /.*/ 138 | branches: 139 | ignore: /.*/ 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | FancyGenerators plugin logo 3 |

4 | 5 |

FancyGenerators

6 |

A collection of new level Generators

7 | 8 |

9 | 10 | Plugin version 11 | 12 | 13 | API version 14 | 15 | 16 | Downloads on Poggit 17 | 18 | 19 | License 20 | 21 | 22 | Discord 23 | 24 | 25 | Website 26 | 27 |

28 | 29 |

30 | 31 | Download FancyGenerators plugin release 32 | FancyGenerators plugin features 33 | 34 |

35 | 36 | ## 📙 Description 37 | FancyGenerators is an experimental plugin project which adds new kinds of world generators to your PocketMine-MP server. 38 | We've implemented some well-known world generators like void with better performance. 39 | We've also added some crazy new world generators creating fantasy worlds. 40 | You can use any compatible world management plugin, e.g. [Worlds by surva](https://dev.surva.net/plugins/#worlds). 41 | 42 | ## 🎁 Features 43 | - **COMMON WORLD GENERATORS** Adds well-known world generators like void with great performance 44 | - **SPECIAL WORLD GENERATORS** Create worlds like never before with our special, crazy world generators 45 | - **COMPATIBILITY** Using the standard API, compatible with every modern world management plugin 46 | 47 | ## 🗺️ Generators 48 | 49 | ### Void 50 | 51 | The void generator just generates an empty world without any blocks, but a small 2x2 planks 52 | platform at the spawn. 53 | 54 | Void generator world screenshot 55 | 56 | ### CandyLand 57 | 58 | CandyLand creates a very colorful world with clay blocks in random colors and 59 | custom colorful trees, also made out of clay blocks. However, it is also the generator 60 | with the worst performance yet, so world generation requires a bit more computing power than 61 | usual (but still runs on most computers). 62 | 63 | CandyLand generator world screenshot 64 | 65 | ### WinterWonder 66 | 67 | WinterWonder generates a beautiful Christmas-themed world with snow-blocks mixed with red and 68 | green decorations of wool. The world is populated with Christmas trees (made of green wool and torches) 69 | and gifts in random colors. 70 | 71 | WinterWonder generator world screenshot 72 | 73 | ### PirateIslands 74 | 75 | PirateIslands creates a huge sea with a constant water level and ground made out of sand and sandstone. 76 | It randomly spawns hilly islands in the water with terrain made out of sandstone and jungle 77 | trees on the islands. 78 | 79 | PirateIslands generator world screenshot 80 | 81 | ## 🖱 Usage 82 | Just drop the plugin file into your server's plugin folder, there is no further configuration or commands required. 83 | 84 | You can use a world management plugin to create world's using the generators. 85 | 86 | Available generators are: 87 | 88 | ``` 89 | void 90 | candyland 91 | winterwonder 92 | pirateislands 93 | ``` 94 | 95 | ### Using the Worlds plugin 96 | 97 | You can download [Worlds by surva here](https://dev.surva.net/plugins/#worlds). Worlds has first-class support for FancyGenerators and is our recommended world management plugin. 98 | 99 | Create a new world using: `/worlds create ` 100 | 101 | E.g., to create a void world named void123, use `/worlds create void123 void`. 102 | 103 | [Ask questions on Discord 💬](https://discord.gg/t4Kg4j3829) 104 | 105 | ## 🙋‍ Contribution 106 | Feel free to contribute if you have ideas or found an issue. 107 | 108 | You can: 109 | - [open an issue](https://github.com/survanetwork/FancyGenerators/issues) (problems, bugs or feature requests) 110 | - [create a pull request](https://github.com/survanetwork/FancyGenerators/pulls) (code contributions like fixed bugs or added features) 111 | 112 | Please read our **[Contribution Guidelines](CONTRIBUTING.md)** before creating an issue or submitting a pull request. 113 | 114 | Many thanks for their support to all contributors! 115 | 116 | ## 👨‍⚖️ License 117 | [MIT](https://github.com/survanetwork/FancyGenerators/blob/master/LICENSE) 118 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/winterwonder/object/Gift.php: -------------------------------------------------------------------------------- 1 | setColor(DyeColor::RED()); 37 | $ribbon->setColor(DyeColor::YELLOW()); 38 | break; 39 | case self::COL_2: 40 | $base->setColor(DyeColor::YELLOW()); 41 | $ribbon->setColor(DyeColor::PURPLE()); 42 | break; 43 | case self::COL_3: 44 | $base->setColor(DyeColor::LIGHT_BLUE()); 45 | $ribbon->setColor(DyeColor::PINK()); 46 | break; 47 | } 48 | 49 | $this->baseBlock = $base; 50 | $this->ribbonBlock = $ribbon; 51 | } 52 | 53 | /** 54 | * Get block transaction for gift object 55 | * 56 | * @param \pocketmine\world\ChunkManager $world 57 | * @param int $x 58 | * @param int $y 59 | * @param int $z 60 | * 61 | * @return \pocketmine\world\BlockTransaction|null 62 | */ 63 | public function getBlockTransaction(ChunkManager $world, int $x, int $y, int $z): ?BlockTransaction 64 | { 65 | if (!$this->canPlaceObject($world, $x, $y, $z)) { 66 | return null; 67 | } 68 | 69 | $transaction = new BlockTransaction($world); 70 | 71 | $this->placeGift($x, $y, $z, $transaction); 72 | 73 | return $transaction; 74 | } 75 | 76 | /** 77 | * Check if a Christmas gift can be placed at this position 78 | * 79 | * @param \pocketmine\world\ChunkManager $world 80 | * @param int $x 81 | * @param int $y 82 | * @param int $z 83 | * 84 | * @return bool 85 | */ 86 | public function canPlaceObject(ChunkManager $world, int $x, int $y, int $z): bool 87 | { 88 | $maxOff = self::CENTER_OFF; 89 | 90 | for ($xx = $x - $maxOff; $xx <= $x + $maxOff; $xx++) { 91 | for ($zz = $z - $maxOff; $zz <= $z + $maxOff; $zz++) { 92 | for ($yy = 0; $yy < self::GIFT_WIDTH; $yy++) { 93 | if (!$world->getBlockAt($xx, $y + $yy, $zz)->canBeReplaced()) { 94 | return false; 95 | } 96 | } 97 | } 98 | } 99 | 100 | return true; 101 | } 102 | 103 | /** 104 | * Place gift object 105 | * 106 | * @param int $x 107 | * @param int $y 108 | * @param int $z 109 | * @param \pocketmine\world\BlockTransaction $transaction 110 | * 111 | * @return void 112 | */ 113 | private function placeGift(int $x, int $y, int $z, BlockTransaction $transaction): void 114 | { 115 | for ($xx = -self::CENTER_OFF; $xx <= self::CENTER_OFF; $xx++) { 116 | for ($yy = 0; $yy < self::GIFT_WIDTH; $yy++) { 117 | if ($transaction->fetchBlockAt($x + $xx, $y + $yy, $z)->canBeReplaced()) { 118 | $transaction->addBlockAt($x + $xx, $y + $yy, $z, $this->ribbonBlock); 119 | } 120 | } 121 | } 122 | 123 | for ($zz = -self::CENTER_OFF; $zz <= self::CENTER_OFF; $zz++) { 124 | for ($yy = 0; $yy < self::GIFT_WIDTH; $yy++) { 125 | if ($transaction->fetchBlockAt($x, $y + $yy, $z + $zz)->canBeReplaced()) { 126 | $transaction->addBlockAt($x, $y + $yy, $z + $zz, $this->ribbonBlock); 127 | } 128 | } 129 | } 130 | 131 | for ($xx = -self::CENTER_OFF; $xx <= self::CENTER_OFF; $xx++) { 132 | for ($zz = -self::CENTER_OFF; $zz <= self::CENTER_OFF; $zz++) { 133 | if ($transaction->fetchBlockAt($x + $xx, $y + self::CENTER_OFF, $z + $zz)->canBeReplaced()) { 134 | $transaction->addBlockAt($x + $xx, $y + self::CENTER_OFF, $z + $zz, $this->ribbonBlock); 135 | } 136 | } 137 | } 138 | 139 | if ($transaction->fetchBlockAt($x, $y + self::GIFT_WIDTH, $z)->canBeReplaced()) { 140 | $transaction->addBlockAt($x, $y + self::GIFT_WIDTH, $z, $this->ribbonBlock); 141 | } 142 | 143 | $baseBlocksOffs = [ 144 | [-1, 0, -1], 145 | [-1, 0, 1], 146 | [1, 0, -1], 147 | [1, 0, 1], 148 | [-1, 2, -1], 149 | [-1, 2, 1], 150 | [1, 2, -1], 151 | [1, 2, 1], 152 | ]; 153 | 154 | foreach ($baseBlocksOffs as $baseBlockOff) { 155 | if ( 156 | $transaction->fetchBlockAt($x + $baseBlockOff[0], $y + $baseBlockOff[1], $z + $baseBlockOff[2]) 157 | ->canBeReplaced() 158 | ) { 159 | $transaction->addBlockAt( 160 | $x + $baseBlockOff[0], 161 | $y + $baseBlockOff[1], 162 | $z + $baseBlockOff[2], 163 | $this->baseBlock 164 | ); 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/void/VoidGenerator.php: -------------------------------------------------------------------------------- 1 | defaultSpawn = new Vector3(256, 65, 256); 45 | 46 | $this->spawnChunkX = (int) $this->defaultSpawn->getX() >> 4; 47 | $this->spawnChunkZ = (int) $this->defaultSpawn->getZ() >> 4; 48 | 49 | $this->xNbSpawnChunkX = $this->spawnChunkX; 50 | $this->xNbSpawnChunkZ = ((int) $this->defaultSpawn->getZ() - 1) >> 4; 51 | 52 | $this->zNbSpawnChunkX = ((int) $this->defaultSpawn->getX() - 1) >> 4; 53 | $this->zNbSpawnChunkZ = $this->spawnChunkZ; 54 | 55 | $this->bothNbSpawnChunkX = ((int) $this->defaultSpawn->getX() - 1) >> 4; 56 | $this->bothNbSpawnChunkZ = ((int) $this->defaultSpawn->getZ() - 1) >> 4; 57 | } 58 | 59 | /** 60 | * Generate one of the first chunks including the start blocks 61 | * 62 | * @param \pocketmine\world\ChunkManager $world 63 | * @param int $chunkX 64 | * @param int $chunkZ 65 | * @param int $whichChunk 66 | * 67 | * @return \pocketmine\world\format\Chunk 68 | * @throws \surva\fancygenerators\generator\exception\ChunkPopulateException 69 | */ 70 | private function generateFirstChunk(ChunkManager $world, int $chunkX, int $chunkZ, int $whichChunk): Chunk 71 | { 72 | $chunk = $world->getChunk($chunkX, $chunkZ); 73 | 74 | if ($chunk === null) { 75 | throw new ChunkPopulateException("first chunk is null"); 76 | } 77 | 78 | $spawn = $this->defaultSpawn; 79 | $underSpawn = $spawn->subtract(0, 1, 0); 80 | $yUnderSpawn = (int) $underSpawn->getY(); 81 | 82 | $planks = VanillaBlocks::OAK_PLANKS()->getStateId(); 83 | 84 | switch ($whichChunk) { 85 | case self::SPAWN: 86 | for ($x = 0; $x <= 1; $x++) { 87 | for ($z = 0; $z <= 1; $z++) { 88 | $chunk->setBlockStateId($x, $yUnderSpawn, $z, $planks); 89 | } 90 | } 91 | break; 92 | case self::NB_X: 93 | $chunk->setBlockStateId(0, $yUnderSpawn, 15, $planks); 94 | $chunk->setBlockStateId(1, $yUnderSpawn, 15, $planks); 95 | break; 96 | case self::NB_Z: 97 | $chunk->setBlockStateId(15, $yUnderSpawn, 0, $planks); 98 | $chunk->setBlockStateId(15, $yUnderSpawn, 1, $planks); 99 | break; 100 | case self::NB_BOTH: 101 | $chunk->setBlockStateId(15, $yUnderSpawn, 15, $planks); 102 | break; 103 | } 104 | 105 | return $chunk; 106 | } 107 | 108 | /** 109 | * Generate a basic empty chunk 110 | * 111 | * @param \pocketmine\world\ChunkManager $world 112 | * @param int $chunkX 113 | * @param int $chunkZ 114 | * 115 | * @return \pocketmine\world\format\Chunk 116 | * @throws \surva\fancygenerators\generator\exception\ChunkPopulateException 117 | */ 118 | private function generateBaseChunk(ChunkManager $world, int $chunkX, int $chunkZ): Chunk 119 | { 120 | $chunk = $world->getChunk($chunkX, $chunkZ); 121 | 122 | if ($chunk === null) { 123 | throw new ChunkPopulateException("chunk to generate is null"); 124 | } 125 | 126 | return $chunk; 127 | } 128 | 129 | public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 130 | { 131 | try { 132 | if ($chunkX === $this->spawnChunkX and $chunkZ === $this->spawnChunkZ) { 133 | $chunk = $this->generateFirstChunk($world, $chunkX, $chunkZ, self::SPAWN); 134 | } elseif ($chunkX === $this->xNbSpawnChunkX and $chunkZ === $this->xNbSpawnChunkZ) { 135 | $chunk = $this->generateFirstChunk($world, $chunkX, $chunkZ, self::NB_X); 136 | } elseif ($chunkX === $this->zNbSpawnChunkX and $chunkZ === $this->zNbSpawnChunkZ) { 137 | $chunk = $this->generateFirstChunk($world, $chunkX, $chunkZ, self::NB_Z); 138 | } elseif ($chunkX === $this->bothNbSpawnChunkX and $chunkZ === $this->bothNbSpawnChunkZ) { 139 | $chunk = $this->generateFirstChunk($world, $chunkX, $chunkZ, self::NB_BOTH); 140 | } else { 141 | $chunk = $this->generateBaseChunk($world, $chunkX, $chunkZ); 142 | } 143 | } catch (ChunkPopulateException $ex) { 144 | FancyGenerators::getInstance()->getLogger()->error("Cannot generate void chunk: " . $ex->getMessage()); 145 | 146 | return; 147 | } 148 | 149 | $world->setChunk($chunkX, $chunkZ, $chunk); 150 | } 151 | 152 | public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 153 | { 154 | // no population needed 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/pirateislands/PirateIslands.php: -------------------------------------------------------------------------------- 1 | noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 64); 48 | $this->populators[] = new JungleTreePopulator(); 49 | 50 | $this->generateBaseGroundSubChunk(); 51 | } 52 | 53 | /** 54 | * Generate a basic "beach-like" ground sub chunk 55 | */ 56 | private function generateBaseGroundSubChunk(): void 57 | { 58 | // @phpstan-ignore class.notFound 59 | $subChunk = new SubChunk(Block::EMPTY_STATE_ID, [], new PalettedBlockArray(BiomeIds::OCEAN)); 60 | 61 | $sandStone = VanillaBlocks::SANDSTONE()->getStateId(); 62 | $sand = VanillaBlocks::SAND()->getStateId(); 63 | $water = VanillaBlocks::WATER()->getStateId(); 64 | 65 | for ($y = 0; $y < self::WATER_UNTIL; $y++) { 66 | for ($z = 0; $z < 16; $z++) { 67 | for ($x = 0; $x < 16; $x++) { 68 | if ($y < self::SANDSTONE_UNTIL) { 69 | $subChunk->setBlockStateId($x, $y, $z, $sandStone); 70 | } elseif ($y < self::SAND_UNTIL) { 71 | $subChunk->setBlockStateId($x, $y, $z, $sand); 72 | } else { 73 | $subChunk->setBlockStateId($x, $y, $z, $water); 74 | } 75 | } 76 | } 77 | } 78 | 79 | $this->baseGroundSubChunk = $subChunk; 80 | } 81 | 82 | public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 83 | { 84 | $chunk = $world->getChunk($chunkX, $chunkZ); 85 | 86 | if ($chunk === null) { 87 | FancyGenerators::getInstance()->getLogger()->error("Cannot generate chunk: chunk to generate is null"); 88 | 89 | return; 90 | } 91 | 92 | $subChunk = clone $this->baseGroundSubChunk; 93 | $chunk->setSubChunk(self::GROUND_CHUNK, $subChunk); 94 | 95 | $yOffs = self::GROUND_CHUNK * 16 + self::SAND_UNTIL; 96 | $noise = $this->noiseBase->getFastNoise3D( 97 | 16, 98 | 128, 99 | 16, 100 | 4, 101 | 64, 102 | 4, 103 | $chunkX * 16, 104 | $yOffs, 105 | $chunkZ * 16 106 | ); 107 | $sandStone = VanillaBlocks::SANDSTONE()->getStateId(); 108 | 109 | for ($x = 0; $x < 16; ++$x) { 110 | for ($z = 0; $z < 16; ++$z) { 111 | $worldX = $chunkX * 16 + $x; 112 | $worldZ = $chunkZ * 16 + $z; 113 | 114 | // check if we're inside an island cell 115 | $cellX = intdiv($worldX, self::ISLAND_CELL_SIZE); 116 | $cellZ = intdiv($worldZ, self::ISLAND_CELL_SIZE); 117 | 118 | $cellRand = new Random(crc32("isl$cellX$cellZ")); 119 | if ($cellRand->nextFloat() < 0.2) { 120 | continue; // no island in this cell 121 | } 122 | 123 | // distance to island center 124 | $centerX = $cellX * self::ISLAND_CELL_SIZE + self::ISLAND_CELL_SIZE / 2; 125 | $centerZ = $cellZ * self::ISLAND_CELL_SIZE + self::ISLAND_CELL_SIZE / 2; 126 | 127 | // randomize position of the island inside its cell 128 | $offsetX = $cellRand->nextBoundedInt(21) - 10; // -10 to +10 129 | $offsetZ = $cellRand->nextBoundedInt(21) - 10; 130 | 131 | $centerX += $offsetX; 132 | $centerZ += $offsetZ; 133 | 134 | // check our distance to the island center 135 | $dx = $worldX - $centerX; 136 | $dz = $worldZ - $centerZ; 137 | $distance = sqrt($dx * $dx + $dz * $dz); 138 | 139 | if ($distance > self::ISLAND_RADIUS) { 140 | continue; // outside island radius 141 | } 142 | 143 | // prepare island terrain and falloff 144 | $edgeDrop = 4; 145 | $radialFalloff = pow(1 - ($distance / self::ISLAND_RADIUS), 2); 146 | 147 | $heightShift = (1 - $radialFalloff) * $edgeDrop; 148 | 149 | $verticalBase = $yOffs + 5; 150 | $baseHeight = $verticalBase + $cellRand->nextBoundedInt(6) - 3; 151 | 152 | for ($y = 0; $y < 128; ++$y) { 153 | // generate terrain 154 | $terrainValue = $noise[$x][$z][$y]; 155 | $verticalFalloff = ($y - ($baseHeight - $heightShift)) * 0.08; 156 | 157 | $value = ($terrainValue * $radialFalloff) - $verticalFalloff; 158 | 159 | if ($value > 0.2) { 160 | $chunk->setBlockStateId($x, $y, $z, $sandStone); 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ): void 168 | { 169 | foreach ($this->populators as $populator) { 170 | $populator->populate($world, $chunkX, $chunkZ, $this->random); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/surva/fancygenerators/generator/winterwonder/object/ChristmasTree.php: -------------------------------------------------------------------------------- 1 | setColor(DyeColor::GREEN()); 32 | 33 | $this->trunkBlock = $wood; 34 | $this->leafBlock = $greenWool; 35 | 36 | $this->trunkHeight = $trunkHeight; 37 | $this->canopyHeight = $canopyHeight; 38 | } 39 | 40 | /** 41 | * Get block transaction for Christmas tree 42 | * 43 | * @param \pocketmine\world\ChunkManager $world 44 | * @param int $x 45 | * @param int $y 46 | * @param int $z 47 | * 48 | * @return \pocketmine\world\BlockTransaction|null 49 | */ 50 | public function getBlockTransaction(ChunkManager $world, int $x, int $y, int $z): ?BlockTransaction 51 | { 52 | if (!$this->canPlaceObject($world, $x, $y, $z)) { 53 | return null; 54 | } 55 | 56 | $transaction = new BlockTransaction($world); 57 | 58 | $this->placeTrunk($x, $y, $z, $transaction); 59 | $this->placeCanopy($x, $y, $z, $transaction); 60 | $this->placeTorches($x, $y, $z, $transaction); 61 | 62 | return $transaction; 63 | } 64 | 65 | /** 66 | * Check if a Christmas tree can be placed at this position 67 | * 68 | * @param \pocketmine\world\ChunkManager $world 69 | * @param int $x 70 | * @param int $y 71 | * @param int $z 72 | * 73 | * @return bool 74 | */ 75 | public function canPlaceObject(ChunkManager $world, int $x, int $y, int $z): bool 76 | { 77 | for ($yy = 0; $yy < $this->trunkHeight; $yy++) { // check trunk 78 | if (!$world->getBlockAt($x, $y + $yy, $z)->canBeReplaced()) { 79 | return false; 80 | } 81 | } 82 | 83 | $maxOff = ($this->canopyHeight - 1) / 2; 84 | 85 | for ($xx = $x - $maxOff; $xx <= $x + $maxOff; $xx++) { // check canopy 86 | for ($zz = $z - $maxOff; $zz <= $z + $maxOff; $zz++) { 87 | for ($yy = 0; $yy <= $this->canopyHeight; $yy++) { 88 | if (!$world->getBlockAt($xx, $y + $this->trunkHeight + $yy, $zz)->canBeReplaced()) { 89 | return false; 90 | } 91 | } 92 | } 93 | } 94 | 95 | return true; 96 | } 97 | 98 | /** 99 | * Place Christmas tree trunk 100 | * 101 | * @param int $x 102 | * @param int $y 103 | * @param int $z 104 | * @param \pocketmine\world\BlockTransaction $transaction 105 | * 106 | * @return void 107 | */ 108 | private function placeTrunk(int $x, int $y, int $z, BlockTransaction $transaction): void 109 | { 110 | for ($yy = 0; $yy < $this->trunkHeight; $yy++) { 111 | if ($transaction->fetchBlockAt($x, $y + $yy, $z)->canBeReplaced()) { 112 | $transaction->addBlockAt($x, $y + $yy, $z, $this->trunkBlock); 113 | } 114 | } 115 | } 116 | 117 | /** 118 | * Place Christmas tree canopy 119 | * 120 | * @param int $x 121 | * @param int $y 122 | * @param int $z 123 | * @param \pocketmine\world\BlockTransaction $transaction 124 | * 125 | * @return void 126 | */ 127 | private function placeCanopy(int $x, int $y, int $z, BlockTransaction $transaction): void 128 | { 129 | for ($levelY = 0; $levelY < $this->canopyHeight; $levelY++) { // height levels 130 | $levelGlobalY = $y + $this->trunkHeight + $levelY; 131 | 132 | $diameter = $this->canopyHeight - (intdiv($levelY, 2) * 2); 133 | $radius = ($diameter - 1) / 2; 134 | 135 | for ($xx = $x - $radius; $xx <= $x + $radius; $xx++) { // build base line x 136 | if ($transaction->fetchBlockAt($xx, $levelGlobalY, $z)->canBeReplaced()) { 137 | $transaction->addBlockAt($xx, $levelGlobalY, $z, $this->leafBlock); 138 | } 139 | } 140 | 141 | for ($zz = $z - $radius; $zz <= $z + $radius; $zz++) { // build base line z 142 | if ($transaction->fetchBlockAt($x, $levelGlobalY, $zz)->canBeReplaced()) { 143 | $transaction->addBlockAt($x, $levelGlobalY, $zz, $this->leafBlock); 144 | } 145 | } 146 | 147 | for ($dd = $diameter - 2; $dd > 2; $dd -= 2) { // down to lowest diameter 148 | $this->placeSquare( 149 | $x, 150 | $levelGlobalY, 151 | $z, 152 | $dd, 153 | $dd - 2, 154 | $this->leafBlock, 155 | $transaction 156 | ); // place first square 157 | $this->placeSquare( 158 | $x, 159 | $levelGlobalY, 160 | $z, 161 | $dd - 2, 162 | $dd, 163 | $this->leafBlock, 164 | $transaction 165 | ); // place second square 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * Place some torches on the Christmas tree 172 | * 173 | * @param int $x 174 | * @param int $y 175 | * @param int $z 176 | * @param \pocketmine\world\BlockTransaction $transaction 177 | * 178 | * @return void 179 | */ 180 | private function placeTorches(int $x, int $y, int $z, BlockTransaction $transaction): void 181 | { 182 | $maxDiameter = $this->canopyHeight - 3; 183 | $maxOff = $maxDiameter / 2; 184 | 185 | $maxY = $y + $this->trunkHeight + $this->canopyHeight; 186 | 187 | $torchesAmount = rand(2, 6); 188 | for ($i = 0; $i < $torchesAmount; $i++) { 189 | $randX = rand($x - $maxOff, $x + $maxOff); 190 | $randZ = rand($z - $maxOff, $z + $maxOff); 191 | 192 | $tY = $this->getHighestTreeBlockAt($randX, $randZ, $maxY, $transaction); 193 | 194 | $transaction->addBlockAt($randX, $tY + 1, $randZ, VanillaBlocks::TORCH()); 195 | } 196 | } 197 | 198 | /** 199 | * Place a square 200 | * 201 | * @param int $x 202 | * @param int $y 203 | * @param int $z 204 | * @param int $length 205 | * @param int $width 206 | * @param \pocketmine\block\Block $block 207 | * @param \pocketmine\world\BlockTransaction $transaction 208 | * 209 | * @return void 210 | */ 211 | private function placeSquare( 212 | int $x, 213 | int $y, 214 | int $z, 215 | int $length, 216 | int $width, 217 | Block $block, 218 | BlockTransaction $transaction 219 | ): void { 220 | $halfLength = ($length - 1) / 2; 221 | $halfWidth = ($width - 1) / 2; 222 | 223 | for ($xx = $x - $halfLength; $xx <= $x + $halfLength; $xx++) { 224 | for ($zz = $z - $halfWidth; $zz <= $z + $halfWidth; $zz++) { 225 | if ($transaction->fetchBlockAt($xx, $y, $zz)->canBeReplaced()) { 226 | $transaction->addBlockAt($xx, $y, $zz, $block); 227 | } 228 | } 229 | } 230 | } 231 | 232 | /** 233 | * Get the highest tree block y coordinate at an x/z position 234 | * 235 | * @param int $x 236 | * @param int $z 237 | * @param int $maxY 238 | * @param \pocketmine\world\BlockTransaction $transaction 239 | * 240 | * @return int|null 241 | */ 242 | private function getHighestTreeBlockAt(int $x, int $z, int $maxY, BlockTransaction $transaction): ?int 243 | { 244 | for ($y = $maxY; $y > 0; $y--) { 245 | $idAt = $transaction->fetchBlockAt($x, $y, $z)->getTypeId(); 246 | 247 | if ($idAt === BlockTypeIds::WOOL) { 248 | return $y; 249 | } 250 | 251 | if ($idAt !== BlockTypeIds::AIR) { 252 | return null; 253 | } 254 | } 255 | 256 | return null; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "ea76d0955706588e3b4227bef1ff6a27", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "adhocore/json-comment", 12 | "version": "1.2.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/adhocore/php-json-comment.git", 16 | "reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/651023f9fe52e9efa2198cbaf6e481d1968e2377", 21 | "reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "ext-ctype": "*", 26 | "php": ">=7.0" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^6.5 || ^7.5 || ^8.5" 30 | }, 31 | "type": "library", 32 | "autoload": { 33 | "psr-4": { 34 | "Ahc\\Json\\": "src/" 35 | } 36 | }, 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "MIT" 40 | ], 41 | "authors": [ 42 | { 43 | "name": "Jitendra Adhikari", 44 | "email": "jiten.adhikary@gmail.com" 45 | } 46 | ], 47 | "description": "Lightweight JSON comment stripper library for PHP", 48 | "keywords": [ 49 | "comment", 50 | "json", 51 | "strip-comment" 52 | ], 53 | "support": { 54 | "issues": "https://github.com/adhocore/php-json-comment/issues", 55 | "source": "https://github.com/adhocore/php-json-comment/tree/1.2.1" 56 | }, 57 | "funding": [ 58 | { 59 | "url": "https://paypal.me/ji10", 60 | "type": "custom" 61 | }, 62 | { 63 | "url": "https://github.com/adhocore", 64 | "type": "github" 65 | } 66 | ], 67 | "time": "2022-10-02T11:22:07+00:00" 68 | }, 69 | { 70 | "name": "brick/math", 71 | "version": "0.12.3", 72 | "source": { 73 | "type": "git", 74 | "url": "https://github.com/brick/math.git", 75 | "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", 80 | "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", 81 | "shasum": "" 82 | }, 83 | "require": { 84 | "php": "^8.1" 85 | }, 86 | "require-dev": { 87 | "php-coveralls/php-coveralls": "^2.2", 88 | "phpunit/phpunit": "^10.1", 89 | "vimeo/psalm": "6.8.8" 90 | }, 91 | "type": "library", 92 | "autoload": { 93 | "psr-4": { 94 | "Brick\\Math\\": "src/" 95 | } 96 | }, 97 | "notification-url": "https://packagist.org/downloads/", 98 | "license": [ 99 | "MIT" 100 | ], 101 | "description": "Arbitrary-precision arithmetic library", 102 | "keywords": [ 103 | "Arbitrary-precision", 104 | "BigInteger", 105 | "BigRational", 106 | "arithmetic", 107 | "bigdecimal", 108 | "bignum", 109 | "bignumber", 110 | "brick", 111 | "decimal", 112 | "integer", 113 | "math", 114 | "mathematics", 115 | "rational" 116 | ], 117 | "support": { 118 | "issues": "https://github.com/brick/math/issues", 119 | "source": "https://github.com/brick/math/tree/0.12.3" 120 | }, 121 | "funding": [ 122 | { 123 | "url": "https://github.com/BenMorel", 124 | "type": "github" 125 | } 126 | ], 127 | "time": "2025-02-28T13:11:00+00:00" 128 | }, 129 | { 130 | "name": "netresearch/jsonmapper", 131 | "version": "v5.0.0", 132 | "source": { 133 | "type": "git", 134 | "url": "https://github.com/cweiske/jsonmapper.git", 135 | "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c" 136 | }, 137 | "dist": { 138 | "type": "zip", 139 | "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", 140 | "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", 141 | "shasum": "" 142 | }, 143 | "require": { 144 | "ext-json": "*", 145 | "ext-pcre": "*", 146 | "ext-reflection": "*", 147 | "ext-spl": "*", 148 | "php": ">=7.1" 149 | }, 150 | "require-dev": { 151 | "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", 152 | "squizlabs/php_codesniffer": "~3.5" 153 | }, 154 | "type": "library", 155 | "autoload": { 156 | "psr-0": { 157 | "JsonMapper": "src/" 158 | } 159 | }, 160 | "notification-url": "https://packagist.org/downloads/", 161 | "license": [ 162 | "OSL-3.0" 163 | ], 164 | "authors": [ 165 | { 166 | "name": "Christian Weiske", 167 | "email": "cweiske@cweiske.de", 168 | "homepage": "http://github.com/cweiske/jsonmapper/", 169 | "role": "Developer" 170 | } 171 | ], 172 | "description": "Map nested JSON structures onto PHP classes", 173 | "support": { 174 | "email": "cweiske@cweiske.de", 175 | "issues": "https://github.com/cweiske/jsonmapper/issues", 176 | "source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0" 177 | }, 178 | "time": "2024-09-08T10:20:00+00:00" 179 | }, 180 | { 181 | "name": "phpstan/phpstan", 182 | "version": "2.1.16", 183 | "source": { 184 | "type": "git", 185 | "url": "https://github.com/phpstan/phpstan.git", 186 | "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9" 187 | }, 188 | "dist": { 189 | "type": "zip", 190 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9", 191 | "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9", 192 | "shasum": "" 193 | }, 194 | "require": { 195 | "php": "^7.4|^8.0" 196 | }, 197 | "conflict": { 198 | "phpstan/phpstan-shim": "*" 199 | }, 200 | "bin": [ 201 | "phpstan", 202 | "phpstan.phar" 203 | ], 204 | "type": "library", 205 | "autoload": { 206 | "files": [ 207 | "bootstrap.php" 208 | ] 209 | }, 210 | "notification-url": "https://packagist.org/downloads/", 211 | "license": [ 212 | "MIT" 213 | ], 214 | "description": "PHPStan - PHP Static Analysis Tool", 215 | "keywords": [ 216 | "dev", 217 | "static analysis" 218 | ], 219 | "support": { 220 | "docs": "https://phpstan.org/user-guide/getting-started", 221 | "forum": "https://github.com/phpstan/phpstan/discussions", 222 | "issues": "https://github.com/phpstan/phpstan/issues", 223 | "security": "https://github.com/phpstan/phpstan/security/policy", 224 | "source": "https://github.com/phpstan/phpstan-src" 225 | }, 226 | "funding": [ 227 | { 228 | "url": "https://github.com/ondrejmirtes", 229 | "type": "github" 230 | }, 231 | { 232 | "url": "https://github.com/phpstan", 233 | "type": "github" 234 | } 235 | ], 236 | "time": "2025-05-16T09:40:10+00:00" 237 | }, 238 | { 239 | "name": "pocketmine/bedrock-block-upgrade-schema", 240 | "version": "5.1.0", 241 | "source": { 242 | "type": "git", 243 | "url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git", 244 | "reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a" 245 | }, 246 | "dist": { 247 | "type": "zip", 248 | "url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/2218512e4b91f5bfd09ef55f7a4c4b04e169e41a", 249 | "reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a", 250 | "shasum": "" 251 | }, 252 | "type": "library", 253 | "notification-url": "https://packagist.org/downloads/", 254 | "license": [ 255 | "CC0-1.0" 256 | ], 257 | "description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves", 258 | "support": { 259 | "issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues", 260 | "source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/5.1.0" 261 | }, 262 | "time": "2025-02-11T17:41:44+00:00" 263 | }, 264 | { 265 | "name": "pocketmine/bedrock-data", 266 | "version": "5.0.0+bedrock-1.21.80", 267 | "source": { 268 | "type": "git", 269 | "url": "https://github.com/pmmp/BedrockData.git", 270 | "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080" 271 | }, 272 | "dist": { 273 | "type": "zip", 274 | "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e38d5ea19f794ec5216e5f96742237e8c4e7f080", 275 | "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080", 276 | "shasum": "" 277 | }, 278 | "type": "library", 279 | "notification-url": "https://packagist.org/downloads/", 280 | "license": [ 281 | "CC0-1.0" 282 | ], 283 | "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP", 284 | "support": { 285 | "issues": "https://github.com/pmmp/BedrockData/issues", 286 | "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.80" 287 | }, 288 | "time": "2025-05-09T14:15:18+00:00" 289 | }, 290 | { 291 | "name": "pocketmine/bedrock-item-upgrade-schema", 292 | "version": "1.14.0", 293 | "source": { 294 | "type": "git", 295 | "url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git", 296 | "reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb" 297 | }, 298 | "dist": { 299 | "type": "zip", 300 | "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/9fc7c9bbb558a017395c1cb7dd819c033ee971bb", 301 | "reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb", 302 | "shasum": "" 303 | }, 304 | "type": "library", 305 | "notification-url": "https://packagist.org/downloads/", 306 | "license": [ 307 | "CC0-1.0" 308 | ], 309 | "description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves", 310 | "support": { 311 | "issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues", 312 | "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.14.0" 313 | }, 314 | "time": "2024-12-04T12:22:49+00:00" 315 | }, 316 | { 317 | "name": "pocketmine/bedrock-protocol", 318 | "version": "38.0.1+bedrock-1.21.80", 319 | "source": { 320 | "type": "git", 321 | "url": "https://github.com/pmmp/BedrockProtocol.git", 322 | "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f" 323 | }, 324 | "dist": { 325 | "type": "zip", 326 | "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f", 327 | "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f", 328 | "shasum": "" 329 | }, 330 | "require": { 331 | "ext-json": "*", 332 | "php": "^8.1", 333 | "pocketmine/binaryutils": "^0.2.0", 334 | "pocketmine/color": "^0.2.0 || ^0.3.0", 335 | "pocketmine/math": "^0.3.0 || ^0.4.0 || ^1.0.0", 336 | "pocketmine/nbt": "^1.0.0", 337 | "ramsey/uuid": "^4.1" 338 | }, 339 | "require-dev": { 340 | "phpstan/phpstan": "2.1.0", 341 | "phpstan/phpstan-phpunit": "^2.0.0", 342 | "phpstan/phpstan-strict-rules": "^2.0.0", 343 | "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0" 344 | }, 345 | "type": "library", 346 | "autoload": { 347 | "psr-4": { 348 | "pocketmine\\network\\mcpe\\protocol\\": "src/" 349 | } 350 | }, 351 | "notification-url": "https://packagist.org/downloads/", 352 | "license": [ 353 | "LGPL-3.0" 354 | ], 355 | "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", 356 | "support": { 357 | "issues": "https://github.com/pmmp/BedrockProtocol/issues", 358 | "source": "https://github.com/pmmp/BedrockProtocol/tree/38.0.1+bedrock-1.21.80" 359 | }, 360 | "time": "2025-05-17T11:56:33+00:00" 361 | }, 362 | { 363 | "name": "pocketmine/binaryutils", 364 | "version": "0.2.6", 365 | "source": { 366 | "type": "git", 367 | "url": "https://github.com/pmmp/BinaryUtils.git", 368 | "reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84" 369 | }, 370 | "dist": { 371 | "type": "zip", 372 | "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/ccfc1899b859d45814ea3592e20ebec4cb731c84", 373 | "reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84", 374 | "shasum": "" 375 | }, 376 | "require": { 377 | "php": "^7.4 || ^8.0", 378 | "php-64bit": "*" 379 | }, 380 | "require-dev": { 381 | "phpstan/extension-installer": "^1.0", 382 | "phpstan/phpstan": "~1.10.3", 383 | "phpstan/phpstan-phpunit": "^1.0", 384 | "phpstan/phpstan-strict-rules": "^1.0.0", 385 | "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0" 386 | }, 387 | "type": "library", 388 | "autoload": { 389 | "psr-4": { 390 | "pocketmine\\utils\\": "src/" 391 | } 392 | }, 393 | "notification-url": "https://packagist.org/downloads/", 394 | "license": [ 395 | "LGPL-3.0" 396 | ], 397 | "description": "Classes and methods for conveniently handling binary data", 398 | "support": { 399 | "issues": "https://github.com/pmmp/BinaryUtils/issues", 400 | "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.6" 401 | }, 402 | "time": "2024-03-04T15:04:17+00:00" 403 | }, 404 | { 405 | "name": "pocketmine/callback-validator", 406 | "version": "1.0.3", 407 | "source": { 408 | "type": "git", 409 | "url": "https://github.com/pmmp/CallbackValidator.git", 410 | "reference": "64787469766bcaa7e5885242e85c23c25e8c55a2" 411 | }, 412 | "dist": { 413 | "type": "zip", 414 | "url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/64787469766bcaa7e5885242e85c23c25e8c55a2", 415 | "reference": "64787469766bcaa7e5885242e85c23c25e8c55a2", 416 | "shasum": "" 417 | }, 418 | "require": { 419 | "ext-reflection": "*", 420 | "php": "^7.1 || ^8.0" 421 | }, 422 | "replace": { 423 | "daverandom/callback-validator": "*" 424 | }, 425 | "require-dev": { 426 | "phpstan/extension-installer": "^1.0", 427 | "phpstan/phpstan": "0.12.59", 428 | "phpstan/phpstan-strict-rules": "^0.12.4", 429 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0" 430 | }, 431 | "type": "library", 432 | "autoload": { 433 | "psr-4": { 434 | "DaveRandom\\CallbackValidator\\": "src/" 435 | } 436 | }, 437 | "notification-url": "https://packagist.org/downloads/", 438 | "license": [ 439 | "MIT" 440 | ], 441 | "authors": [ 442 | { 443 | "name": "Chris Wright", 444 | "email": "cw@daverandom.com" 445 | } 446 | ], 447 | "description": "Fork of daverandom/callback-validator - Tools for validating callback signatures", 448 | "support": { 449 | "issues": "https://github.com/pmmp/CallbackValidator/issues", 450 | "source": "https://github.com/pmmp/CallbackValidator/tree/1.0.3" 451 | }, 452 | "time": "2020-12-11T01:45:37+00:00" 453 | }, 454 | { 455 | "name": "pocketmine/color", 456 | "version": "0.3.1", 457 | "source": { 458 | "type": "git", 459 | "url": "https://github.com/pmmp/Color.git", 460 | "reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1" 461 | }, 462 | "dist": { 463 | "type": "zip", 464 | "url": "https://api.github.com/repos/pmmp/Color/zipball/a0421f1e9e0b0c619300fb92d593283378f6a5e1", 465 | "reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1", 466 | "shasum": "" 467 | }, 468 | "require": { 469 | "php": "^8.0" 470 | }, 471 | "require-dev": { 472 | "phpstan/phpstan": "1.10.3", 473 | "phpstan/phpstan-strict-rules": "^1.2.0" 474 | }, 475 | "type": "library", 476 | "autoload": { 477 | "psr-4": { 478 | "pocketmine\\color\\": "src/" 479 | } 480 | }, 481 | "notification-url": "https://packagist.org/downloads/", 482 | "license": [ 483 | "LGPL-3.0" 484 | ], 485 | "description": "Color handling library used by PocketMine-MP and related projects", 486 | "support": { 487 | "issues": "https://github.com/pmmp/Color/issues", 488 | "source": "https://github.com/pmmp/Color/tree/0.3.1" 489 | }, 490 | "time": "2023-04-10T11:38:05+00:00" 491 | }, 492 | { 493 | "name": "pocketmine/errorhandler", 494 | "version": "0.7.0", 495 | "source": { 496 | "type": "git", 497 | "url": "https://github.com/pmmp/ErrorHandler.git", 498 | "reference": "cae94884368a74ece5294b9ff7fef18732dcd921" 499 | }, 500 | "dist": { 501 | "type": "zip", 502 | "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/cae94884368a74ece5294b9ff7fef18732dcd921", 503 | "reference": "cae94884368a74ece5294b9ff7fef18732dcd921", 504 | "shasum": "" 505 | }, 506 | "require": { 507 | "php": "^8.0" 508 | }, 509 | "require-dev": { 510 | "phpstan/phpstan": "~1.10.3", 511 | "phpstan/phpstan-strict-rules": "^1.0", 512 | "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0" 513 | }, 514 | "type": "library", 515 | "autoload": { 516 | "psr-4": { 517 | "pocketmine\\errorhandler\\": "src/" 518 | } 519 | }, 520 | "notification-url": "https://packagist.org/downloads/", 521 | "license": [ 522 | "LGPL-3.0" 523 | ], 524 | "description": "Utilities to handle nasty PHP E_* errors in a usable way", 525 | "support": { 526 | "issues": "https://github.com/pmmp/ErrorHandler/issues", 527 | "source": "https://github.com/pmmp/ErrorHandler/tree/0.7.0" 528 | }, 529 | "time": "2024-04-02T18:29:54+00:00" 530 | }, 531 | { 532 | "name": "pocketmine/locale-data", 533 | "version": "2.24.2", 534 | "source": { 535 | "type": "git", 536 | "url": "https://github.com/pmmp/Language.git", 537 | "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b" 538 | }, 539 | "dist": { 540 | "type": "zip", 541 | "url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b", 542 | "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b", 543 | "shasum": "" 544 | }, 545 | "type": "library", 546 | "notification-url": "https://packagist.org/downloads/", 547 | "description": "Language resources used by PocketMine-MP", 548 | "support": { 549 | "issues": "https://github.com/pmmp/Language/issues", 550 | "source": "https://github.com/pmmp/Language/tree/2.24.2" 551 | }, 552 | "time": "2025-04-03T01:23:27+00:00" 553 | }, 554 | { 555 | "name": "pocketmine/log", 556 | "version": "0.4.0", 557 | "source": { 558 | "type": "git", 559 | "url": "https://github.com/pmmp/Log.git", 560 | "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043" 561 | }, 562 | "dist": { 563 | "type": "zip", 564 | "url": "https://api.github.com/repos/pmmp/Log/zipball/e6c912c0f9055c81d23108ec2d179b96f404c043", 565 | "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043", 566 | "shasum": "" 567 | }, 568 | "require": { 569 | "php": "^7.4 || ^8.0" 570 | }, 571 | "conflict": { 572 | "pocketmine/spl": "<0.4" 573 | }, 574 | "require-dev": { 575 | "phpstan/phpstan": "0.12.88", 576 | "phpstan/phpstan-strict-rules": "^0.12.2" 577 | }, 578 | "type": "library", 579 | "autoload": { 580 | "classmap": [ 581 | "./src" 582 | ] 583 | }, 584 | "notification-url": "https://packagist.org/downloads/", 585 | "license": [ 586 | "LGPL-3.0" 587 | ], 588 | "description": "Logging components used by PocketMine-MP and related projects", 589 | "support": { 590 | "issues": "https://github.com/pmmp/Log/issues", 591 | "source": "https://github.com/pmmp/Log/tree/0.4.0" 592 | }, 593 | "time": "2021-06-18T19:08:09+00:00" 594 | }, 595 | { 596 | "name": "pocketmine/math", 597 | "version": "1.0.0", 598 | "source": { 599 | "type": "git", 600 | "url": "https://github.com/pmmp/Math.git", 601 | "reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf" 602 | }, 603 | "dist": { 604 | "type": "zip", 605 | "url": "https://api.github.com/repos/pmmp/Math/zipball/dc132d93595b32e9f210d78b3c8d43c662a5edbf", 606 | "reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf", 607 | "shasum": "" 608 | }, 609 | "require": { 610 | "php": "^8.0", 611 | "php-64bit": "*" 612 | }, 613 | "require-dev": { 614 | "phpstan/extension-installer": "^1.0", 615 | "phpstan/phpstan": "~1.10.3", 616 | "phpstan/phpstan-strict-rules": "^1.0", 617 | "phpunit/phpunit": "^8.5 || ^9.5" 618 | }, 619 | "type": "library", 620 | "autoload": { 621 | "psr-4": { 622 | "pocketmine\\math\\": "src/" 623 | } 624 | }, 625 | "notification-url": "https://packagist.org/downloads/", 626 | "license": [ 627 | "LGPL-3.0" 628 | ], 629 | "description": "PHP library containing math related code used in PocketMine-MP", 630 | "support": { 631 | "issues": "https://github.com/pmmp/Math/issues", 632 | "source": "https://github.com/pmmp/Math/tree/1.0.0" 633 | }, 634 | "time": "2023-08-03T12:56:33+00:00" 635 | }, 636 | { 637 | "name": "pocketmine/nbt", 638 | "version": "1.1.1", 639 | "source": { 640 | "type": "git", 641 | "url": "https://github.com/pmmp/NBT.git", 642 | "reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1" 643 | }, 644 | "dist": { 645 | "type": "zip", 646 | "url": "https://api.github.com/repos/pmmp/NBT/zipball/c3c7b0a7295daeaf7873d90fed5c5d10381d12e1", 647 | "reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1", 648 | "shasum": "" 649 | }, 650 | "require": { 651 | "php": "^7.4 || ^8.0", 652 | "php-64bit": "*", 653 | "pocketmine/binaryutils": "^0.2.0" 654 | }, 655 | "require-dev": { 656 | "phpstan/extension-installer": "^1.0", 657 | "phpstan/phpstan": "2.1.0", 658 | "phpstan/phpstan-strict-rules": "^2.0", 659 | "phpunit/phpunit": "^9.5" 660 | }, 661 | "type": "library", 662 | "autoload": { 663 | "psr-4": { 664 | "pocketmine\\nbt\\": "src/" 665 | } 666 | }, 667 | "notification-url": "https://packagist.org/downloads/", 668 | "license": [ 669 | "LGPL-3.0" 670 | ], 671 | "description": "PHP library for working with Named Binary Tags", 672 | "support": { 673 | "issues": "https://github.com/pmmp/NBT/issues", 674 | "source": "https://github.com/pmmp/NBT/tree/1.1.1" 675 | }, 676 | "time": "2025-03-09T01:46:03+00:00" 677 | }, 678 | { 679 | "name": "pocketmine/pocketmine-mp", 680 | "version": "5.28.2", 681 | "source": { 682 | "type": "git", 683 | "url": "https://github.com/pmmp/PocketMine-MP.git", 684 | "reference": "81d3017ad5e15e8f6ca846733826b47a5e90eba2" 685 | }, 686 | "dist": { 687 | "type": "zip", 688 | "url": "https://api.github.com/repos/pmmp/PocketMine-MP/zipball/81d3017ad5e15e8f6ca846733826b47a5e90eba2", 689 | "reference": "81d3017ad5e15e8f6ca846733826b47a5e90eba2", 690 | "shasum": "" 691 | }, 692 | "require": { 693 | "adhocore/json-comment": "~1.2.0", 694 | "composer-runtime-api": "^2.0", 695 | "ext-chunkutils2": "^0.3.1", 696 | "ext-crypto": "^0.3.1", 697 | "ext-ctype": "*", 698 | "ext-curl": "*", 699 | "ext-date": "*", 700 | "ext-gmp": "*", 701 | "ext-hash": "*", 702 | "ext-igbinary": "^3.0.1", 703 | "ext-json": "*", 704 | "ext-leveldb": "^0.2.1 || ^0.3.0", 705 | "ext-mbstring": "*", 706 | "ext-morton": "^0.1.0", 707 | "ext-openssl": "*", 708 | "ext-pcre": "*", 709 | "ext-phar": "*", 710 | "ext-pmmpthread": "^6.1.0", 711 | "ext-reflection": "*", 712 | "ext-simplexml": "*", 713 | "ext-sockets": "*", 714 | "ext-spl": "*", 715 | "ext-yaml": ">=2.0.0", 716 | "ext-zip": "*", 717 | "ext-zlib": ">=1.2.11", 718 | "netresearch/jsonmapper": "~v5.0.0", 719 | "php": "^8.1", 720 | "php-64bit": "*", 721 | "pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60", 722 | "pocketmine/bedrock-data": "~5.0.0+bedrock-1.21.80", 723 | "pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50", 724 | "pocketmine/bedrock-protocol": "~38.0.0+bedrock-1.21.80", 725 | "pocketmine/binaryutils": "^0.2.1", 726 | "pocketmine/callback-validator": "^1.0.2", 727 | "pocketmine/color": "^0.3.0", 728 | "pocketmine/errorhandler": "^0.7.0", 729 | "pocketmine/locale-data": "~2.24.0", 730 | "pocketmine/log": "^0.4.0", 731 | "pocketmine/math": "~1.0.0", 732 | "pocketmine/nbt": "~1.1.0", 733 | "pocketmine/raklib": "~1.1.2", 734 | "pocketmine/raklib-ipc": "~1.0.0", 735 | "pocketmine/snooze": "^0.5.0", 736 | "ramsey/uuid": "~4.7.0", 737 | "symfony/filesystem": "~6.4.0" 738 | }, 739 | "provide": { 740 | "symfony/polyfill-ctype": "*", 741 | "symfony/polyfill-mbstring": "*" 742 | }, 743 | "require-dev": { 744 | "phpstan/phpstan": "2.1.16", 745 | "phpstan/phpstan-phpunit": "^2.0.0", 746 | "phpstan/phpstan-strict-rules": "^2.0.0", 747 | "phpunit/phpunit": "^10.5.24" 748 | }, 749 | "type": "project", 750 | "autoload": { 751 | "files": [ 752 | "src/CoreConstants.php" 753 | ], 754 | "psr-4": { 755 | "pocketmine\\": "src/" 756 | } 757 | }, 758 | "notification-url": "https://packagist.org/downloads/", 759 | "license": [ 760 | "LGPL-3.0" 761 | ], 762 | "description": "A server software for Minecraft: Bedrock Edition written in PHP", 763 | "homepage": "https://pmmp.io", 764 | "support": { 765 | "issues": "https://github.com/pmmp/PocketMine-MP/issues", 766 | "source": "https://github.com/pmmp/PocketMine-MP/tree/5.28.2" 767 | }, 768 | "funding": [ 769 | { 770 | "url": "https://github.com/pmmp/PocketMine-MP#donate", 771 | "type": "custom" 772 | }, 773 | { 774 | "url": "https://www.patreon.com/pocketminemp", 775 | "type": "patreon" 776 | } 777 | ], 778 | "time": "2025-05-17T15:44:19+00:00" 779 | }, 780 | { 781 | "name": "pocketmine/raklib", 782 | "version": "1.1.2", 783 | "source": { 784 | "type": "git", 785 | "url": "https://github.com/pmmp/RakLib.git", 786 | "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f" 787 | }, 788 | "dist": { 789 | "type": "zip", 790 | "url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f", 791 | "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f", 792 | "shasum": "" 793 | }, 794 | "require": { 795 | "ext-sockets": "*", 796 | "php": "^8.1", 797 | "php-64bit": "*", 798 | "php-ipv6": "*", 799 | "pocketmine/binaryutils": "^0.2.0", 800 | "pocketmine/log": "^0.3.0 || ^0.4.0" 801 | }, 802 | "require-dev": { 803 | "phpstan/phpstan": "2.1.0", 804 | "phpstan/phpstan-strict-rules": "^2.0" 805 | }, 806 | "type": "library", 807 | "autoload": { 808 | "psr-4": { 809 | "raklib\\": "src/" 810 | } 811 | }, 812 | "notification-url": "https://packagist.org/downloads/", 813 | "license": [ 814 | "GPL-3.0" 815 | ], 816 | "description": "A RakNet server implementation written in PHP", 817 | "support": { 818 | "issues": "https://github.com/pmmp/RakLib/issues", 819 | "source": "https://github.com/pmmp/RakLib/tree/1.1.2" 820 | }, 821 | "time": "2025-04-06T03:38:21+00:00" 822 | }, 823 | { 824 | "name": "pocketmine/raklib-ipc", 825 | "version": "1.0.1", 826 | "source": { 827 | "type": "git", 828 | "url": "https://github.com/pmmp/RakLibIpc.git", 829 | "reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc" 830 | }, 831 | "dist": { 832 | "type": "zip", 833 | "url": "https://api.github.com/repos/pmmp/RakLibIpc/zipball/ce632ef2c6743e71eddb5dc329c49af6555f90bc", 834 | "reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc", 835 | "shasum": "" 836 | }, 837 | "require": { 838 | "php": "^8.0", 839 | "php-64bit": "*", 840 | "pocketmine/binaryutils": "^0.2.0", 841 | "pocketmine/raklib": "^0.15.0 || ^1.0.0" 842 | }, 843 | "require-dev": { 844 | "phpstan/phpstan": "1.10.1", 845 | "phpstan/phpstan-strict-rules": "^1.0.0" 846 | }, 847 | "type": "library", 848 | "autoload": { 849 | "psr-4": { 850 | "raklib\\server\\ipc\\": "src/" 851 | } 852 | }, 853 | "notification-url": "https://packagist.org/downloads/", 854 | "license": [ 855 | "GPL-3.0" 856 | ], 857 | "description": "Channel-based protocols for inter-thread/inter-process communication with RakLib", 858 | "support": { 859 | "issues": "https://github.com/pmmp/RakLibIpc/issues", 860 | "source": "https://github.com/pmmp/RakLibIpc/tree/1.0.1" 861 | }, 862 | "time": "2024-03-01T15:55:05+00:00" 863 | }, 864 | { 865 | "name": "pocketmine/snooze", 866 | "version": "0.5.0", 867 | "source": { 868 | "type": "git", 869 | "url": "https://github.com/pmmp/Snooze.git", 870 | "reference": "a86d9ee60ce44755d166d3c7ba4b8b8be8360915" 871 | }, 872 | "dist": { 873 | "type": "zip", 874 | "url": "https://api.github.com/repos/pmmp/Snooze/zipball/a86d9ee60ce44755d166d3c7ba4b8b8be8360915", 875 | "reference": "a86d9ee60ce44755d166d3c7ba4b8b8be8360915", 876 | "shasum": "" 877 | }, 878 | "require": { 879 | "ext-pmmpthread": "^6.0", 880 | "php-64bit": "^8.1" 881 | }, 882 | "require-dev": { 883 | "phpstan/extension-installer": "^1.0", 884 | "phpstan/phpstan": "1.10.3", 885 | "phpstan/phpstan-strict-rules": "^1.0" 886 | }, 887 | "type": "library", 888 | "autoload": { 889 | "psr-4": { 890 | "pocketmine\\snooze\\": "src/" 891 | } 892 | }, 893 | "notification-url": "https://packagist.org/downloads/", 894 | "license": [ 895 | "LGPL-3.0" 896 | ], 897 | "description": "Thread notification management library for code using the pthreads extension", 898 | "support": { 899 | "issues": "https://github.com/pmmp/Snooze/issues", 900 | "source": "https://github.com/pmmp/Snooze/tree/0.5.0" 901 | }, 902 | "time": "2023-05-22T23:43:01+00:00" 903 | }, 904 | { 905 | "name": "ramsey/collection", 906 | "version": "2.1.1", 907 | "source": { 908 | "type": "git", 909 | "url": "https://github.com/ramsey/collection.git", 910 | "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" 911 | }, 912 | "dist": { 913 | "type": "zip", 914 | "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", 915 | "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", 916 | "shasum": "" 917 | }, 918 | "require": { 919 | "php": "^8.1" 920 | }, 921 | "require-dev": { 922 | "captainhook/plugin-composer": "^5.3", 923 | "ergebnis/composer-normalize": "^2.45", 924 | "fakerphp/faker": "^1.24", 925 | "hamcrest/hamcrest-php": "^2.0", 926 | "jangregor/phpstan-prophecy": "^2.1", 927 | "mockery/mockery": "^1.6", 928 | "php-parallel-lint/php-console-highlighter": "^1.0", 929 | "php-parallel-lint/php-parallel-lint": "^1.4", 930 | "phpspec/prophecy-phpunit": "^2.3", 931 | "phpstan/extension-installer": "^1.4", 932 | "phpstan/phpstan": "^2.1", 933 | "phpstan/phpstan-mockery": "^2.0", 934 | "phpstan/phpstan-phpunit": "^2.0", 935 | "phpunit/phpunit": "^10.5", 936 | "ramsey/coding-standard": "^2.3", 937 | "ramsey/conventional-commits": "^1.6", 938 | "roave/security-advisories": "dev-latest" 939 | }, 940 | "type": "library", 941 | "extra": { 942 | "captainhook": { 943 | "force-install": true 944 | }, 945 | "ramsey/conventional-commits": { 946 | "configFile": "conventional-commits.json" 947 | } 948 | }, 949 | "autoload": { 950 | "psr-4": { 951 | "Ramsey\\Collection\\": "src/" 952 | } 953 | }, 954 | "notification-url": "https://packagist.org/downloads/", 955 | "license": [ 956 | "MIT" 957 | ], 958 | "authors": [ 959 | { 960 | "name": "Ben Ramsey", 961 | "email": "ben@benramsey.com", 962 | "homepage": "https://benramsey.com" 963 | } 964 | ], 965 | "description": "A PHP library for representing and manipulating collections.", 966 | "keywords": [ 967 | "array", 968 | "collection", 969 | "hash", 970 | "map", 971 | "queue", 972 | "set" 973 | ], 974 | "support": { 975 | "issues": "https://github.com/ramsey/collection/issues", 976 | "source": "https://github.com/ramsey/collection/tree/2.1.1" 977 | }, 978 | "time": "2025-03-22T05:38:12+00:00" 979 | }, 980 | { 981 | "name": "ramsey/uuid", 982 | "version": "4.7.6", 983 | "source": { 984 | "type": "git", 985 | "url": "https://github.com/ramsey/uuid.git", 986 | "reference": "91039bc1faa45ba123c4328958e620d382ec7088" 987 | }, 988 | "dist": { 989 | "type": "zip", 990 | "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", 991 | "reference": "91039bc1faa45ba123c4328958e620d382ec7088", 992 | "shasum": "" 993 | }, 994 | "require": { 995 | "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", 996 | "ext-json": "*", 997 | "php": "^8.0", 998 | "ramsey/collection": "^1.2 || ^2.0" 999 | }, 1000 | "replace": { 1001 | "rhumsaa/uuid": "self.version" 1002 | }, 1003 | "require-dev": { 1004 | "captainhook/captainhook": "^5.10", 1005 | "captainhook/plugin-composer": "^5.3", 1006 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", 1007 | "doctrine/annotations": "^1.8", 1008 | "ergebnis/composer-normalize": "^2.15", 1009 | "mockery/mockery": "^1.3", 1010 | "paragonie/random-lib": "^2", 1011 | "php-mock/php-mock": "^2.2", 1012 | "php-mock/php-mock-mockery": "^1.3", 1013 | "php-parallel-lint/php-parallel-lint": "^1.1", 1014 | "phpbench/phpbench": "^1.0", 1015 | "phpstan/extension-installer": "^1.1", 1016 | "phpstan/phpstan": "^1.8", 1017 | "phpstan/phpstan-mockery": "^1.1", 1018 | "phpstan/phpstan-phpunit": "^1.1", 1019 | "phpunit/phpunit": "^8.5 || ^9", 1020 | "ramsey/composer-repl": "^1.4", 1021 | "slevomat/coding-standard": "^8.4", 1022 | "squizlabs/php_codesniffer": "^3.5", 1023 | "vimeo/psalm": "^4.9" 1024 | }, 1025 | "suggest": { 1026 | "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", 1027 | "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", 1028 | "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", 1029 | "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", 1030 | "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." 1031 | }, 1032 | "type": "library", 1033 | "extra": { 1034 | "captainhook": { 1035 | "force-install": true 1036 | } 1037 | }, 1038 | "autoload": { 1039 | "files": [ 1040 | "src/functions.php" 1041 | ], 1042 | "psr-4": { 1043 | "Ramsey\\Uuid\\": "src/" 1044 | } 1045 | }, 1046 | "notification-url": "https://packagist.org/downloads/", 1047 | "license": [ 1048 | "MIT" 1049 | ], 1050 | "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", 1051 | "keywords": [ 1052 | "guid", 1053 | "identifier", 1054 | "uuid" 1055 | ], 1056 | "support": { 1057 | "issues": "https://github.com/ramsey/uuid/issues", 1058 | "source": "https://github.com/ramsey/uuid/tree/4.7.6" 1059 | }, 1060 | "funding": [ 1061 | { 1062 | "url": "https://github.com/ramsey", 1063 | "type": "github" 1064 | }, 1065 | { 1066 | "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", 1067 | "type": "tidelift" 1068 | } 1069 | ], 1070 | "time": "2024-04-27T21:32:50+00:00" 1071 | }, 1072 | { 1073 | "name": "squizlabs/php_codesniffer", 1074 | "version": "3.13.0", 1075 | "source": { 1076 | "type": "git", 1077 | "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", 1078 | "reference": "65ff2489553b83b4597e89c3b8b721487011d186" 1079 | }, 1080 | "dist": { 1081 | "type": "zip", 1082 | "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/65ff2489553b83b4597e89c3b8b721487011d186", 1083 | "reference": "65ff2489553b83b4597e89c3b8b721487011d186", 1084 | "shasum": "" 1085 | }, 1086 | "require": { 1087 | "ext-simplexml": "*", 1088 | "ext-tokenizer": "*", 1089 | "ext-xmlwriter": "*", 1090 | "php": ">=5.4.0" 1091 | }, 1092 | "require-dev": { 1093 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" 1094 | }, 1095 | "bin": [ 1096 | "bin/phpcbf", 1097 | "bin/phpcs" 1098 | ], 1099 | "type": "library", 1100 | "extra": { 1101 | "branch-alias": { 1102 | "dev-master": "3.x-dev" 1103 | } 1104 | }, 1105 | "notification-url": "https://packagist.org/downloads/", 1106 | "license": [ 1107 | "BSD-3-Clause" 1108 | ], 1109 | "authors": [ 1110 | { 1111 | "name": "Greg Sherwood", 1112 | "role": "Former lead" 1113 | }, 1114 | { 1115 | "name": "Juliette Reinders Folmer", 1116 | "role": "Current lead" 1117 | }, 1118 | { 1119 | "name": "Contributors", 1120 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" 1121 | } 1122 | ], 1123 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1124 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 1125 | "keywords": [ 1126 | "phpcs", 1127 | "standards", 1128 | "static analysis" 1129 | ], 1130 | "support": { 1131 | "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", 1132 | "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", 1133 | "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 1134 | "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" 1135 | }, 1136 | "funding": [ 1137 | { 1138 | "url": "https://github.com/PHPCSStandards", 1139 | "type": "github" 1140 | }, 1141 | { 1142 | "url": "https://github.com/jrfnl", 1143 | "type": "github" 1144 | }, 1145 | { 1146 | "url": "https://opencollective.com/php_codesniffer", 1147 | "type": "open_collective" 1148 | }, 1149 | { 1150 | "url": "https://thanks.dev/u/gh/phpcsstandards", 1151 | "type": "thanks_dev" 1152 | } 1153 | ], 1154 | "time": "2025-05-11T03:36:00+00:00" 1155 | }, 1156 | { 1157 | "name": "symfony/filesystem", 1158 | "version": "v6.4.13", 1159 | "source": { 1160 | "type": "git", 1161 | "url": "https://github.com/symfony/filesystem.git", 1162 | "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" 1163 | }, 1164 | "dist": { 1165 | "type": "zip", 1166 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", 1167 | "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", 1168 | "shasum": "" 1169 | }, 1170 | "require": { 1171 | "php": ">=8.1", 1172 | "symfony/polyfill-ctype": "~1.8", 1173 | "symfony/polyfill-mbstring": "~1.8" 1174 | }, 1175 | "require-dev": { 1176 | "symfony/process": "^5.4|^6.4|^7.0" 1177 | }, 1178 | "type": "library", 1179 | "autoload": { 1180 | "psr-4": { 1181 | "Symfony\\Component\\Filesystem\\": "" 1182 | }, 1183 | "exclude-from-classmap": [ 1184 | "/Tests/" 1185 | ] 1186 | }, 1187 | "notification-url": "https://packagist.org/downloads/", 1188 | "license": [ 1189 | "MIT" 1190 | ], 1191 | "authors": [ 1192 | { 1193 | "name": "Fabien Potencier", 1194 | "email": "fabien@symfony.com" 1195 | }, 1196 | { 1197 | "name": "Symfony Community", 1198 | "homepage": "https://symfony.com/contributors" 1199 | } 1200 | ], 1201 | "description": "Provides basic utilities for the filesystem", 1202 | "homepage": "https://symfony.com", 1203 | "support": { 1204 | "source": "https://github.com/symfony/filesystem/tree/v6.4.13" 1205 | }, 1206 | "funding": [ 1207 | { 1208 | "url": "https://symfony.com/sponsor", 1209 | "type": "custom" 1210 | }, 1211 | { 1212 | "url": "https://github.com/fabpot", 1213 | "type": "github" 1214 | }, 1215 | { 1216 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1217 | "type": "tidelift" 1218 | } 1219 | ], 1220 | "time": "2024-10-25T15:07:50+00:00" 1221 | } 1222 | ], 1223 | "aliases": [], 1224 | "minimum-stability": "stable", 1225 | "stability-flags": {}, 1226 | "prefer-stable": false, 1227 | "prefer-lowest": false, 1228 | "platform": {}, 1229 | "platform-dev": {}, 1230 | "plugin-api-version": "2.6.0" 1231 | } 1232 | --------------------------------------------------------------------------------