├── 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 |
3 |
4 |
5 | FancyGenerators
6 | A collection of new level Generators
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------