PocketMine-MP 5.23.3 git-f7687af337d001ddbcc47b8e773f014a33faa662
Loading...
Searching...
No Matches
PopulationTask.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
25
32use function array_map;
33use function igbinary_serialize;
34use function igbinary_unserialize;
35
40 private const TLS_KEY_ON_COMPLETION = "onCompletion";
41
42 private ?string $chunk;
43
44 private string $adjacentChunks;
45
51 public function __construct(
52 private int $worldId,
53 private int $chunkX,
54 private int $chunkZ,
55 ?Chunk $chunk,
56 array $adjacentChunks,
57 \Closure $onCompletion
58 ){
59 $this->chunk = $chunk !== null ? FastChunkSerializer::serializeTerrain($chunk) : null;
60
61 $this->adjacentChunks = igbinary_serialize(array_map(
62 fn(?Chunk $c) => $c !== null ? FastChunkSerializer::serializeTerrain($c) : null,
63 $adjacentChunks
64 )) ?? throw new AssumptionFailedError("igbinary_serialize() returned null");
65
66 $this->storeLocal(self::TLS_KEY_ON_COMPLETION, $onCompletion);
67 }
68
69 public function onRun() : void{
70 $context = ThreadLocalGeneratorContext::fetch($this->worldId);
71 if($context === null){
72 throw new AssumptionFailedError("Generator context should have been initialized before any PopulationTask execution");
73 }
74 $generator = $context->getGenerator();
75 $manager = new SimpleChunkManager($context->getWorldMinY(), $context->getWorldMaxY());
76
77 $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null;
78
83 $serialChunks = igbinary_unserialize($this->adjacentChunks);
84 $chunks = array_map(
85 function(?string $serialized) : ?Chunk{
86 if($serialized === null){
87 return null;
88 }
89 $chunk = FastChunkSerializer::deserializeTerrain($serialized);
90 $chunk->clearTerrainDirtyFlags(); //this allows us to avoid sending existing chunks back to the main thread if they haven't changed during generation
91 return $chunk;
92 },
93 $serialChunks
94 );
95
96 self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk);
97
98 $resultChunks = []; //this is just to keep phpstan's type inference happy
99 foreach($chunks as $relativeChunkHash => $c){
100 World::getXZ($relativeChunkHash, $relativeX, $relativeZ);
101 $resultChunks[$relativeChunkHash] = self::setOrGenerateChunk($manager, $generator, $this->chunkX + $relativeX, $this->chunkZ + $relativeZ, $c);
102 }
103 $chunks = $resultChunks;
104
105 $generator->populateChunk($manager, $this->chunkX, $this->chunkZ);
106 $chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
107 if($chunk === null){
108 throw new AssumptionFailedError("We just generated this chunk, so it must exist");
109 }
110 $chunk->setPopulated();
111
112 $this->chunk = FastChunkSerializer::serializeTerrain($chunk);
113
114 $serialChunks = [];
115 foreach($chunks as $relativeChunkHash => $c){
116 $serialChunks[$relativeChunkHash] = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null;
117 }
118 $this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null");
119 }
120
121 private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{
122 $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk([], false));
123 if($chunk === null){
124 $generator->generateChunk($manager, $chunkX, $chunkZ);
125 $chunk = $manager->getChunk($chunkX, $chunkZ);
126 if($chunk === null){
127 throw new AssumptionFailedError("We just set this chunk, so it must exist");
128 }
129 }
130 return $chunk;
131 }
132
133 public function onCompletion() : void{
138 $onCompletion = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
139
140 $chunk = $this->chunk !== null ?
141 FastChunkSerializer::deserializeTerrain($this->chunk) :
142 throw new AssumptionFailedError("Center chunk should never be null");
143
148 $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks);
149 $adjacentChunks = [];
150 foreach($serialAdjacentChunks as $relativeChunkHash => $c){
151 if($c !== null){
152 $adjacentChunks[$relativeChunkHash] = FastChunkSerializer::deserializeTerrain($c);
153 }
154 }
155
156 $onCompletion($chunk, $adjacentChunks);
157 }
158}
storeLocal(string $key, mixed $complexData)
static getXZ(int $hash, ?int &$x, ?int &$z)
Definition World.php:441
__construct(private int $worldId, private int $chunkX, private int $chunkZ, ?Chunk $chunk, array $adjacentChunks, \Closure $onCompletion)