├── .gitignore ├── phpstan.neon.dist ├── src └── ColinHDev │ └── CPlot │ ├── utils │ ├── ParseException.php │ ├── promise │ │ ├── PromiseSharedData.php │ │ ├── PromiseResolver.php │ │ └── Promise.php │ └── APIHolder.php │ ├── worlds │ └── schematic │ │ └── SchematicTypes.php │ ├── event │ ├── PlotEvent.php │ ├── PlayerLeavePlotEvent.php │ ├── PlayerEnterPlotEvent.php │ ├── PlayerLeftPlotEvent.php │ ├── PlotAsyncEvent.php │ ├── PlayerEnteredPlotEvent.php │ ├── PlotClearedAsyncEvent.php │ ├── PlotMergedAsyncEvent.php │ ├── PlotClearAsyncEvent.php │ ├── PlotResetAsyncEvent.php │ ├── PlayerKickFromPlotEvent.php │ ├── PlotMergeAsyncEvent.php │ ├── PlotClaimAsyncEvent.php │ ├── PlotWallChangeAsyncEvent.php │ ├── PlotBorderChangeAsyncEvent.php │ ├── PlotBiomeChangeAsyncEvent.php │ ├── PlotPlayerAddAsyncEvent.php │ ├── PlotPlayerRemoveAsyncEvent.php │ └── PlotWorldGenerateAsyncEvent.php │ ├── plots │ ├── flags │ │ ├── InternalFlag.php │ │ ├── implementation │ │ │ ├── UseFlag.php │ │ │ ├── BreakFlag.php │ │ │ ├── PlaceFlag.php │ │ │ ├── FarewellFlag.php │ │ │ ├── GreetingFlag.php │ │ │ ├── PveFlag.php │ │ │ ├── BurningFlag.php │ │ │ ├── FlowingFlag.php │ │ │ ├── GrowingFlag.php │ │ │ ├── ItemDropFlag.php │ │ │ ├── ExplosionFlag.php │ │ │ ├── ItemPickupFlag.php │ │ │ ├── SpawnFlag.php │ │ │ ├── PlayerInteractFlag.php │ │ │ └── PvpFlag.php │ │ ├── FlagIDs.php │ │ ├── Flag.php │ │ └── Flags.php │ ├── lock │ │ ├── MergeLockID.php │ │ ├── ResetLockID.php │ │ ├── ClearLockID.php │ │ ├── BiomeChangeLockID.php │ │ ├── WallChangeLockID.php │ │ ├── BorderChangeLockID.php │ │ ├── AddPlotPlayerLockID.php │ │ ├── RemovePlotPlayerLockID.php │ │ └── PlotLockID.php │ ├── TeleportDestination.php │ ├── PlotRate.php │ ├── MergePlot.php │ └── PlotPlayer.php │ ├── player │ └── settings │ │ ├── InternalSetting.php │ │ ├── SettingIDs.php │ │ ├── implementation │ │ ├── WarnFlagSetting.php │ │ ├── WarnFlagChangeSetting.php │ │ ├── TeleportFlagChangeSetting.php │ │ ├── InformUndeniedSetting.php │ │ ├── InformAddedSetting.php │ │ ├── InformDeniedSetting.php │ │ ├── InformRateAddSetting.php │ │ ├── InformRemovedSetting.php │ │ ├── InformTrustedSetting.php │ │ └── InformUntrustedSetting.php │ │ ├── Setting.php │ │ └── Settings.php │ ├── provider │ ├── cache │ │ ├── CacheIDs.php │ │ └── Cache.php │ ├── LanguageManager.php │ ├── BedrockEconomyProvider.php │ ├── LanguageProvider.php │ ├── utils │ │ └── EconomyException.php │ ├── EconomyProvider.php │ └── CapitalEconomyProvider.php │ ├── attributes │ ├── ListAttribute.php │ ├── StringAttribute.php │ ├── utils │ │ └── AttributeParseException.php │ ├── BooleanAttribute.php │ └── LocationAttribute.php │ ├── commands │ ├── AsyncSubcommand.php │ ├── subcommands │ │ ├── MiddleSubcommand.php │ │ ├── SpawnSubcommand.php │ │ ├── HelpersSubcommand.php │ │ ├── DeniedSubcommand.php │ │ ├── TrustedSubcommand.php │ │ ├── GenerateSubcommand.php │ │ ├── HelpSubcommand.php │ │ ├── WarpSubcommand.php │ │ ├── InfoSubcommand.php │ │ └── WallSubcommand.php │ └── Subcommand.php │ ├── listener │ ├── MyPlotConversionListener.php │ ├── BlockGrowListener.php │ ├── PlayerLoginListener.php │ ├── BlockFormListener.php │ ├── BlockBurnListener.php │ ├── BlockUpdateListener.php │ ├── StructureGrowListener.php │ ├── EntityExplodeListener.php │ ├── BlockTeleportListener.php │ ├── BlockSpreadListener.php │ ├── PlayerBucketEmptyListener.php │ ├── PlayerDropItemListener.php │ ├── BlockBreakListener.php │ ├── EntityDamageByEntityListener.php │ ├── EntityShootBowListener.php │ ├── EntityItemPickupListener.php │ ├── EntityTrampleFarmlandListener.php │ ├── BlockPlaceListener.php │ ├── PlayerInteractListener.php │ ├── ProjectileLaunchListener.php │ └── ChunkPopulateListener.php │ ├── math │ ├── Area.php │ └── CoordinateUtils.php │ ├── ResourceManager.php │ └── tasks │ ├── utils │ ├── PlotAreaCalculationTrait.php │ ├── DummyTile.php │ └── AreaCalculationTrait.php │ └── async │ ├── ChunkModifyingAsyncTask.php │ ├── ChunkFetchingAsyncTask.php │ ├── CPlotAsyncTask.php │ ├── PlotBiomeChangeAsyncTask.php │ ├── PlotBorderChangeAsyncTask.php │ └── PlotWallChangeAsyncTask.php ├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── .poggit.yml ├── resources └── sql │ ├── myplot_mysql.sql │ └── myplot_sqlite.sql └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | virions 4 | build-plugin.php 5 | CPlot.phar -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 9 3 | paths: 4 | - src 5 | scanDirectories: 6 | - vendor 7 | 8 | includes: 9 | - phpstan-baseline.neon -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/utils/ParseException.php: -------------------------------------------------------------------------------- 1 | plot = $plot; 16 | } 17 | 18 | public function getPlot() : Plot { 19 | return $this->plot; 20 | } 21 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/InternalFlag.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlayerEnterPlotEvent.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/attributes/ListAttribute.php: -------------------------------------------------------------------------------- 1 | 9 | * @extends BaseAttribute 10 | */ 11 | abstract class ListAttribute extends BaseAttribute { 12 | 13 | /** 14 | * @param TValue $value 15 | * @return self 16 | */ 17 | public function merge(mixed $value) : self { 18 | /** @var TValue $values */ 19 | $values = $this->value; 20 | foreach ($value as $newValue) { 21 | if ($this->contains($newValue)) { 22 | continue; 23 | } 24 | $values[] = $newValue; 25 | } 26 | return $this->createInstance($values); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlayerLeftPlotEvent.php: -------------------------------------------------------------------------------- 1 | player = $player; 21 | } 22 | 23 | public function getPlayer() : Player { 24 | return $this->player; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/ClearLockID.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotAsyncEvent.php: -------------------------------------------------------------------------------- 1 | plot = $plot; 24 | } 25 | 26 | public function getPlot() : Plot { 27 | return $this->plot; 28 | } 29 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/BiomeChangeLockID.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/WallChangeLockID.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlayerEnteredPlotEvent.php: -------------------------------------------------------------------------------- 1 | player = $player; 21 | } 22 | 23 | public function getPlayer() : Player { 24 | return $this->player; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/BorderChangeLockID.php: -------------------------------------------------------------------------------- 1 | chunkLockId)) { 22 | $this->chunkLockId = new ChunkLockId(); 23 | } 24 | return $this->chunkLockId; 25 | } 26 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/UseFlag.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class UseFlag extends BlockListAttribute implements Flag { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(FlagIDs::FLAG_USE, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/BreakFlag.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class BreakFlag extends BlockListAttribute implements Flag { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(FlagIDs::FLAG_BREAK, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/PlaceFlag.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class PlaceFlag extends BlockListAttribute implements Flag { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(FlagIDs::FLAG_PLACE, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/SettingIDs.php: -------------------------------------------------------------------------------- 1 | playerID = $playerID; 16 | } 17 | 18 | public function isCompatible(PlotLockID $other) : bool { 19 | if ($other instanceof ClearLockID) { 20 | return true; 21 | } 22 | if ($other instanceof self || $other instanceof RemovePlotPlayerLockID) { 23 | return $this->playerID !== $other->playerID; 24 | } 25 | return false; 26 | } 27 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/RemovePlotPlayerLockID.php: -------------------------------------------------------------------------------- 1 | playerID = $playerID; 16 | } 17 | 18 | public function isCompatible(PlotLockID $other) : bool { 19 | if ($other instanceof ClearLockID) { 20 | return true; 21 | } 22 | if ($other instanceof self || $other instanceof AddPlotPlayerLockID) { 23 | return $this->playerID !== $other->playerID; 24 | } 25 | return false; 26 | } 27 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/FlagIDs.php: -------------------------------------------------------------------------------- 1 | executeAsync($sender, $args) 15 | ); 16 | } 17 | 18 | /** 19 | * This generator function contains the code you want to be executed when the command is run. 20 | * Asynchronous code can be used in this function with {@see Await::g2c()}. 21 | * @param string[] $args 22 | * @phpstan-return Generator 23 | */ 24 | abstract public function executeAsync(CommandSender $sender, array $args) : Generator; 25 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/WarnFlagSetting.php: -------------------------------------------------------------------------------- 1 | >> 14 | */ 15 | class WarnFlagSetting extends FlagListAttribute implements Setting { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(SettingIDs::SETTING_WARN_FLAG, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/FarewellFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class FarewellFlag extends StringAttribute implements Flag { 15 | 16 | final public function __construct(string $value) { 17 | parent::__construct(FlagIDs::FLAG_FAREWELL, $value); 18 | } 19 | 20 | public static function EMPTY() : static { 21 | return new static(""); 22 | } 23 | 24 | public function createInstance(mixed $value) : static { 25 | return new static($value); 26 | } 27 | 28 | public function getExample() : string { 29 | return "Bye.. D:"; 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/GreetingFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class GreetingFlag extends StringAttribute implements Flag { 15 | 16 | final public function __construct(string $value) { 17 | parent::__construct(FlagIDs::FLAG_GREETING, $value); 18 | } 19 | 20 | public static function EMPTY() : static { 21 | return new static(""); 22 | } 23 | 24 | public function createInstance(mixed $value) : static { 25 | return new static($value); 26 | } 27 | 28 | public function getExample() : string { 29 | return "Welcome! :D"; 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/WarnFlagChangeSetting.php: -------------------------------------------------------------------------------- 1 | >> 14 | */ 15 | class WarnFlagChangeSetting extends FlagListAttribute implements Setting { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(SettingIDs::SETTING_WARN_FLAG_CHANGE, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/PveFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class PveFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_PVE, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/TeleportFlagChangeSetting.php: -------------------------------------------------------------------------------- 1 | >> 14 | */ 15 | class TeleportFlagChangeSetting extends FlagListAttribute implements Setting { 16 | 17 | final public function __construct(array $value) { 18 | parent::__construct(SettingIDs::SETTING_TELEPORT_FLAG_CHANGE, $value); 19 | } 20 | 21 | public static function NONE() : static { 22 | return new static([]); 23 | } 24 | 25 | public function createInstance(mixed $value) : static { 26 | return new static($value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/BurningFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class BurningFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_BURNING, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/FlowingFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class FlowingFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_FLOWING, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/GrowingFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class GrowingFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_GROWING, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/ItemDropFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ItemDropFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_ITEM_DROP, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/ExplosionFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ExplosionFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_EXPLOSION, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/ItemPickupFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ItemPickupFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_ITEM_PICKUP, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/SpawnFlag.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class SpawnFlag extends LocationAttribute implements Flag, InternalFlag { 17 | 18 | final public function __construct(Location $value) { 19 | parent::__construct(FlagIDs::FLAG_SPAWN, $value); 20 | } 21 | 22 | public static function NONE() : static { 23 | return new static(new Location(0.0, 0.0, 0.0, null, 0.0, 0.0)); 24 | } 25 | 26 | public function createInstance(mixed $value) : static { 27 | return new static($value); 28 | } 29 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/PlayerInteractFlag.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class PlayerInteractFlag extends BooleanAttribute implements Flag { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(FlagIDs::FLAG_PLAYER_INTERACT, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformUndeniedSetting.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class InformUndeniedSetting extends BooleanAttribute implements Setting { 13 | 14 | final public function __construct(bool $value) { 15 | parent::__construct(SettingIDs::SETTING_INFORM_UNDENIED, $value); 16 | } 17 | 18 | public static function TRUE() : static { 19 | return new static(true); 20 | } 21 | 22 | public static function FALSE() : static { 23 | return new static(false); 24 | } 25 | 26 | public function createInstance(mixed $value) : static { 27 | return $value === true ? self::TRUE() : self::FALSE(); 28 | } 29 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/implementation/PvpFlag.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class PvpFlag extends BooleanAttribute implements Flag { 16 | 17 | final public function __construct(bool $value) { 18 | parent::__construct(FlagIDs::FLAG_PVP, $value); 19 | } 20 | 21 | public static function TRUE() : static { 22 | return new static(true); 23 | } 24 | 25 | public static function FALSE() : static { 26 | return new static(false); 27 | } 28 | 29 | public function createInstance(mixed $value) : static { 30 | return $value === true ? self::TRUE() : self::FALSE(); 31 | } 32 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformAddedSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformAddedSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_ADDED, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformDeniedSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformDeniedSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_DENIED, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformRateAddSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformRateAddSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_RATE_ADD, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformRemovedSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformRemovedSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_REMOVED, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformTrustedSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformTrustedSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_TRUSTED, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotClearedAsyncEvent.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | public static function create(Plot $plot) : \Generator { 19 | $event = yield from Await::promise( 20 | static function ($onSuccess) use ($plot) : void { 21 | $event = new self($plot); 22 | $event->setCallback($onSuccess); 23 | $event->call(); 24 | } 25 | ); 26 | assert($event instanceof self); 27 | return $event; 28 | } 29 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/implementation/InformUntrustedSetting.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class InformUntrustedSetting extends BooleanAttribute implements Setting { 15 | 16 | final public function __construct(bool $value) { 17 | parent::__construct(SettingIDs::SETTING_INFORM_UNTRUSTED, $value); 18 | } 19 | 20 | public static function TRUE() : static { 21 | return new static(true); 22 | } 23 | 24 | public static function FALSE() : static { 25 | return new static(false); 26 | } 27 | 28 | public function createInstance(mixed $value) : static { 29 | return $value === true ? self::TRUE() : self::FALSE(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotMergedAsyncEvent.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | public static function create(Plot $plot) : \Generator { 19 | $event = yield from Await::promise( 20 | static function ($onSuccess, $onError) use ($plot) : void { 21 | $event = new self($plot); 22 | $event->setCallback($onSuccess); 23 | $event->call(); 24 | } 25 | ); 26 | assert($event instanceof self); 27 | return $event; 28 | } 29 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/utils/promise/PromiseSharedData.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | public array $onSuccess = []; 22 | /** 23 | * An array of {@see Closure}s to call when the promise is rejected. 24 | * @phpstan-var array 25 | */ 26 | public array $onError = []; 27 | 28 | /** 29 | * The result of the promise. 30 | * @phpstan-var TValue|null 31 | */ 32 | public mixed $result = null; 33 | /** 34 | * The exception that was thrown when the promise was rejected. 35 | */ 36 | public ?Throwable $error = null; 37 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/LanguageManager.php: -------------------------------------------------------------------------------- 1 | provider = new CPlotLanguageProvider(); 16 | } 17 | 18 | /** 19 | * Returns the {@see LanguageProvider} instance that is currently used for CPlot's language integration and 20 | * can be used to interact with the specific language provider. 21 | */ 22 | public function getProvider() : LanguageProvider { 23 | return $this->provider; 24 | } 25 | 26 | /** 27 | * Change the current {@see LanguageProvider} instance. 28 | * This method can be used to make CPlot compatible with your own, (maybe closed-source) language manager. 29 | */ 30 | public function setProvider(LanguageProvider $provider) : void { 31 | $this->provider = $provider; 32 | } 33 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/lock/PlotLockID.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | public static function create(Plot $plot) : \Generator { 22 | $event = yield from Await::promise( 23 | static function ($onSuccess) use ($plot) : void { 24 | $event = new self($plot); 25 | $event->setCallback($onSuccess); 26 | $event->call(); 27 | } 28 | ); 29 | assert($event instanceof self); 30 | return $event; 31 | } 32 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/TeleportDestination.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public static function create(Plot $plot) : \Generator { 23 | $event = yield from Await::promise( 24 | static function ($onSuccess, $onError) use ($plot) : void { 25 | $event = new self($plot); 26 | $event->setCallback($onSuccess); 27 | $event->call(); 28 | } 29 | ); 30 | assert($event instanceof self); 31 | return $event; 32 | } 33 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/MyPlotConversionListener.php: -------------------------------------------------------------------------------- 1 | getWorld(); 18 | if ($world->getProvider()->getWorldData()->getGenerator() !== MyPlotGenerator::GENERATOR_NAME) { 19 | return; 20 | } 21 | Await::f2c( 22 | static function() use($world) : Generator { 23 | $worldSettings = yield from DataProvider::getInstance()->awaitWorld($world->getFolderName()); 24 | if ($worldSettings !== false) { 25 | return; 26 | } 27 | yield from DataProvider::getInstance()->importMyPlotData($world); 28 | } 29 | ); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/attributes/StringAttribute.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | abstract class StringAttribute extends BaseAttribute { 11 | 12 | public function equals(object $other) : bool { 13 | if (!($other instanceof static)) { 14 | return false; 15 | } 16 | return $this->value === $other->getValue(); 17 | } 18 | 19 | /** 20 | * @param string $value 21 | */ 22 | public function contains(mixed $value) : bool { 23 | return $this->equals($this->createInstance($value)); 24 | } 25 | 26 | /** 27 | * @param string $value 28 | */ 29 | public function merge(mixed $value) : self { 30 | return $this->createInstance($value); 31 | } 32 | 33 | public function toString() : string { 34 | return $this->value; 35 | } 36 | 37 | public function toReadableString() : string { 38 | return "\"" . $this->value . "\""; 39 | } 40 | 41 | public function parse(string $value) : string { 42 | return $value; 43 | } 44 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "colinhdev/cplot", 3 | "minimum-stability": "dev", 4 | "require": { 5 | "pocketmine/pocketmine-mp": "^5.5.0", 6 | "sof3/await-generator": "^3.4.3", 7 | "sof3/libasynql": "dev-pm5", 8 | "cooldogedev/bedrockeconomy": "^2.0.8", 9 | "colinhdev/libasyncevent": "^v3.0.0", 10 | "ext-zlib": "*", 11 | "ext-yaml": "*" 12 | }, 13 | "require-dev": { 14 | "phpstan/phpstan": "^1.10.3", 15 | "phpstan/phpstan-strict-rules": "^1.5.0", 16 | "phpstan/extension-installer": "^1.2.0" 17 | }, 18 | "repositories": { 19 | "capital": { 20 | "type": "vcs", 21 | "url": "https://github.com/SOF3/Capital" 22 | }, 23 | "bedrockeconomy": { 24 | "type": "package", 25 | "package": { 26 | "name": "cooldogedev/bedrockeconomy", 27 | "version": "2.0.8", 28 | "source": { 29 | "type": "git", 30 | "url": "https://github.com/cooldogedev/BedrockEconomy", 31 | "reference": "main" 32 | } 33 | } 34 | } 35 | }, 36 | "config": { 37 | "allow-plugins": { 38 | "phpstan/extension-installer": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/attributes/utils/AttributeParseException.php: -------------------------------------------------------------------------------- 1 | */ 17 | private BaseAttribute $attribute; 18 | private string $value; 19 | 20 | /** 21 | * @param BaseAttribute $attribute 22 | */ 23 | public function __construct(BaseAttribute $attribute, string $value) { 24 | // TODO: 25 | parent::__construct("Failed to parse attribute " . $attribute::class . ". Value " . $value . " was not accepted."); 26 | $this->attribute = $attribute; 27 | $this->value = $value; 28 | } 29 | 30 | /** 31 | * @return BaseAttribute 32 | */ 33 | public function getAttribute() : BaseAttribute { 34 | return $this->attribute; 35 | } 36 | 37 | public function getValue() : string { 38 | return $this->value; 39 | } 40 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/math/Area.php: -------------------------------------------------------------------------------- 1 | xMin = min($x1, $x2); 16 | $this->zMin = min($z1, $z2); 17 | $this->xMax = max($x1, $x2); 18 | $this->zMax = max($z1, $z2); 19 | } 20 | 21 | public function getXMin() : int { 22 | return $this->xMin; 23 | } 24 | 25 | public function getZMin() : int { 26 | return $this->zMin; 27 | } 28 | 29 | public function getXMax() : int { 30 | return $this->xMax; 31 | } 32 | 33 | public function getZMax() : int { 34 | return $this->zMax; 35 | } 36 | 37 | public function isInside(int $x, int $z) : bool { 38 | return 39 | $x >= $this->xMin && $x <= $this->xMax && 40 | $z >= $this->zMin && $z <= $this->zMax; 41 | } 42 | 43 | public function toString() : string { 44 | return $this->xMin . ";" . $this->zMin . ";" . $this->xMax . ";" . $this->zMax; 45 | } 46 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/ResourceManager.php: -------------------------------------------------------------------------------- 1 | getDataFolder() . "language")) { 17 | mkdir(CPlot::getInstance()->getDataFolder() . "language"); 18 | } 19 | if (!is_dir(CPlot::getInstance()->getDataFolder() . "schematics")) { 20 | mkdir(CPlot::getInstance()->getDataFolder() . "schematics"); 21 | } 22 | 23 | CPlot::getInstance()->saveResource("config.yml"); 24 | 25 | foreach (CPlot::getInstance()->getResources() as $path => $fileInfo) { 26 | if(str_contains($path, "language") and strtolower($fileInfo->getExtension()) === "ini") { 27 | CPlot::getInstance()->saveResource($path); 28 | } 29 | } 30 | 31 | $this->config = new Config(CPlot::getInstance()->getDataFolder() . "config.yml", Config::YAML); 32 | } 33 | 34 | public function getConfig() : Config { 35 | $this->config->reload(); 36 | return $this->config; 37 | } 38 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/math/CoordinateUtils.php: -------------------------------------------------------------------------------- 1 | = ($sizeRoad - 1)) return true; 21 | 22 | } else if ($x === ($sizeRoad - 1)) { 23 | if ($z === 0) return true; 24 | if ($z >= ($sizeRoad - 1)) return true; 25 | } 26 | 27 | if ($z === 0) { 28 | if ($x === 0) return true; 29 | if ($x >= ($sizeRoad - 1)) return true; 30 | 31 | } else if ($z === ($sizeRoad - 1)) { 32 | if ($x === 0) return true; 33 | if ($x >= ($sizeRoad - 1)) return true; 34 | } 35 | return false; 36 | } 37 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlayerKickFromPlotEvent.php: -------------------------------------------------------------------------------- 1 | player = $player; 27 | $this->target = $target; 28 | } 29 | 30 | /** 31 | * Returns the player who is kicking the @see getTarget(). 32 | */ 33 | public function getPlayer() : Player { 34 | return $this->player; 35 | } 36 | 37 | /** 38 | * Returns the player who gets kicked by the @see getPlayer(). 39 | */ 40 | public function getTarget() : Player { 41 | return $this->target; 42 | } 43 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockGrowListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 22 | /** @phpstan-var true|false|null $isPlotWorld */ 23 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 24 | if ($isPlotWorld !== true) { 25 | if ($isPlotWorld !== false) { 26 | $event->cancel(); 27 | } 28 | return; 29 | } 30 | 31 | /** @phpstan-var Plot|false|null $plot */ 32 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 33 | if ($plot instanceof Plot && $plot->getFlag(Flags::GROWING())->equals(GrowingFlag::TRUE())) { 34 | return; 35 | } 36 | 37 | $event->cancel(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/PlayerLoginListener.php: -------------------------------------------------------------------------------- 1 | getPlayer(); 20 | Await::g2c( 21 | DataProvider::getInstance()->updatePlayerData( 22 | $player->getUniqueId()->getBytes(), 23 | $player->getXuid(), 24 | $player->getName() 25 | ), 26 | null, 27 | static function() use ($player) : void { 28 | if (!$player->isConnected()) { 29 | return; 30 | } 31 | $player->kick( 32 | LanguageManager::getInstance()->getProvider()->translateForCommandSender( 33 | $player, 34 | ["prefix", "playerLogin.savePlayerDataError"] 35 | ) 36 | ); 37 | } 38 | ); 39 | } 40 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/utils/PlotAreaCalculationTrait.php: -------------------------------------------------------------------------------- 1 | getMergePlots()); 24 | /** @var BasePlot $plot */ 25 | foreach ($plots as $plot) { 26 | $plotPosition = $plot->getVector3(); 27 | $plotPositionX = $plotPosition->getFloorX(); 28 | $plotPositionZ = $plotPosition->getFloorZ(); 29 | $area = new Area( 30 | $plotPositionX, 31 | $plotPositionZ, 32 | ($plotPositionX + $worldSettings->getPlotSize() - 1), 33 | ($plotPositionZ + $worldSettings->getPlotSize() - 1), 34 | ); 35 | $areas[$area->toString()] = $area; 36 | } 37 | 38 | return $areas; 39 | } 40 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/utils/DummyTile.php: -------------------------------------------------------------------------------- 1 | nbt = $nbt; 26 | $this->position = new Position($nbt->getInt(self::TAG_X), $nbt->getInt(self::TAG_Y), $nbt->getInt(self::TAG_Z), null); 27 | } 28 | 29 | public function saveNBT() : CompoundTag { 30 | return $this->nbt; 31 | } 32 | 33 | public function readSaveData(CompoundTag $nbt) : void { 34 | } 35 | 36 | protected function writeSaveData(CompoundTag $nbt) : void { 37 | } 38 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotMergeAsyncEvent.php: -------------------------------------------------------------------------------- 1 | plotToMerge = $plotToMerge; 23 | } 24 | 25 | public function getPlotToMerge() : Plot { 26 | return $this->plotToMerge; 27 | } 28 | 29 | /** 30 | * @phpstan-return \Generator 31 | */ 32 | public static function create(Plot $plot, Plot $plotToMerge) : \Generator { 33 | $event = yield from Await::promise( 34 | static function ($onSuccess, $onError) use ($plot, $plotToMerge) : void { 35 | $event = new self($plot, $plotToMerge); 36 | $event->setCallback($onSuccess); 37 | $event->call(); 38 | } 39 | ); 40 | assert($event instanceof self); 41 | return $event; 42 | } 43 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockFormListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 22 | /** @phpstan-var true|false|null $isPlotWorld */ 23 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 24 | if ($isPlotWorld !== true) { 25 | if ($isPlotWorld !== false) { 26 | $event->cancel(); 27 | } 28 | return; 29 | } 30 | 31 | /** @phpstan-var Plot|false|null $plot */ 32 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 33 | if ( 34 | $plot instanceof Plot && 35 | $plot->getFlag(Flags::FLOWING())->equals(FlowingFlag::TRUE()) && 36 | $plot->isOnPlot($event->getCausingBlock()->getPosition()) 37 | ) { 38 | return; 39 | } 40 | 41 | $event->cancel(); 42 | } 43 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/utils/AreaCalculationTrait.php: -------------------------------------------------------------------------------- 1 | $areas 14 | * @phpstan-param array> $chunks 15 | */ 16 | private function getChunksFromAreas(string $identifier, array $areas, array &$chunks) : void { 17 | foreach ($areas as $area) { 18 | for ($x = $area->getXMin(); $x <= $area->getXMax(); $x++) { 19 | for ($z = $area->getZMin(); $z <= $area->getZMax(); $z++) { 20 | $chunkHash = World::chunkHash($x >> 4, $z >> 4); 21 | $blockHash = World::chunkHash($x & 0x0f, $z & 0x0f); 22 | if (!isset($chunks[$chunkHash])) { 23 | $chunks[$chunkHash] = []; 24 | $chunks[$chunkHash][$identifier] = []; 25 | } else if (!isset($chunks[$chunkHash][$identifier])) { 26 | $chunks[$chunkHash][$identifier] = []; 27 | } else if (in_array($blockHash, $chunks[$chunkHash][$identifier], true)) { 28 | continue; 29 | } 30 | $chunks[$chunkHash][$identifier][] = $blockHash; 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotClaimAsyncEvent.php: -------------------------------------------------------------------------------- 1 | player = $player; 24 | } 25 | 26 | public function getPlayer() : Player { 27 | return $this->player; 28 | } 29 | 30 | /** 31 | * @phpstan-return \Generator 32 | */ 33 | public static function create(Plot $plot, Player $player) : \Generator { 34 | $event = yield from Await::promise( 35 | static function ($onSuccess, $onError) use ($plot, $player) : void { 36 | $event = new self($plot, $player); 37 | $event->setCallback($onSuccess); 38 | $event->call(); 39 | } 40 | ); 41 | assert($event instanceof self); 42 | return $event; 43 | } 44 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/ChunkModifyingAsyncTask.php: -------------------------------------------------------------------------------- 1 | worldID = $world->getId(); 19 | $this->worldName = $world->getFolderName(); 20 | } 21 | 22 | public function onCompletion() : void { 23 | $worldManager = Server::getInstance()->getWorldManager(); 24 | $world = $worldManager->getWorld($this->worldID); 25 | if ($world === null) { 26 | $worldManager->loadWorld($this->worldName); 27 | $world = $worldManager->getWorldByName($this->worldName); 28 | } 29 | if ($world !== null) { 30 | /** @phpstan-var array $chunks */ 31 | $chunks = unserialize($this->chunks, ["allowed_classes" => false]); 32 | foreach ($chunks as $hash => $chunk) { 33 | World::getXZ($hash, $chunkX, $chunkZ); 34 | $world->setChunk($chunkX, $chunkZ, FastChunkSerializer::deserializeTerrain($chunk)); 35 | } 36 | } 37 | parent::onCompletion(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/MiddleSubcommand.php: -------------------------------------------------------------------------------- 1 | awaitWorld($sender->getWorld()->getFolderName())) instanceof WorldSettings)) { 25 | self::sendMessage($sender, ["prefix", "middle.noPlotWorld"]); 26 | return; 27 | } 28 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 29 | if (!($plot instanceof Plot)) { 30 | self::sendMessage($sender, ["prefix", "middle.noPlot"]); 31 | return; 32 | } 33 | 34 | if (!$plot->teleportTo($sender, TeleportDestination::PLOT_CENTER)) { 35 | self::sendMessage($sender, ["prefix", "middle.teleportError"]); 36 | return; 37 | } 38 | self::sendMessage($sender, ["prefix", "middle.success"]); 39 | } 40 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotWallChangeAsyncEvent.php: -------------------------------------------------------------------------------- 1 | block = $block; 24 | } 25 | 26 | public function getBlock() : Block { 27 | return $this->block; 28 | } 29 | 30 | public function setBlock(Block $block) : void { 31 | $this->block = $block; 32 | } 33 | 34 | /** 35 | * @phpstan-return \Generator 36 | */ 37 | public static function create(Plot $plot, Block $block) : \Generator { 38 | $event = yield from Await::promise( 39 | static function ($onSuccess, $onError) use ($plot, $block) : void { 40 | $event = new self($plot, $block); 41 | $event->setCallback($onSuccess); 42 | $event->call(); 43 | } 44 | ); 45 | assert($event instanceof self); 46 | return $event; 47 | } 48 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotBorderChangeAsyncEvent.php: -------------------------------------------------------------------------------- 1 | block = $block; 24 | } 25 | 26 | public function getBlock() : Block { 27 | return $this->block; 28 | } 29 | 30 | public function setBlock(Block $block) : void { 31 | $this->block = $block; 32 | } 33 | 34 | /** 35 | * @phpstan-return \Generator 36 | */ 37 | public static function create(Plot $plot, Block $block) : \Generator { 38 | $event = yield from Await::promise( 39 | static function ($onSuccess, $onError) use ($plot, $block) : void { 40 | $event = new self($plot, $block); 41 | $event->setCallback($onSuccess); 42 | $event->call(); 43 | } 44 | ); 45 | assert($event instanceof self); 46 | return $event; 47 | } 48 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockBurnListener.php: -------------------------------------------------------------------------------- 1 | getCausingBlock()->getPosition(); 22 | /** @phpstan-var true|false|null $isPlotWorld */ 23 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 24 | if ($isPlotWorld !== true) { 25 | if ($isPlotWorld !== false) { 26 | $event->cancel(); 27 | } 28 | return; 29 | } 30 | 31 | /** @phpstan-var Plot|false|null $plot */ 32 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 33 | // We not only need to check if the causing block is on the plot but also if that applies for the changed one. 34 | if ( 35 | $plot instanceof Plot && 36 | $plot->isOnPlot($event->getBlock()->getPosition()) && 37 | $plot->getFlag(Flags::BURNING())->equals(BurningFlag::TRUE()) 38 | ) { 39 | return; 40 | } 41 | 42 | $event->cancel(); 43 | } 44 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockUpdateListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 22 | $world = $position->getWorld(); 23 | /** @var WorldSettings|false|null $worldSettings */ 24 | $worldSettings = $this->getAPI()->getOrLoadWorldSettings($world)->getResult(); 25 | if (!($worldSettings instanceof WorldSettings)) { 26 | if ($worldSettings !== false) { 27 | $event->cancel(); 28 | } 29 | return; 30 | } 31 | 32 | /** @var BasePlot|false $basePlot */ 33 | $basePlot = $this->getAPI()->getBasePlotAtPoint($world->getFolderName(), $worldSettings, $position); 34 | if ($basePlot instanceof BasePlot) { 35 | return; 36 | } 37 | 38 | /** @var Plot|false|null $basePlot */ 39 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 40 | if ($plot instanceof Plot) { 41 | return; 42 | } 43 | 44 | $event->cancel(); 45 | } 46 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/BedrockEconomyProvider.php: -------------------------------------------------------------------------------- 1 | getPluginManager()->getPlugin("BedrockEconomy") === null) { 20 | throw new \RuntimeException("BedrockEconomyProvider requires the plugin \"BedrockEconomy\" to be installed."); 21 | } 22 | } 23 | 24 | public function getCurrency() : string { 25 | return BedrockEconomy::getInstance()->getCurrencyManager()->getSymbol(); 26 | } 27 | 28 | public function parseMoneyToString(float $money) : string { 29 | return (string) floor($money); 30 | } 31 | 32 | public function removeMoney(Player $player, float $money, string $reason, callable $onSuccess, callable $onError) : void { 33 | $intMoney = (int) floor($money); 34 | $promise = BedrockEconomyAPI::beta()->deduct( 35 | $player->getName(), 36 | $intMoney 37 | ); 38 | $promise->onCompletion( 39 | \Closure::fromCallable($onSuccess), 40 | static function() use ($onError) { 41 | $onError( 42 | new EconomyException() 43 | ); 44 | } 45 | ); 46 | } 47 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/LanguageProvider.php: -------------------------------------------------------------------------------- 1 | >|MessageKey $keys 21 | */ 22 | abstract public function translateString(array|string $keys) : string; 23 | 24 | /** 25 | * This method is used to translate a message for the given {@see CommandSender}. 26 | * @phpstan-param array>|MessageKey $keys 27 | */ 28 | abstract public function translateForCommandSender(CommandSender $sender, array|string $keys) : string; 29 | 30 | /** 31 | * This method is used to send a message to the given {@see CommandSender} (e.g. a player or the console). 32 | * @phpstan-param array>|MessageKey $keys 33 | */ 34 | abstract public function sendMessage(CommandSender $sender, array|string $keys) : void; 35 | 36 | /** 37 | * This method is used to send a tip to the given {@see Player}. 38 | * @phpstan-param array>|MessageKey $keys 39 | */ 40 | abstract public function sendTip(Player $player, array|string $keys) : void; 41 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/StructureGrowListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 23 | $world = $position->getWorld(); 24 | /** @phpstan-var true|false|null $isPlotWorld */ 25 | $isPlotWorld = $this->getAPI()->isPlotWorld($world)->getResult(); 26 | if ($isPlotWorld !== true) { 27 | if ($isPlotWorld !== false) { 28 | $event->cancel(); 29 | } 30 | return; 31 | } 32 | 33 | /** @phpstan-var Plot|false|null $plot */ 34 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 35 | if ($plot instanceof Plot && $plot->getFlag(Flags::GROWING())->equals(GrowingFlag::TRUE())) { 36 | $transaction = $event->getTransaction(); 37 | foreach ($transaction->getBlocks() as [$x, $y, $z, $block]) { 38 | if (!$plot->isOnPlot(new Position($x, $y, $z, $world))) { 39 | $transaction->addBlockAt($x, $y, $z, $world->getBlockAt($x, $y, $z)); 40 | } 41 | } 42 | return; 43 | } 44 | 45 | $event->cancel(); 46 | } 47 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/EntityExplodeListener.php: -------------------------------------------------------------------------------- 1 | getBlockList()) === 0) { 22 | return; 23 | } 24 | 25 | $position = $event->getPosition(); 26 | /** @phpstan-var true|false|null $isPlotWorld */ 27 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 28 | if ($isPlotWorld !== true) { 29 | if ($isPlotWorld !== false) { 30 | $event->cancel(); 31 | } 32 | return; 33 | } 34 | 35 | /** @phpstan-var Plot|false|null $plot */ 36 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 37 | if ($plot instanceof Plot && $plot->getFlag(Flags::EXPLOSION())->equals(ExplosionFlag::TRUE())) { 38 | $affectedBlocks = []; 39 | foreach ($event->getBlockList() as $hash => $block) { 40 | if ($plot->isOnPlot($block->getPosition())) { 41 | $affectedBlocks[$hash] = $block; 42 | } 43 | } 44 | $event->setBlockList($affectedBlocks); 45 | return; 46 | } 47 | 48 | $event->cancel(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/utils/EconomyException.php: -------------------------------------------------------------------------------- 1 | code) { 34 | self::UNKNOWN => "economy.error.unknown", 35 | self::EVENT_CANCELLED => "economy.error.eventCancelled", 36 | self::SOURCE_NON_EXISTENT => "economy.error.sourceNonExistent", 37 | self::SOURCE_UNDERFLOW => "economy.error.sourceUnderflow", 38 | default => $this->message 39 | }; 40 | } 41 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/EconomyProvider.php: -------------------------------------------------------------------------------- 1 | 12,345.09 22 | */ 23 | abstract public function parseMoneyToString(float $money) : string; 24 | 25 | /** 26 | * @internal method to remove money from a player through the economy plugin while also using a 27 | * {@see \Generator} function which we can handle with {@see Await}. 28 | * @phpstan-return \Generator 29 | */ 30 | final public function awaitMoneyRemoval(Player $player, float $money, string $reason) : \Generator { 31 | yield from Await::promise( 32 | fn($onSuccess, $onError) => $this->removeMoney($player, $money, $reason, $onSuccess, $onError) 33 | ); 34 | } 35 | 36 | /** 37 | * This method is used to remove money from a player through the economy plugin. 38 | * @phpstan-param callable(mixed=): void $onSuccess 39 | * @phpstan-param callable(\Throwable): void $onError 40 | */ 41 | abstract public function removeMoney(Player $player, float $money, string $reason, callable $onSuccess, callable $onError) : void; 42 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/utils/APIHolder.php: -------------------------------------------------------------------------------- 1 | api === null || $this->version !== $version) { 34 | $this->api = CPlotAPI::getInstance($version); 35 | $this->version = $version; 36 | } 37 | return $this->api; 38 | } 39 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockTeleportListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 23 | $world = $fromPosition->getWorld(); 24 | /** @phpstan-var WorldSettings|false|null $worldSettings */ 25 | $worldSettings = $this->getAPI()->getOrLoadWorldSettings($world)->getResult(); 26 | if (!($worldSettings instanceof WorldSettings)) { 27 | if ($worldSettings !== false) { 28 | $event->cancel(); 29 | } 30 | return; 31 | } 32 | 33 | $fromBasePlot = $this->getAPI()->getBasePlotAtPoint($world->getFolderName(), $worldSettings, $fromPosition); 34 | if ($fromBasePlot instanceof BasePlot) { 35 | $toPosition = Position::fromObject($event->getTo(), $world); 36 | if ($fromBasePlot->isOnPlot($toPosition)) { 37 | return; 38 | } 39 | /** @phpstan-var Plot|false|null $fromPlot */ 40 | $fromPlot = $this->getAPI()->getOrLoadPlot($world, $fromBasePlot->getX(), $fromBasePlot->getZ())->getResult(); 41 | if ($fromPlot instanceof Plot && $fromPlot->isOnPlot($toPosition)) { 42 | return; 43 | } 44 | } 45 | 46 | $event->cancel(); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/ChunkFetchingAsyncTask.php: -------------------------------------------------------------------------------- 1 | $chunkAreas 24 | */ 25 | public function __construct(World $world, array $chunkAreas) { 26 | parent::__construct(); 27 | $this->minY = $world->getMinY(); 28 | $this->maxY = $world->getMaxY(); 29 | $chunks = []; 30 | foreach ($chunkAreas as $chunkHash => $data) { 31 | World::getXZ($chunkHash, $chunkX, $chunkZ); 32 | $chunk = $world->loadChunk($chunkX, $chunkZ); 33 | if ($chunk === null) { 34 | continue; 35 | } 36 | $chunks[$chunkHash] = FastChunkSerializer::serializeTerrain($chunk); 37 | } 38 | $this->chunks = serialize($chunks); 39 | $this->chunkAreas = serialize($chunkAreas); 40 | } 41 | 42 | protected function getChunkManager() : SimpleChunkManager { 43 | $manager = new SimpleChunkManager($this->minY, $this->maxY); 44 | /** @phpstan-var array $chunks */ 45 | $chunks = unserialize($this->chunks, ["allowed_classes" => false]); 46 | foreach ($chunks as $hash => $chunk) { 47 | World::getXZ($hash, $chunkX, $chunkZ); 48 | $manager->setChunk($chunkX, $chunkZ, FastChunkSerializer::deserializeTerrain($chunk)); 49 | } 50 | return $manager; 51 | } 52 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotBiomeChangeAsyncEvent.php: -------------------------------------------------------------------------------- 1 | biomeID = $biomeID; 28 | } 29 | 30 | /** 31 | * @phpstan-return BiomeIds::* 32 | */ 33 | public function getBiomeID() : int { 34 | return $this->biomeID; 35 | } 36 | 37 | /** 38 | * @phpstan-param BiomeIds::* $biomeID 39 | */ 40 | public function setBiomeID(int $biomeID) : void { 41 | $this->biomeID = $biomeID; 42 | } 43 | 44 | /** 45 | * @phpstan-param BiomeIds::* $biomeID 46 | * @phpstan-return \Generator 47 | */ 48 | public static function create(Plot $plot, int $biomeID) : \Generator { 49 | $event = yield from Await::promise( 50 | static function ($onSuccess, $onError) use ($plot, $biomeID) : void { 51 | $event = new self($plot, $biomeID); 52 | $event->setCallback($onSuccess); 53 | $event->call(); 54 | } 55 | ); 56 | assert($event instanceof self); 57 | return $event; 58 | } 59 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockSpreadListener.php: -------------------------------------------------------------------------------- 1 | getSource()->getPosition(); 24 | /** @phpstan-var true|false|null $isPlotWorld */ 25 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 26 | if ($isPlotWorld !== true) { 27 | if ($isPlotWorld !== false) { 28 | $event->cancel(); 29 | } 30 | return; 31 | } 32 | 33 | /** @phpstan-var Plot|false|null $plot */ 34 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 35 | // We not only need to check if the source is on the plot but also if that applies for the changed block. 36 | if ($plot instanceof Plot && $plot->isOnPlot($event->getBlock()->getPosition())) { 37 | if ($event->getNewState() instanceof Liquid) { 38 | $flag = $plot->getFlag(Flags::FLOWING()); 39 | $flagToCompare = FlowingFlag::TRUE(); 40 | } else { 41 | $flag = $plot->getFlag(Flags::GROWING()); 42 | $flagToCompare = GrowingFlag::TRUE(); 43 | } 44 | if ($flag->equals($flagToCompare)) { 45 | return; 46 | } 47 | } 48 | 49 | $event->cancel(); 50 | } 51 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotPlayerAddAsyncEvent.php: -------------------------------------------------------------------------------- 1 | plotPlayer = $plotPlayer; 26 | $this->player = $player; 27 | } 28 | 29 | /** 30 | * Returns the {@see PlotPlayer} that is being added to the plot. 31 | */ 32 | public function getPlotPlayer() : PlotPlayer { 33 | return $this->plotPlayer; 34 | } 35 | 36 | /** 37 | * Returns the {@see Player} that adds the {@see PlotPlayer} to the plot. 38 | */ 39 | public function getPlayer() : Player { 40 | return $this->player; 41 | } 42 | 43 | /** 44 | * @phpstan-return \Generator 45 | */ 46 | public static function create(Plot $plot, PlotPlayer $plotPlayer, Player $player) : \Generator { 47 | $event = yield from Await::promise( 48 | static function ($onSuccess, $onError) use ($plot, $plotPlayer, $player) : void { 49 | $event = new self($plot, $plotPlayer, $player); 50 | $event->setCallback($onSuccess); 51 | $event->call(); 52 | } 53 | ); 54 | assert($event instanceof self); 55 | return $event; 56 | } 57 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/PlayerBucketEmptyListener.php: -------------------------------------------------------------------------------- 1 | getBlockClicked()->getPosition(); 20 | /** @phpstan-var true|false|null $isPlotWorld */ 21 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 22 | if ($isPlotWorld !== true) { 23 | if ($isPlotWorld !== false) { 24 | $event->cancel(); 25 | } 26 | return; 27 | } 28 | 29 | /** @phpstan-var Plot|false|null $plot */ 30 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 31 | if ($plot instanceof Plot) { 32 | $player = $event->getPlayer(); 33 | if ($player->hasPermission("cplot.interact.plot")) { 34 | return; 35 | } 36 | 37 | if ($plot->isPlotOwner($player)) { 38 | return; 39 | } 40 | if ($plot->isPlotTrusted($player)) { 41 | return; 42 | } 43 | if ($plot->isPlotHelper($player)) { 44 | foreach ($plot->getPlotOwners() as $plotOwner) { 45 | $owner = $plotOwner->getPlayerData()->getPlayer(); 46 | if ($owner !== null) { 47 | return; 48 | } 49 | } 50 | } 51 | 52 | } else if ($plot === false && $event->getPlayer()->hasPermission("cplot.interact.road")) { 53 | return; 54 | } 55 | 56 | $event->cancel(); 57 | } 58 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotPlayerRemoveAsyncEvent.php: -------------------------------------------------------------------------------- 1 | plotPlayer = $plotPlayer; 26 | $this->player = $player; 27 | } 28 | 29 | /** 30 | * Returns the {@see PlotPlayer} that is being removed from the plot. 31 | */ 32 | public function getPlotPlayer() : PlotPlayer { 33 | return $this->plotPlayer; 34 | } 35 | 36 | /** 37 | * Returns the {@see Player} that removes the {@see PlotPlayer} from the plot. 38 | */ 39 | public function getPlayer() : Player { 40 | return $this->player; 41 | } 42 | 43 | /** 44 | * @phpstan-return \Generator 45 | */ 46 | public static function create(Plot $plot, PlotPlayer $plotPlayer, Player $player) : \Generator { 47 | $event = yield from Await::promise( 48 | static function ($onSuccess, $onError) use ($plot, $plotPlayer, $player) : void { 49 | $event = new self($plot, $plotPlayer, $player); 50 | $event->setCallback($onSuccess); 51 | $event->call(); 52 | } 53 | ); 54 | assert($event instanceof self); 55 | return $event; 56 | } 57 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/attributes/BooleanAttribute.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | abstract class BooleanAttribute extends BaseAttribute { 13 | 14 | /** @var array{"1": true, "y": true, "yes": true, "allow": true, "true": true} */ 15 | private const TRUE_VALUES = ["1" => true, "y" => true, "yes" => true, "allow" => true, "true" => true]; 16 | /** @var array{"0": true, "no": true, "deny": true, "disallow": true, "false": true} */ 17 | private const FALSE_VALUES = ["0" => true, "no" => true, "deny" => true, "disallow" => true, "false" => true]; 18 | 19 | public function equals(object $other) : bool { 20 | if (!($other instanceof static)) { 21 | return false; 22 | } 23 | return $this->value === $other->getValue(); 24 | } 25 | 26 | /** 27 | * @param bool $value 28 | */ 29 | public function contains(mixed $value) : bool { 30 | return $this->equals($this->createInstance($value)); 31 | } 32 | 33 | /** 34 | * @param bool $value 35 | */ 36 | public function merge(mixed $value) : self { 37 | return $this->createInstance($value); 38 | } 39 | 40 | public function getExample() : string { 41 | return "true"; 42 | } 43 | 44 | public function toString() : string { 45 | return $this->value ? "true" : "false"; 46 | } 47 | 48 | public function toReadableString() : string { 49 | return $this->value ? "true" : "false"; 50 | } 51 | 52 | /** 53 | * @throws AttributeParseException 54 | */ 55 | public function parse(string $value) : bool { 56 | $value = strtolower($value); 57 | if (isset(self::TRUE_VALUES[$value])) { 58 | return true; 59 | } 60 | if (isset(self::FALSE_VALUES[$value])) { 61 | return false; 62 | } 63 | throw new AttributeParseException($this, $value); 64 | } 65 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/PlayerDropItemListener.php: -------------------------------------------------------------------------------- 1 | getPlayer(); 22 | $position = $player->getPosition(); 23 | /** @phpstan-var true|false|null $isPlotWorld */ 24 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 25 | if ($isPlotWorld !== true) { 26 | if ($isPlotWorld !== false) { 27 | $event->cancel(); 28 | } 29 | return; 30 | } 31 | 32 | /** @phpstan-var Plot|false|null $plot */ 33 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 34 | if ($plot instanceof Plot) { 35 | if ($player->hasPermission("cplot.interact.plot")) { 36 | return; 37 | } 38 | 39 | if ($plot->isPlotOwner($player)) { 40 | return; 41 | } 42 | if ($plot->isPlotTrusted($player)) { 43 | return; 44 | } 45 | if ($plot->isPlotHelper($player)) { 46 | foreach ($plot->getPlotOwners() as $plotOwner) { 47 | $owner = $plotOwner->getPlayerData()->getPlayer(); 48 | if ($owner !== null) { 49 | return; 50 | } 51 | } 52 | } 53 | 54 | if ($plot->getFlag(Flags::ITEM_DROP())->equals(ItemDropFlag::TRUE())) { 55 | return; 56 | } 57 | } 58 | 59 | $event->cancel(); 60 | } 61 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/PlotRate.php: -------------------------------------------------------------------------------- 1 | rate = $rate; 18 | $this->playerData = $playerData; 19 | $this->rateTime = $rateTime; 20 | $this->comment = $comment; 21 | } 22 | 23 | public function getRate() : string { 24 | return $this->rate; 25 | } 26 | 27 | public function getPlayerData() : PlayerData { 28 | return $this->playerData; 29 | } 30 | 31 | public function getRateTime() : int { 32 | return $this->rateTime; 33 | } 34 | 35 | public function getComment() : ?string { 36 | return $this->comment; 37 | } 38 | 39 | public function toString() : string { 40 | return $this->playerData->getPlayerID() . ";" . $this->rateTime; 41 | } 42 | 43 | /** 44 | * @phpstan-return array{rate: string, playerData: string, rateTime: int, comment: string|null} 45 | */ 46 | public function __serialize() : array { 47 | return [ 48 | "rate" => $this->rate, 49 | "playerData" => serialize($this->playerData), 50 | "rateTime" => $this->rateTime, 51 | "comment" => $this->comment 52 | ]; 53 | } 54 | 55 | /** 56 | * @phpstan-param array{rate: string, playerData: string, rateTime: int, comment: string|null} $data 57 | */ 58 | public function __unserialize(array $data) : void { 59 | $this->rate = $data["rate"]; 60 | $playerData = unserialize($data["playerData"], ["allowed_classes" => [PlayerData::class]]); 61 | assert($playerData instanceof PlayerData); 62 | $this->playerData = $playerData; 63 | $this->rateTime = $data["rateTime"]; 64 | $this->comment = $data["comment"]; 65 | } 66 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockBreakListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 21 | /** @phpstan-var true|false|null $isPlotWorld */ 22 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 23 | if ($isPlotWorld !== true) { 24 | if ($isPlotWorld !== false) { 25 | $event->cancel(); 26 | } 27 | return; 28 | } 29 | 30 | /** @phpstan-var Plot|false|null $plot */ 31 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 32 | if ($plot instanceof Plot) { 33 | $player = $event->getPlayer(); 34 | if ($player->hasPermission("cplot.break.plot")) { 35 | return; 36 | } 37 | 38 | if ($plot->isPlotOwner($player)) { 39 | return; 40 | } 41 | if ($plot->isPlotTrusted($player)) { 42 | return; 43 | } 44 | if ($plot->isPlotHelper($player)) { 45 | foreach ($plot->getPlotOwners() as $plotOwner) { 46 | $owner = $plotOwner->getPlayerData()->getPlayer(); 47 | if ($owner !== null) { 48 | return; 49 | } 50 | } 51 | } 52 | 53 | if ($plot->getFlag(Flags::BREAK())->contains($event->getBlock())) { 54 | return; 55 | } 56 | 57 | } else if ($plot === false) { 58 | if ($event->getPlayer()->hasPermission("cplot.break.road")) { 59 | return; 60 | } 61 | } 62 | 63 | $event->cancel(); 64 | } 65 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/EntityDamageByEntityListener.php: -------------------------------------------------------------------------------- 1 | getDamager(); 24 | if (!$damager instanceof Player) { 25 | return; 26 | } 27 | $damaged = $event->getEntity(); 28 | 29 | /** @phpstan-var true|false|null $isPlotWorld */ 30 | $isPlotWorld = $this->getAPI()->isPlotWorld($damaged->getWorld())->getResult(); 31 | if ($isPlotWorld !== true) { 32 | if ($isPlotWorld !== false) { 33 | $event->cancel(); 34 | } 35 | return; 36 | } 37 | 38 | /** @phpstan-var Plot|false|null $plot */ 39 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($damaged->getPosition())->getResult(); 40 | 41 | // pvp flag 42 | if ($damaged instanceof Player) { 43 | if ($plot instanceof Plot) { 44 | if ($damager->hasPermission("cplot.pvp.plot")) { 45 | return; 46 | } 47 | if ($plot->getFlag(Flags::PVP())->equals(PvpFlag::TRUE())) { 48 | return; 49 | } 50 | 51 | } else if ($plot === false) { 52 | if ($damager->hasPermission("cplot.pvp.road")) { 53 | return; 54 | } 55 | } 56 | 57 | // pve flag 58 | } else if ($plot instanceof Plot && $plot->getFlag(Flags::PVE())->equals(PveFlag::TRUE())) { 59 | return; 60 | } 61 | 62 | $event->cancel(); 63 | } 64 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/SpawnSubcommand.php: -------------------------------------------------------------------------------- 1 | awaitWorld($sender->getWorld()->getFolderName())) instanceof WorldSettings)) { 26 | self::sendMessage($sender, ["prefix", "spawn.noPlotWorld"]); 27 | return; 28 | } 29 | 30 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 31 | if (!($plot instanceof Plot)) { 32 | self::sendMessage($sender, ["prefix", "spawn.noPlot"]); 33 | return; 34 | } 35 | 36 | if (!$sender->hasPermission("cplot.admin.spawn")) { 37 | if (!$plot->hasPlotOwner()) { 38 | self::sendMessage($sender, ["prefix", "spawn.noPlotOwner"]); 39 | return; 40 | } 41 | if (!$plot->isPlotOwner($sender)) { 42 | self::sendMessage($sender, ["prefix", "spawn.notPlotOwner"]); 43 | return; 44 | } 45 | } 46 | 47 | $location = $sender->getLocation(); 48 | $flag = Flags::SPAWN()->createInstance(Location::fromObject( 49 | $location->subtractVector($plot->getVector3()), 50 | $sender->getWorld(), 51 | $location->getYaw(), 52 | $location->getPitch() 53 | )); 54 | $plot->addFlag($flag); 55 | yield DataProvider::getInstance()->savePlotFlag($plot, $flag); 56 | self::sendMessage($sender, ["prefix", "spawn.success"]); 57 | } 58 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/CPlotAsyncTask.php: -------------------------------------------------------------------------------- 1 | startTime = (int) (round(microtime(true) * 1000)); 15 | } 16 | 17 | public function getElapsedTime() : int { 18 | return ((int) (round(microtime(true) * 1000))) - $this->startTime; 19 | } 20 | 21 | public function getElapsedTimeString() : string { 22 | $ms = $this->getElapsedTime(); 23 | $min = floor($ms / 60000); 24 | $ms -= $min * 60000; 25 | $s = floor($ms / 1000); 26 | $ms -= $s * 1000; 27 | $time = ""; 28 | if ($min > 0) { 29 | $time .= $min . "min"; 30 | } 31 | if ($s > 0) { 32 | if ($time !== "") $time .= ", "; 33 | $time .= $s . "s"; 34 | } 35 | if ($ms > 0) { 36 | if ($time !== "") $time .= ", "; 37 | $time .= $ms . "ms"; 38 | } 39 | return $time; 40 | } 41 | 42 | /** 43 | * @phpstan-param (callable(static): void)|null $onSuccess 44 | * @phpstan-param (callable(static): void)|null $onError 45 | */ 46 | public function setCallback(?callable $onSuccess, ?callable $onError) : void { 47 | if ($onSuccess !== null) { 48 | $this->storeLocal("onSuccess", $onSuccess); 49 | } 50 | if ($onError !== null) { 51 | $this->storeLocal("onError", $onError); 52 | } 53 | } 54 | 55 | public function onCompletion() : void { 56 | try { 57 | /** @phpstan-var callable(static): void $callback */ 58 | $callback = $this->fetchLocal("onSuccess"); 59 | $callback($this); 60 | } catch (\InvalidArgumentException) { 61 | } 62 | } 63 | 64 | public function onError() : void { 65 | try { 66 | /** @phpstan-var callable(static): void $callback */ 67 | $callback = $this->fetchLocal("onError"); 68 | $callback($this); 69 | } catch (\InvalidArgumentException) { 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/MergePlot.php: -------------------------------------------------------------------------------- 1 | originX = $originX; 18 | $this->originZ = $originZ; 19 | } 20 | 21 | public function getOriginX() : int { 22 | return $this->originX; 23 | } 24 | 25 | public function getOriginZ() : int { 26 | return $this->originZ; 27 | } 28 | 29 | public function toBasePlot() : BasePlot { 30 | return new BasePlot($this->worldName, $this->worldSettings, $this->x, $this->z); 31 | } 32 | 33 | /** 34 | * @deprecated 35 | * @phpstan-return \Generator 36 | */ 37 | public function toPlot() : \Generator { 38 | return yield DataProvider::getInstance()->awaitPlot($this->worldName, $this->originX, $this->originZ); 39 | } 40 | 41 | public static function fromBasePlot(BasePlot $basePlot, int $originX, int $originZ) : self { 42 | return new self( 43 | $basePlot->getWorldName(), $basePlot->getWorldSettings(), $basePlot->getX(), $basePlot->getZ(), 44 | $originX, $originZ 45 | ); 46 | } 47 | 48 | /** 49 | * @phpstan-return array{worldName: string, worldSettings: string, x: int, z: int, originX: int, originZ: int} 50 | */ 51 | public function __serialize() : array { 52 | $data = parent::__serialize(); 53 | $data["originX"] = $this->originX; 54 | $data["originZ"] = $this->originZ; 55 | return $data; 56 | } 57 | 58 | /** 59 | * @phpstan-param array{worldName: string, worldSettings: string, x: int, z: int, originX: int, originZ: int} $data 60 | */ 61 | public function __unserialize(array $data) : void { 62 | parent::__unserialize($data); 63 | $this->originX = $data["originX"]; 64 | $this->originZ = $data["originZ"]; 65 | } 66 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/EntityShootBowListener.php: -------------------------------------------------------------------------------- 1 | getEntity(); 24 | $position = $entity->getPosition(); 25 | /** @phpstan-var true|false|null $isPlotWorld */ 26 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 27 | if ($isPlotWorld !== true) { 28 | if ($isPlotWorld !== false) { 29 | $event->cancel(); 30 | } 31 | return; 32 | } 33 | 34 | /** @phpstan-var Plot|false|null $plot */ 35 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 36 | if (!($plot instanceof Plot)) { 37 | $event->cancel(); 38 | return; 39 | } 40 | 41 | if (!($entity instanceof Player)) { 42 | if ($plot->getFlag(Flags::PVE())->equals(PveFlag::TRUE())) { 43 | return; 44 | } 45 | $event->cancel(); 46 | return; 47 | } 48 | 49 | if ($plot->isPlotOwner($entity)) { 50 | return; 51 | } 52 | if ($plot->isPlotTrusted($entity)) { 53 | return; 54 | } 55 | if ($plot->isPlotHelper($entity)) { 56 | foreach ($plot->getPlotOwners() as $plotOwner) { 57 | $owner = $plotOwner->getPlayerData()->getPlayer(); 58 | if ($owner !== null) { 59 | return; 60 | } 61 | } 62 | } 63 | 64 | if ($plot->getFlag(Flags::PVP())->equals(PvpFlag::TRUE())) { 65 | return; 66 | } 67 | 68 | $event->cancel(); 69 | } 70 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/PlotPlayer.php: -------------------------------------------------------------------------------- 1 | true, 17 | self::STATE_TRUSTED => true, 18 | self::STATE_HELPER => true, 19 | self::STATE_DENIED => true 20 | ]; 21 | 22 | private PlayerData $playerData; 23 | /** @phpstan-var PlotPlayer::STATE_* */ 24 | private string $state; 25 | private int $addTime; 26 | 27 | /** 28 | * @phpstan-param PlotPlayer::STATE_* $state 29 | */ 30 | public function __construct(PlayerData $playerData, string $state, ?int $addTime = null) { 31 | $this->playerData = $playerData; 32 | $this->state = $state; 33 | $this->addTime = $addTime ?? time(); 34 | } 35 | 36 | public function getPlayerData() : PlayerData { 37 | return $this->playerData; 38 | } 39 | 40 | /** 41 | * @phpstan-return PlotPlayer::STATE_* 42 | */ 43 | public function getState() : string { 44 | return $this->state; 45 | } 46 | 47 | public function getAddTime() : int { 48 | return $this->addTime; 49 | } 50 | 51 | /** 52 | * @phpstan-return array{playerData: string, state: PlotPlayer::STATE_*, addTime: int} 53 | */ 54 | public function __serialize() : array { 55 | return [ 56 | "playerData" => serialize($this->playerData), 57 | "state" => $this->state, 58 | "addTime" => $this->addTime 59 | ]; 60 | } 61 | 62 | /** 63 | * @phpstan-param array{playerData: string, state: PlotPlayer::STATE_*, addTime: int} $data 64 | */ 65 | public function __unserialize(array $data) : void { 66 | $playerData = unserialize($data["playerData"], ["allowed_classes" => [PlayerData::class]]); 67 | assert($playerData instanceof PlayerData); 68 | $this->playerData = $playerData; 69 | $this->state = $data["state"]; 70 | $this->addTime = $data["addTime"]; 71 | } 72 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/EntityItemPickupListener.php: -------------------------------------------------------------------------------- 1 | getEntity(); 23 | if (!$entity instanceof Player) { 24 | return; 25 | } 26 | 27 | $position = $entity->getPosition(); 28 | /** @phpstan-var true|false|null $isPlotWorld */ 29 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 30 | if ($isPlotWorld !== true) { 31 | if ($isPlotWorld !== false) { 32 | $event->cancel(); 33 | } 34 | return; 35 | } 36 | 37 | /** @phpstan-var Plot|false|null $plot */ 38 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 39 | if ($plot instanceof Plot) { 40 | if ($entity->hasPermission("cplot.interact.plot")) { 41 | return; 42 | } 43 | 44 | if ($plot->isPlotOwner($entity)) { 45 | return; 46 | } 47 | if ($plot->isPlotTrusted($entity)) { 48 | return; 49 | } 50 | if ($plot->isPlotHelper($entity)) { 51 | foreach ($plot->getPlotOwners() as $plotOwner) { 52 | $owner = $plotOwner->getPlayerData()->getPlayer(); 53 | if ($owner !== null) { 54 | return; 55 | } 56 | } 57 | } 58 | 59 | if ($plot->getFlag(Flags::ITEM_PICKUP())->equals(ItemPickupFlag::TRUE())) { 60 | return; 61 | } 62 | 63 | } else if ($plot === false) { 64 | return; 65 | } 66 | 67 | $event->cancel(); 68 | } 69 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/EntityTrampleFarmlandListener.php: -------------------------------------------------------------------------------- 1 | getEntity(); 21 | $position = $event->getBlock()->getPosition(); 22 | /** @phpstan-var true|false|null $isPlotWorld */ 23 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 24 | if ($isPlotWorld !== true) { 25 | if ($isPlotWorld !== false) { 26 | $event->cancel(); 27 | } 28 | return; 29 | } 30 | 31 | /** @phpstan-var Plot|false|null $plot */ 32 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 33 | if ($plot instanceof Plot) { 34 | if (!($entity instanceof Player)) { 35 | $owningEntity = $entity->getOwningEntity(); 36 | if ($owningEntity instanceof Player) { 37 | $entity = $owningEntity; 38 | } else { 39 | return; 40 | } 41 | } 42 | if ($entity->hasPermission("cplot.interact.plot")) { 43 | return; 44 | } 45 | if ($plot->isPlotOwner($entity)) { 46 | return; 47 | } 48 | if ($plot->isPlotTrusted($entity)) { 49 | return; 50 | } 51 | if ($plot->isPlotHelper($entity)) { 52 | foreach ($plot->getPlotOwners() as $plotOwner) { 53 | $owner = $plotOwner->getPlayerData()->getPlayer(); 54 | if ($owner !== null) { 55 | return; 56 | } 57 | } 58 | } 59 | 60 | } else if ($plot === false && $entity instanceof Player && $entity->hasPermission("cplot.interact.road")) { 61 | return; 62 | } 63 | 64 | $event->cancel(); 65 | } 66 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/HelpersSubcommand.php: -------------------------------------------------------------------------------- 1 | awaitWorld($sender->getWorld()->getFolderName())) instanceof WorldSettings)) { 24 | self::sendMessage($sender, ["prefix", "helpers.noPlotWorld"]); 25 | return; 26 | } 27 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 28 | if (!($plot instanceof Plot)) { 29 | self::sendMessage($sender, ["prefix", "helpers.noPlot"]); 30 | return; 31 | } 32 | 33 | $helperData = []; 34 | foreach ($plot->getPlotHelpers() as $plotPlayer) { 35 | $plotPlayerData = $plotPlayer->getPlayerData(); 36 | $addTime = self::translateForCommandSender( 37 | $sender, 38 | ["format.time" => explode(".", date("Y.m.d.H.i.s", $plotPlayer->getAddTime()))] 39 | ); 40 | $helperData[] = self::translateForCommandSender( 41 | $sender, 42 | ["format.list.playerWithTime" => [ 43 | $plotPlayerData->getPlayerName() ?? "Unknown", 44 | $addTime 45 | ]] 46 | ); 47 | } 48 | if (count($helperData) === 0) { 49 | self::sendMessage($sender, ["prefix", "helpers.noHelpers"]); 50 | return; 51 | } 52 | 53 | /** @phpstan-var string $separator */ 54 | $separator = self::translateForCommandSender($sender, "format.list.playerWithTime.separator"); 55 | $list = implode($separator, $helperData); 56 | self::sendMessage( 57 | $sender, 58 | [ 59 | "prefix", 60 | "helpers.success" => $list 61 | ] 62 | ); 63 | } 64 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/PlotBiomeChangeAsyncTask.php: -------------------------------------------------------------------------------- 1 | biomeID = $biomeID; 27 | 28 | $chunks = []; 29 | $this->getChunksFromAreas("", $this->calculateBasePlotAreas($plot->getWorldSettings(), $plot), $chunks); 30 | $this->getChunksFromAreas("", $this->calculateMergeRoadAreas($plot->getWorldSettings(), $plot), $chunks); 31 | 32 | $world = $plot->getWorld(); 33 | assert($world instanceof World); 34 | parent::__construct($world, $chunks); 35 | } 36 | 37 | public function onRun() : void { 38 | $world = $this->getChunkManager(); 39 | 40 | $finishedChunks = []; 41 | /** @phpstan-var array> $chunkAreas */ 42 | $chunkAreas = unserialize($this->chunkAreas, ["allowed_classes" => false]); 43 | foreach ($chunkAreas as $chunkHash => $blockHashs) { 44 | 45 | World::getXZ($chunkHash, $chunkX, $chunkZ); 46 | $chunk = $world->getChunk($chunkX, $chunkZ); 47 | assert($chunk instanceof Chunk); 48 | 49 | foreach ($blockHashs[""] as $blockHash) { 50 | World::getXZ($blockHash, $xInChunk, $zInChunk); 51 | for ($y = $world->getMinY(); $y < $world->getMaxY(); $y++) { 52 | $chunk->setBiomeId($xInChunk, $y, $zInChunk, $this->biomeID); 53 | } 54 | } 55 | 56 | $finishedChunks[$chunkHash] = FastChunkSerializer::serializeTerrain($chunk); 57 | } 58 | 59 | $this->chunks = serialize($finishedChunks); 60 | } 61 | 62 | /** 63 | * @phpstan-return BiomeIds::* 64 | */ 65 | public function getBiomeID() : int { 66 | return $this->biomeID; 67 | } 68 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/DeniedSubcommand.php: -------------------------------------------------------------------------------- 1 | awaitWorld($sender->getWorld()->getFolderName())) instanceof WorldSettings)) { 24 | self::sendMessage($sender, ["prefix", "denied.noPlotWorld"]); 25 | return; 26 | } 27 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 28 | if (!($plot instanceof Plot)) { 29 | self::sendMessage($sender, ["prefix", "denied.noPlot"]); 30 | return; 31 | } 32 | 33 | $deniedPlayerData = []; 34 | foreach ($plot->getPlotDenied() as $plotPlayer) { 35 | $plotPlayerData = $plotPlayer->getPlayerData(); 36 | /** @phpstan-var string $addTime */ 37 | $addTime = self::translateForCommandSender( 38 | $sender, 39 | ["format.time" => explode(".", date("Y.m.d.H.i.s", $plotPlayer->getAddTime()))] 40 | ); 41 | $deniedPlayerData[] = self::translateForCommandSender( 42 | $sender, 43 | ["format.list.playerWithTime" => [ 44 | $plotPlayerData->getPlayerName() ?? "Unknown", 45 | $addTime 46 | ]] 47 | ); 48 | } 49 | if (count($deniedPlayerData) === 0) { 50 | self::sendMessage($sender, ["prefix", "denied.noDeniedPlayers"]); 51 | return; 52 | } 53 | 54 | /** @phpstan-var string $separator */ 55 | $separator = self::translateForCommandSender($sender, "format.list.playerWithTime.separator"); 56 | $list = implode($separator, $deniedPlayerData); 57 | self::sendMessage( 58 | $sender, 59 | [ 60 | "prefix", 61 | "denied.success" => $list 62 | ] 63 | ); 64 | } 65 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/TrustedSubcommand.php: -------------------------------------------------------------------------------- 1 | awaitWorld($sender->getWorld()->getFolderName())) instanceof WorldSettings)) { 24 | self::sendMessage($sender, ["prefix", "trusted.noPlotWorld"]); 25 | return; 26 | } 27 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 28 | if (!($plot instanceof Plot)) { 29 | self::sendMessage($sender, ["prefix", "trusted.noPlot"]); 30 | return; 31 | } 32 | 33 | $trustedPlayerData = []; 34 | foreach ($plot->getPlotTrusted() as $plotPlayer) { 35 | $plotPlayerData = $plotPlayer->getPlayerData(); 36 | /** @phpstan-var string $addTime */ 37 | $addTime = self::translateForCommandSender( 38 | $sender, 39 | ["format.time" => explode(".", date("Y.m.d.H.i.s", $plotPlayer->getAddTime()))] 40 | ); 41 | $trustedPlayerData[] = self::translateForCommandSender( 42 | $sender, 43 | ["format.list.playerWithTime" => [ 44 | $plotPlayerData->getPlayerName() ?? "Unknown", 45 | $addTime 46 | ]] 47 | ); 48 | } 49 | if (count($trustedPlayerData) === 0) { 50 | self::sendMessage($sender, ["prefix", "trusted.noTrustedPlayers"]); 51 | return; 52 | } 53 | 54 | /** @phpstan-var string $separator */ 55 | $separator = self::translateForCommandSender($sender, "format.list.playerWithTime.separator"); 56 | $list = implode($separator, $trustedPlayerData); 57 | self::sendMessage( 58 | $sender, 59 | [ 60 | "prefix", 61 | "trusted.success" => $list 62 | ] 63 | ); 64 | } 65 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/cache/Cache.php: -------------------------------------------------------------------------------- 1 | */ 15 | private array $cache = []; 16 | 17 | /** 18 | * @param int $size 19 | * if $size > 0, cache is enabled and the size of Cache::$cache is limited by $size 20 | * if $size <= 0, cache is disabled 21 | */ 22 | public function __construct(int $size) { 23 | $this->size = $size; 24 | } 25 | 26 | /** 27 | * @phpstan-param TIdentifier $identifier 28 | * @phpstan-param TCacheable $cacheable 29 | */ 30 | public function cacheObject(mixed $identifier, mixed $cacheable) : void { 31 | // if the cache is disabled, we don't need to save anything 32 | if ($this->size <= 0) { 33 | return; 34 | } 35 | 36 | // if the object is already cached, we remove its old version from the cache 37 | if (isset($this->cache[$identifier])) { 38 | unset($this->cache[$identifier]); 39 | 40 | // if the cache has grown to big, we remove the oldest element from the cache 41 | // oldest element = first element of the array Cache::$cache 42 | } else if ($this->size <= count($this->cache)) { 43 | array_shift($this->cache); 44 | } 45 | 46 | // adding the object to the end of the cache 47 | if (is_object($cacheable)) { 48 | $cacheable = clone $cacheable; 49 | } 50 | $this->cache[$identifier] = $cacheable; 51 | } 52 | 53 | /** 54 | * @phpstan-param TIdentifier $identifier 55 | * @phpstan-return TCacheable|null 56 | */ 57 | public function getObjectFromCache(mixed $identifier) : mixed { 58 | // if the cache is disabled, we don't need to check if anything is set in Cache::$cache 59 | if ($this->size <= 0) { 60 | return null; 61 | } 62 | // if no object is saved under $key, return null 63 | return $this->cache[$identifier] ?? null; 64 | } 65 | 66 | /** 67 | * @phpstan-param TIdentifier $identifier 68 | */ 69 | public function removeObjectFromCache(mixed $identifier) : void { 70 | // if the cache is disabled, we don't need to try to remove an object from Cache::$cache 71 | if ($this->size <= 0) { 72 | return; 73 | } 74 | unset($this->cache[$identifier]); 75 | } 76 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/BlockPlaceListener.php: -------------------------------------------------------------------------------- 1 | getTransaction()->getBlocks() as [$x, $y, $z, $block]) { 28 | $position = $block->getPosition(); 29 | /** @var true|false|null $isPlotWorld */ 30 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 31 | if ($isPlotWorld !== true) { 32 | if ($isPlotWorld !== false) { 33 | $event->cancel(); 34 | } 35 | continue; 36 | } 37 | 38 | /** @var Plot|false|null $plot */ 39 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 40 | if ($plot instanceof Plot) { 41 | $player = $event->getPlayer(); 42 | if ($player->hasPermission("cplot.place.plot")) { 43 | continue; 44 | } 45 | 46 | if ($plot->isPlotOwner($player)) { 47 | continue; 48 | } 49 | if ($plot->isPlotTrusted($player)) { 50 | continue; 51 | } 52 | if ($plot->isPlotHelper($player)) { 53 | foreach ($plot->getPlotOwners() as $plotOwner) { 54 | $owner = $plotOwner->getPlayerData()->getPlayer(); 55 | if ($owner !== null) { 56 | continue 2; 57 | } 58 | } 59 | } 60 | 61 | if ($plot->getFlag(Flags::PLACE())->contains($block)) { 62 | continue; 63 | } 64 | 65 | } else if ($plot === false) { 66 | if ($event->getPlayer()->hasPermission("cplot.place.road")) { 67 | continue; 68 | } 69 | } 70 | $event->cancel(); 71 | break; 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/Flag.php: -------------------------------------------------------------------------------- 1 | $other 28 | */ 29 | public function equals(object $other) : bool; 30 | 31 | /** 32 | * Check if the given value is equal or part of the flag's value. 33 | * @param (TValue is array ? value-of : TValue) $value 34 | */ 35 | public function contains(mixed $value) : bool; 36 | 37 | /** 38 | * Create a new instance of the flag with the given value. 39 | * @param TValue $value 40 | * @return static 41 | */ 42 | public function createInstance(mixed $value) : static; 43 | 44 | /** 45 | * Merges this flag's value with another value and return an instance holding the merged value. 46 | * 47 | * @param TValue $value 48 | * @return static 49 | */ 50 | public function merge(mixed $value) : object; 51 | 52 | /** 53 | * Returns an example of a string that would parse into a valid value of this instance. 54 | */ 55 | public function getExample() : string; 56 | 57 | /** 58 | * Returns a string representation of the flag instance, that when passed through {@see parse()} will result in 59 | * an equivalent instance of the flag. 60 | * 61 | * @return string representation of the flag 62 | */ 63 | public function toString() : string; 64 | 65 | /** 66 | * Returns a more easily readable string representation of the flag instance, that might not be parseable with 67 | * {@see parse()}. 68 | * This method is used for display purposes and should not be used for storage or parsing. 69 | * 70 | * @return string representation of the flag 71 | */ 72 | public function toReadableString() : string; 73 | 74 | /** 75 | * Parse a string into a flag value, and throw an exception in the case that the string does not represent a 76 | * valid value. 77 | * Returns the parsed value. 78 | * 79 | * @return TValue 80 | * @throws AttributeParseException if the value could not be parsed 81 | */ 82 | public function parse(string $value) : mixed; 83 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/PlayerInteractListener.php: -------------------------------------------------------------------------------- 1 | getBlock()->getPosition(); 25 | /** @phpstan-var true|false|null $isPlotWorld */ 26 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 27 | if ($isPlotWorld !== true) { 28 | if ($isPlotWorld !== false) { 29 | $event->cancel(); 30 | } 31 | return; 32 | } 33 | 34 | /** @phpstan-var Plot|false|null $plot */ 35 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 36 | if ($plot instanceof Plot) { 37 | $player = $event->getPlayer(); 38 | if ($player->hasPermission("cplot.interact.plot")) { 39 | return; 40 | } 41 | 42 | if ($plot->isPlotOwner($player)) { 43 | return; 44 | } 45 | if ($plot->isPlotTrusted($player)) { 46 | return; 47 | } 48 | if ($plot->isPlotHelper($player)) { 49 | foreach ($plot->getPlotOwners() as $plotOwner) { 50 | $owner = $plotOwner->getPlayerData()->getPlayer(); 51 | if ($owner !== null) { 52 | return; 53 | } 54 | } 55 | } 56 | 57 | $block = $event->getBlock(); 58 | if ( 59 | ($block instanceof Door || $block instanceof Trapdoor || $block instanceof FenceGate) && 60 | $plot->getFlag(Flags::PLAYER_INTERACT())->equals(PlayerInteractFlag::TRUE()) 61 | ) { 62 | return; 63 | } 64 | if ($plot->getFlag(Flags::USE())->contains($block)) { 65 | return; 66 | } 67 | 68 | } else if ($plot === false) { 69 | if ($event->getPlayer()->hasPermission("cplot.interact.road")) { 70 | return; 71 | } 72 | } 73 | 74 | $event->cancel(); 75 | } 76 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/GenerateSubcommand.php: -------------------------------------------------------------------------------- 1 | getServer()->getWorldManager()->isWorldGenerated($worldName)) { 32 | self::sendMessage($sender, ["prefix", "generate.worldExists" => $worldName]); 33 | return; 34 | } 35 | 36 | $options = new WorldCreationOptions(); 37 | $options->setGeneratorClass(PlotGenerator::class); 38 | $worldSettings = WorldSettings::fromConfig(); 39 | $worldSettingsArray = $worldSettings->toArray(); 40 | $worldSettingsArray["worldName"] = $worldName; 41 | $options->setGeneratorOptions(json_encode($worldSettingsArray, JSON_THROW_ON_ERROR)); 42 | $options->setSpawnPosition(new Vector3(0, $worldSettings->getGroundSize() + 1, 0)); 43 | 44 | /** @phpstan-var PlotWorldGenerateAsyncEvent $event */ 45 | $event = yield from PlotWorldGenerateAsyncEvent::create($worldName, $worldSettings, $options); 46 | if ($event->isCancelled()) { 47 | return; 48 | } 49 | $worldName = $event->getWorldName(); 50 | 51 | if (!Server::getInstance()->getWorldManager()->generateWorld($worldName, $event->getWorldCreationOptions())) { 52 | self::sendMessage($sender, ["prefix", "generate.generateError"]); 53 | return; 54 | } 55 | try { 56 | yield from DataProvider::getInstance()->addWorld($worldName, $event->getWorldSettings()); 57 | } catch(SqlError $exception) { 58 | self::sendMessage($sender, ["prefix", "generate.saveError"]); 59 | $sender->getServer()->getLogger()->logException($exception); 60 | return; 61 | } 62 | self::sendMessage($sender, ["prefix", "generate.success" => $worldName]); 63 | } 64 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/Setting.php: -------------------------------------------------------------------------------- 1 | $other 28 | */ 29 | public function equals(object $other) : bool; 30 | 31 | /** 32 | * Check if the given value is equal or part of the setting's value. 33 | * @param (TValue is array ? value-of : TValue) $value 34 | */ 35 | public function contains(mixed $value) : bool; 36 | 37 | /** 38 | * Create a new instance of the setting with the given value. 39 | * @param TValue $value 40 | * @return static 41 | */ 42 | public function createInstance(mixed $value) : static; 43 | 44 | /** 45 | * Merges this setting's value with another value and return an instance holding the merged value. 46 | * 47 | * @param TValue $value 48 | * @return static 49 | */ 50 | public function merge(mixed $value) : object; 51 | 52 | /** 53 | * Returns an example of a string that would parse into a valid value of this instance. 54 | */ 55 | public function getExample() : string; 56 | 57 | /** 58 | * Returns a string representation of the setting instance, that when passed through {@see parse()} will result in 59 | * an equivalent instance of the setting. 60 | * 61 | * @return string representation of the setting 62 | */ 63 | public function toString() : string; 64 | 65 | /** 66 | * Returns a more easily readable string representation of the setting instance, that might not be parseable with 67 | * {@see parse()}. 68 | * This method is used for display purposes and should not be used for storage or parsing. 69 | * 70 | * @return string representation of the setting 71 | */ 72 | public function toReadableString() : string; 73 | 74 | /** 75 | * Parse a string into a setting value, and throw an exception in the case that the string does not represent a 76 | * valid value. 77 | * Returns the parsed value. 78 | * 79 | * @return TValue 80 | * @throws AttributeParseException if the value could not be parsed 81 | */ 82 | public function parse(string $value) : mixed; 83 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/PlotBorderChangeAsyncTask.php: -------------------------------------------------------------------------------- 1 | blockFullID = $block->getStateId(); 25 | $worldSettings = $plot->getWorldSettings(); 26 | $this->y = $worldSettings->getGroundSize() + 1; 27 | 28 | $chunks = []; 29 | $this->getChunksFromAreas("", $this->calculatePlotBorderAreas($worldSettings, $plot), $chunks); 30 | 31 | $world = $plot->getWorld(); 32 | assert($world instanceof World); 33 | parent::__construct($world, $chunks); 34 | } 35 | 36 | public function onRun() : void { 37 | $world = $this->getChunkManager(); 38 | $explorer = new SubChunkExplorer($world); 39 | $finishedChunks = []; 40 | $yInChunk = $this->y & 0x0f; 41 | /** @phpstan-var array> $chunkAreas */ 42 | $chunkAreas = unserialize($this->chunkAreas, ["allowed_classes" => false]); 43 | foreach ($chunkAreas as $chunkHash => $blockHashs) { 44 | World::getXZ($chunkHash, $chunkX, $chunkZ); 45 | 46 | foreach ($blockHashs[""] as $blockHash) { 47 | World::getXZ($blockHash, $xInChunk, $zInChunk); 48 | $x = CoordinateUtils::getCoordinateFromChunk($chunkX, $xInChunk); 49 | $z = CoordinateUtils::getCoordinateFromChunk($chunkZ, $zInChunk); 50 | $explorer->moveTo($x, $this->y, $z); 51 | if ($explorer->currentSubChunk instanceof SubChunk) { 52 | $explorer->currentSubChunk->setBlockStateId( 53 | $xInChunk, 54 | $yInChunk, 55 | $zInChunk, 56 | $this->blockFullID 57 | ); 58 | } 59 | } 60 | 61 | $chunk = $world->getChunk($chunkX, $chunkZ); 62 | assert($chunk instanceof Chunk); 63 | $finishedChunks[$chunkHash] = FastChunkSerializer::serializeTerrain($chunk); 64 | } 65 | 66 | $this->chunks = serialize($finishedChunks); 67 | } 68 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/attributes/LocationAttribute.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | abstract class LocationAttribute extends BaseAttribute { 19 | 20 | public function equals(object $other) : bool { 21 | if (!($other instanceof static)) { 22 | return false; 23 | } 24 | return $this->value->equals($other->getValue()); 25 | } 26 | 27 | /** 28 | * @param Location $value 29 | */ 30 | public function contains(mixed $value) : bool { 31 | return $this->equals($this->createInstance($value)); 32 | } 33 | 34 | /** 35 | * @param Location $value 36 | */ 37 | public function merge(mixed $value) : self { 38 | return $this->createInstance($value); 39 | } 40 | 41 | public function getExample() : string { 42 | return "0;0;0;0;0"; 43 | } 44 | 45 | public function toString() : string { 46 | return $this->value->x . ";" . $this->value->y . ";" . $this->value->z . ";" . $this->value->yaw . ";" . $this->value->pitch; 47 | } 48 | 49 | public function toReadableString() : string { 50 | return 51 | "X: " . $this->value->x . 52 | ", Y: " . $this->value->y . 53 | ", Z: " . $this->value->z . 54 | ", Yaw: " . $this->value->yaw . 55 | ", Pitch: " . $this->value->pitch; 56 | } 57 | 58 | /** 59 | * @throws AttributeParseException 60 | */ 61 | public function parse(string $value) : Location { 62 | $locationData = explode(";", $value); 63 | if (count($locationData) === 5) { 64 | [$x, $y, $z, $yaw, $pitch] = explode(";", $value); 65 | if (is_numeric($x) && is_numeric($y) && is_numeric($z) && is_numeric($yaw) && is_numeric($pitch)) { 66 | $x = (float) $x; 67 | $y = (float) $y; 68 | $z = (float) $z; 69 | $yaw = (float) $yaw; 70 | $pitch = (float) $pitch; 71 | if ( 72 | !is_nan($x) && !is_nan($y) && !is_nan($z) && !is_nan($yaw) && !is_nan($pitch) && 73 | !is_infinite($x) && !is_infinite($y) && !is_infinite($z) && !is_infinite($yaw) && !is_infinite($pitch) 74 | ) { 75 | return new Location($x, $y, $z, null, $yaw, $pitch); 76 | } 77 | } 78 | } 79 | throw new AttributeParseException($this, $value); 80 | } 81 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/HelpSubcommand.php: -------------------------------------------------------------------------------- 1 | command = $command; 19 | } 20 | 21 | public function execute(CommandSender $sender, array $args) : void { 22 | if (count($args) === 0) { 23 | $page = 1; 24 | } else if (is_numeric($args[0])) { 25 | $page = (int) $args[0]; 26 | if ($page <= 0) { 27 | $page = 1; 28 | } 29 | } else { 30 | $page = 1; 31 | } 32 | 33 | $subcommands = []; 34 | $checkPermission = (bool) ResourceManager::getInstance()->getConfig()->get("help.checkPermission", true); 35 | foreach ($this->command->getSubcommands() as $subcommand) { 36 | if ($checkPermission) { 37 | if ($sender->hasPermission($subcommand->getPermission())) { 38 | $subcommands[$subcommand->getName()] = $subcommand; 39 | } 40 | } else { 41 | $subcommands[$subcommand->getName()] = $subcommand; 42 | } 43 | } 44 | 45 | ksort($subcommands, SORT_NATURAL | SORT_FLAG_CASE); 46 | $screenLineHeight = $sender->getScreenLineHeight(); 47 | /** @var array> $subcommands */ 48 | $subcommands = array_chunk($subcommands, $screenLineHeight); 49 | /** @var int $page */ 50 | $page = min(count($subcommands), $page); 51 | 52 | $subcommandsOnPage = []; 53 | foreach ($subcommands[$page - 1] as $subcommand) { 54 | /** @phpstan-var string $description */ 55 | $description = self::translateForCommandSender($sender, $subcommand->getName() . ".description"); 56 | $subcommandsOnPage[] = self::translateForCommandSender( 57 | $sender, 58 | ["format.list.commandWithDescription" => [$subcommand->getName(), $description]] 59 | ); 60 | } 61 | 62 | /** @phpstan-var string $separator */ 63 | $separator = self::translateForCommandSender($sender, "format.list.commandWithDescription.separator"); 64 | $list = implode($separator, $subcommandsOnPage); 65 | self::sendMessage( 66 | $sender, 67 | [ 68 | "prefix", 69 | "help.success" => [$page, count($subcommands), $list] 70 | ] 71 | ); 72 | } 73 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/ProjectileLaunchListener.php: -------------------------------------------------------------------------------- 1 | getEntity(); 28 | $position = $entity->getPosition(); 29 | /** @phpstan-var true|false|null $isPlotWorld */ 30 | $isPlotWorld = $this->getAPI()->isPlotWorld($position->getWorld())->getResult(); 31 | if ($isPlotWorld !== true) { 32 | if ($isPlotWorld !== false) { 33 | $event->cancel(); 34 | } 35 | return; 36 | } 37 | 38 | /** @phpstan-var Plot|false|null $plot */ 39 | $plot = $this->getAPI()->getOrLoadPlotAtPosition($position)->getResult(); 40 | if (!($plot instanceof Plot)) { 41 | $event->cancel(); 42 | return; 43 | } 44 | 45 | $owningEntity = $entity->getOwningEntity(); 46 | if (!($owningEntity instanceof Player)) { 47 | if ($owningEntity !== null && $plot->getFlag(Flags::PVE())->equals(PveFlag::TRUE())) { 48 | return; 49 | } 50 | $event->cancel(); 51 | return; 52 | } 53 | 54 | if ($plot->isPlotOwner($owningEntity)) { 55 | return; 56 | } 57 | if ($plot->isPlotTrusted($owningEntity)) { 58 | return; 59 | } 60 | if ($plot->isPlotHelper($owningEntity)) { 61 | foreach ($plot->getPlotOwners() as $plotOwner) { 62 | $owner = $plotOwner->getPlayerData()->getPlayer(); 63 | if ($owner !== null) { 64 | return; 65 | } 66 | } 67 | } 68 | 69 | if ( 70 | ( 71 | $entity instanceof Arrow || 72 | $entity instanceof Egg || 73 | $entity instanceof Snowball || 74 | $entity instanceof SplashPotion 75 | ) && 76 | $plot->getFlag(Flags::PVP())->equals(PvpFlag::TRUE()) 77 | ) { 78 | return; 79 | } 80 | 81 | $event->cancel(); 82 | } 83 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/tasks/async/PlotWallChangeAsyncTask.php: -------------------------------------------------------------------------------- 1 | blockFullID = $block->getStateId(); 25 | $worldSettings = $plot->getWorldSettings(); 26 | $this->groundSize = $worldSettings->getGroundSize(); 27 | 28 | $chunks = []; 29 | $this->getChunksFromAreas("", $this->calculatePlotBorderAreas($worldSettings, $plot), $chunks); 30 | 31 | $world = $plot->getWorld(); 32 | assert($world instanceof World); 33 | parent::__construct($world, $chunks); 34 | } 35 | 36 | public function onRun() : void { 37 | $world = $this->getChunkManager(); 38 | $explorer = new SubChunkExplorer($world); 39 | $finishedChunks = []; 40 | /** @phpstan-var array> $chunkAreas */ 41 | $chunkAreas = unserialize($this->chunkAreas, ["allowed_classes" => false]); 42 | foreach ($chunkAreas as $chunkHash => $blockHashs) { 43 | World::getXZ($chunkHash, $chunkX, $chunkZ); 44 | 45 | foreach ($blockHashs[""] as $blockHash) { 46 | World::getXZ($blockHash, $xInChunk, $zInChunk); 47 | $x = CoordinateUtils::getCoordinateFromChunk($chunkX, $xInChunk); 48 | $z = CoordinateUtils::getCoordinateFromChunk($chunkZ, $zInChunk); 49 | for ($y = $world->getMinY() + 1; $y <= $this->groundSize; $y++) { 50 | $explorer->moveTo($x, $y, $z); 51 | if ($explorer->currentSubChunk instanceof SubChunk) { 52 | $explorer->currentSubChunk->setBlockStateId( 53 | $xInChunk, 54 | ($y & 0x0f), 55 | $zInChunk, 56 | $this->blockFullID 57 | ); 58 | } 59 | } 60 | } 61 | 62 | $chunk = $world->getChunk($chunkX, $chunkZ); 63 | assert($chunk instanceof Chunk); 64 | $finishedChunks[$chunkHash] = FastChunkSerializer::serializeTerrain($chunk); 65 | } 66 | 67 | $this->chunks = serialize($finishedChunks); 68 | } 69 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/Subcommand.php: -------------------------------------------------------------------------------- 1 | */ 23 | private array $alias; 24 | private string $permission; 25 | 26 | public function __construct(string $key) { 27 | $this->key = $key; 28 | $languageProvider = LanguageManager::getInstance()->getProvider(); 29 | $this->name = $languageProvider->translateString($key . ".name"); 30 | $this->alias = ParseUtils::parseAliasesFromString($languageProvider->translateString($key . ".alias")); 31 | $this->permission = "cplot.subcommand." . $key; 32 | } 33 | 34 | public function getName() : string { 35 | return $this->name; 36 | } 37 | 38 | /** 39 | * @return string[] 40 | */ 41 | public function getAlias() : array { 42 | return $this->alias; 43 | } 44 | 45 | public function getPermission() : string { 46 | return $this->permission; 47 | } 48 | 49 | public function testPermission(CommandSender $sender) : bool { 50 | if ($sender->hasPermission($this->permission)) { 51 | return true; 52 | } 53 | self::sendMessage($sender, ["prefix", $this->key . ".permissionMessage"]); 54 | return false; 55 | } 56 | 57 | /** 58 | * This method contains the code you want to be executed when the command is run. 59 | * @param string[] $args 60 | */ 61 | abstract public function execute(CommandSender $sender, array $args) : void; 62 | 63 | /** 64 | * Utility method to send a message to a command sender, while also removing some boilerplate code within the 65 | * subcommand classes. 66 | * @phpstan-param array>|MessageKey $keys 67 | */ 68 | final protected static function sendMessage(CommandSender $sender, array|string $keys) : void { 69 | LanguageManager::getInstance()->getProvider()->sendMessage($sender, $keys); 70 | } 71 | 72 | /** 73 | * Utility method to translate a message for a command sender, while also removing some boilerplate code within the 74 | * subcommand classes. 75 | * @phpstan-param array>|MessageKey $keys 76 | */ 77 | final protected static function translateForCommandSender(CommandSender $sender, array|string $keys) : string { 78 | return LanguageManager::getInstance()->getProvider()->translateForCommandSender($sender, $keys); 79 | } 80 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/WarpSubcommand.php: -------------------------------------------------------------------------------- 1 | getWorld()->getFolderName(); 30 | [$x, $z] = $plotKeys; 31 | break; 32 | case 3: 33 | [$worldName, $x, $z] = $plotKeys; 34 | break; 35 | default: 36 | self::sendMessage($sender, ["prefix", "warp.usage"]); 37 | return; 38 | } 39 | break; 40 | case 2: 41 | $worldName = $sender->getWorld()->getFolderName(); 42 | [$x, $z] = $args; 43 | break; 44 | case 3: 45 | [$worldName, $x, $z] = $args; 46 | break; 47 | default: 48 | self::sendMessage($sender, ["prefix", "warp.usage"]); 49 | return; 50 | } 51 | 52 | $worldSettings = yield DataProvider::getInstance()->awaitWorld($worldName); 53 | if (!($worldSettings instanceof WorldSettings)) { 54 | self::sendMessage($sender, ["prefix", "warp.invalidPlotWorld" => $worldName]); 55 | return; 56 | } 57 | if (!is_numeric($x)) { 58 | self::sendMessage($sender, ["prefix", "warp.invalidXCoordinate" => $x]); 59 | return; 60 | } 61 | if (!is_numeric($z)) { 62 | self::sendMessage($sender, ["prefix", "warp.invalidZCoordinate" => $z]); 63 | return; 64 | } 65 | 66 | $plot = yield (new BasePlot($worldName, $worldSettings, (int) $x, (int) $z))->toAsyncPlot(); 67 | if (!($plot instanceof Plot)) { 68 | self::sendMessage($sender, ["prefix", "warp.loadPlotError"]); 69 | return; 70 | } 71 | 72 | if (!$sender->hasPermission("cplot.admin.warp")) { 73 | if (!$plot->hasPlotOwner()) { 74 | self::sendMessage($sender, ["prefix", "warp.noPlotOwner"]); 75 | return; 76 | } 77 | } 78 | 79 | if (!($plot->teleportTo($sender))) { 80 | self::sendMessage($sender, ["prefix", "warp.teleportError"]); 81 | return; 82 | } 83 | self::sendMessage($sender, ["prefix", "warp.success" => [$plot->getWorldName(), $plot->getX(), $plot->getZ()]]); 84 | } 85 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/player/settings/Settings.php: -------------------------------------------------------------------------------- 1 | $setting 39 | */ 40 | protected static function register(string $settingID, Setting $setting) : void{ 41 | self::_registryRegister($settingID, $setting); 42 | } 43 | 44 | protected static function setup() : void { 45 | $settingManager = SettingManager::getInstance(); 46 | self::register(SettingIDs::SETTING_INFORM_ADDED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_ADDED)); 47 | self::register(SettingIDs::SETTING_INFORM_DENIED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_DENIED)); 48 | self::register(SettingIDs::SETTING_INFORM_RATE_ADD, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_RATE_ADD)); 49 | self::register(SettingIDs::SETTING_INFORM_REMOVED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_REMOVED)); 50 | self::register(SettingIDs::SETTING_INFORM_TRUSTED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_TRUSTED)); 51 | self::register(SettingIDs::SETTING_INFORM_UNDENIED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_UNDENIED)); 52 | self::register(SettingIDs::SETTING_INFORM_UNTRUSTED, $settingManager->getSettingByID(SettingIDs::SETTING_INFORM_UNTRUSTED)); 53 | self::register(SettingIDs::SETTING_TELEPORT_FLAG_CHANGE, $settingManager->getSettingByID(SettingIDs::SETTING_TELEPORT_FLAG_CHANGE)); 54 | self::register(SettingIDs::SETTING_WARN_FLAG_CHANGE, $settingManager->getSettingByID(SettingIDs::SETTING_WARN_FLAG_CHANGE)); 55 | self::register(SettingIDs::SETTING_WARN_FLAG, $settingManager->getSettingByID(SettingIDs::SETTING_WARN_FLAG)); 56 | } 57 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Plugin Phar 2 | 3 | on: 4 | push 5 | 6 | jobs: 7 | build: 8 | name: Build Plugin Phar 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: 8.1 20 | ini-values: phar.readonly=0 21 | coverage: none 22 | 23 | - name: Get composer cache directory 24 | id: composer-cache 25 | run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT 26 | 27 | - name: Cache composer dependencies 28 | uses: actions/cache@v3 29 | with: 30 | path: ${{ steps.composer-cache.outputs.dir }} 31 | # Use composer.json for key, if composer.lock is not committed. 32 | # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 33 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 34 | restore-keys: ${{ runner.os }}-composer- 35 | 36 | - name: Download pmmp plugin build script 37 | run: wget https://raw.githubusercontent.com/ColinHDev/pmmp-plugin-build-script/main/build-plugin.php 38 | 39 | - id: get-manifest 40 | run: | 41 | echo "NAME=$(grep '^name:' plugin.yml | cut -d' ' -f2- | xargs)" >> $GITHUB_OUTPUT 42 | echo "PRERELEASE=$(grep '^version:' plugin.yml | cut -d' ' -f2- | xargs | grep -E 'alpha|beta|pre' && echo 'true')" >> $GITHUB_OUTPUT 43 | echo "API=$(grep '^api:' plugin.yml | cut -d' ' -f2- | xargs)" >> $GITHUB_OUTPUT 44 | sed -i '/src-namespace-prefix/d' plugin.yml 45 | sed -i "s/version: .*/version: ${{ github.ref_name }}/g" plugin.yml 46 | 47 | - name: Build plugin phar 48 | run: php build-plugin.php 49 | 50 | - name: Upload plugin phar as workflow artifact 51 | uses: actions/upload-artifact@v3 52 | with: 53 | name: release_artifacts 54 | path: | 55 | ${{ github.workspace }}/${{ steps.get-manifest.outputs.NAME }}.phar 56 | 57 | - name: Rename plugin phar for the development release 58 | run: mv "${{ github.workspace }}/${{ steps.get-manifest.outputs.NAME }}.phar" "${{ github.workspace }}/${{ steps.get-manifest.outputs.NAME }}_dev-${{ github.ref_name }}.phar" 59 | 60 | - name: Create or update development release 61 | uses: ncipollo/release-action@v1 62 | with: 63 | artifacts: "${{ github.workspace }}/${{ steps.get-manifest.outputs.NAME }}_dev-${{ github.ref_name }}.phar" 64 | token: ${{ secrets.GITHUB_TOKEN }} 65 | prerelease: true 66 | allowUpdates: true 67 | tag: development-release 68 | name: "Development Plugin Builds" 69 | body: | 70 | This release contains the latest development builds of the plugin for each branch. 71 | They are automatically updated when new commits are pushed to the branch. 72 | 73 | The plugin phar name follows the format: **{plugin name}_dev-{branch name}.phar** 74 | 75 | **DO NOT USE THESE BUILDS ON A PRODUCTION SERVER** -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/provider/CapitalEconomyProvider.php: -------------------------------------------------------------------------------- 1 | getPluginManager()->getPlugin("Capital") === null) { 30 | throw new \RuntimeException("CapitalEconomyProvider requires the plugin \"Capital\" to be installed."); 31 | } 32 | 33 | $currency = ResourceManager::getInstance()->getConfig()->getNested("economy.capital.currency", "$"); 34 | assert(is_string($currency)); 35 | $this->currency = $currency; 36 | 37 | Capital::api( 38 | self::CAPITAL_API_VERSION, 39 | function(Capital $api) { 40 | $selector = ResourceManager::getInstance()->getConfig()->getNested("economy.capital.selector", []); 41 | assert(is_array($selector)); 42 | $this->selector = $api->completeConfig($selector); 43 | return null; 44 | } 45 | ); 46 | } 47 | 48 | public function getCurrency() : string { 49 | return $this->currency; 50 | } 51 | 52 | public function parseMoneyToString(float $money) : string { 53 | return (string) floor($money); 54 | } 55 | 56 | public function removeMoney(Player $player, float $money, string $reason, callable $onSuccess, callable $onError) : void { 57 | $intMoney = (int) floor($money); 58 | Capital::api( 59 | self::CAPITAL_API_VERSION, 60 | function(Capital $api) use($player, $intMoney, $reason, $onSuccess, $onError) : \Generator { 61 | try { 62 | yield from $api->takeMoney( 63 | "CPlot", 64 | $player, 65 | $this->selector, 66 | $intMoney, 67 | new LabelSet(["reason" => $reason]), 68 | ); 69 | $onSuccess(); 70 | } catch(CapitalException $capitalException) { 71 | $onError( 72 | new EconomyException( 73 | match ($capitalException->getCode()) { 74 | CapitalException::SOURCE_UNDERFLOW => EconomyException::SOURCE_UNDERFLOW, 75 | CapitalException::NO_SUCH_ACCOUNT => EconomyException::SOURCE_NON_EXISTENT, 76 | CapitalException::EVENT_CANCELLED => EconomyException::EVENT_CANCELLED, 77 | default => EconomyException::UNKNOWN 78 | }, 79 | $capitalException 80 | ) 81 | ); 82 | } 83 | } 84 | ); 85 | } 86 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/listener/ChunkPopulateListener.php: -------------------------------------------------------------------------------- 1 | getWorld(); 26 | /** @phpstan-var bool $isPlotWorld */ 27 | $isPlotWorld = yield from Await::promise( 28 | fn(Closure $resolve, Closure $reject) => $this->getAPI()->isPlotWorld($world)->onCompletion($resolve, $reject) 29 | ); 30 | if ($isPlotWorld !== true) { 31 | return; 32 | } 33 | $file = "worlds" . DIRECTORY_SEPARATOR . $world->getFolderName() . DIRECTORY_SEPARATOR . World::chunkHash($event->getChunkX(), $event->getChunkZ()) . ".cplot_tile_entities"; 34 | if (!(file_exists($file))) { 35 | return; 36 | } 37 | $contents = file_get_contents($file); 38 | if ($contents === false) { 39 | return; 40 | } 41 | $decompressed = zlib_decode($contents); 42 | if ($decompressed === false) { 43 | return; 44 | } 45 | 46 | try { 47 | $tiles = (new BigEndianNbtSerializer())->readMultiple($decompressed); 48 | } catch (NbtDataException) { 49 | return; 50 | } 51 | $tileFactory = TileFactory::getInstance(); 52 | foreach ($tiles as $coordinateHash => $tileTreeRoot) { 53 | try { 54 | $tileNBT = $tileTreeRoot->mustGetCompoundTag(); 55 | $tile = $tileFactory->createFromData($world, $tileNBT); 56 | } catch(NbtDataException|SavedDataLoadingException $e) { 57 | $world->getLogger()->error("Bad tile entity data at list position $coordinateHash: " . $e->getMessage()); 58 | $world->getLogger()->logException($e); 59 | continue; 60 | } 61 | if ($tile === null) { 62 | $world->getLogger()->warning("Deleted unknown tile entity type " . $tileNBT->getString("id", "")); 63 | } else if (!$world->isChunkLoaded($tile->getPosition()->getFloorX() >> Chunk::COORD_BIT_SIZE, $tile->getPosition()->getFloorZ() >> Chunk::COORD_BIT_SIZE)) { 64 | $world->getLogger()->error("Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); 65 | } else if ($world->getTile($tilePosition = $tile->getPosition()) !== null) { 66 | $world->getLogger()->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); 67 | } else { 68 | $world->addTile($tile); 69 | } 70 | } 71 | } 72 | ); 73 | } 74 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/utils/promise/PromiseResolver.php: -------------------------------------------------------------------------------- 1 | */ 16 | private PromiseSharedData $shared; 17 | /** @phpstan-var Promise */ 18 | private Promise $promise; 19 | 20 | public function __construct() { 21 | $this->shared = new PromiseSharedData(); 22 | $this->promise = new Promise($this->shared); 23 | } 24 | 25 | /** 26 | * Resolves the promise with the given value. 27 | * @param mixed $value The value to resolve the promise with. 28 | * @phpstan-param TValue $value 29 | * @throws LogicException when the promise has already been resolved or rejected 30 | */ 31 | public function resolve(mixed $value) : void { 32 | if ($this->promise->isResolved()) { 33 | throw new LogicException("Promise has already been " . ($this->shared->result === null ? "rejected" : "resolved")); 34 | } 35 | $this->shared->result = $value; 36 | foreach($this->shared->onSuccess as $closure) { 37 | $closure($value); 38 | } 39 | $this->shared->onSuccess = []; 40 | $this->shared->onError = []; 41 | } 42 | 43 | /** 44 | * Resolves the promise with the given value. Unlike {@see PromiseResolver::resolve()}, this method does not throw 45 | * an exception if the promise has already been resolved or rejected. 46 | * @param mixed $value The value to resolve the promise with. 47 | * @phpstan-param TValue $value 48 | * Returns true if the promise was successfully resolved, or false if it was already resolved or rejected. 49 | * @return bool 50 | */ 51 | public function resolveSilent(mixed $value) : bool { 52 | try { 53 | $this->resolve($value); 54 | } catch (LogicException) { 55 | return false; 56 | } 57 | return true; 58 | } 59 | 60 | /** 61 | * Rejects the promise with the given exception. 62 | * @param Throwable $error The exception to reject the promise with. 63 | * @throws LogicException when the promise has already been resolved or rejected 64 | */ 65 | public function reject(Throwable $error) : void { 66 | if ($this->promise->isResolved()) { 67 | throw new LogicException("Promise has already been " . ($this->shared->result === null ? "rejected" : "resolved")); 68 | } 69 | $this->shared->error = $error; 70 | foreach($this->shared->onError as $closure) { 71 | $closure($error); 72 | } 73 | $this->shared->onSuccess = []; 74 | $this->shared->onError = []; 75 | } 76 | 77 | /** 78 | * Rejects the promise with the given exception. Unlike {@see PromiseResolver::reject()}, this method does not throw 79 | * an exception if the promise has already been resolved or rejected. 80 | * @param Throwable $error The exception to reject the promise with. 81 | * Returns true if the promise was successfully rejected, or false if it was already resolved or rejected. 82 | * @return bool 83 | */ 84 | public function rejectSilent(Throwable $error) : bool { 85 | try { 86 | $this->reject($error); 87 | } catch (LogicException) { 88 | return false; 89 | } 90 | return true; 91 | } 92 | 93 | /** 94 | * @phpstan-return Promise 95 | */ 96 | public function getPromise() : Promise { 97 | return $this->promise; 98 | } 99 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/event/PlotWorldGenerateAsyncEvent.php: -------------------------------------------------------------------------------- 1 | worldName = $worldName; 33 | $this->worldSettings = $worldSettings; 34 | $this->worldCreationOptions = $worldCreationOptions; 35 | } 36 | 37 | /** 38 | * Returns the name under which the plot world will be generated. 39 | */ 40 | public function getWorldName() : string { 41 | return $this->worldName; 42 | } 43 | 44 | /** 45 | * Sets the name under which the plot world will be generated. 46 | */ 47 | public function setWorldName(string $worldName) : void { 48 | $this->worldName = $worldName; 49 | } 50 | 51 | /** 52 | * Returns CPlot's {@see WorldSettings} which's contents will be saved to the database. 53 | */ 54 | public function getWorldSettings() : WorldSettings { 55 | return $this->worldSettings; 56 | } 57 | 58 | /** 59 | * Sets CPlot's {@see WorldSettings} which's contents will be saved to the database. 60 | */ 61 | public function setWorldSettings(WorldSettings $worldSettings) : void { 62 | $this->worldSettings = $worldSettings; 63 | } 64 | 65 | /** 66 | * Returns PocketMine-MP's {@see WorldCreationOptions} which's contents will be passed to the {@see Generator} and 67 | * used to generate the world. 68 | */ 69 | public function getWorldCreationOptions() : WorldCreationOptions { 70 | return $this->worldCreationOptions; 71 | } 72 | 73 | /** 74 | * Sets PocketMine-MP's {@see WorldCreationOptions} which's contents will be passed to the {@see Generator} and 75 | * used to generate the world. 76 | */ 77 | public function setWorldCreationOptions(WorldCreationOptions $worldCreationOptions) : void { 78 | $this->worldCreationOptions = $worldCreationOptions; 79 | } 80 | 81 | /** 82 | * @phpstan-return \Generator 83 | */ 84 | public static function create(string $worldName, WorldSettings $worldSettings, WorldCreationOptions $options) : \Generator { 85 | $event = yield from Await::promise( 86 | static function ($onSuccess, $onError) use ($worldName, $worldSettings, $options) : void { 87 | $event = new self($worldName, $worldSettings, $options); 88 | $event->setCallback($onSuccess); 89 | $event->call(); 90 | } 91 | ); 92 | assert($event instanceof self); 93 | return $event; 94 | } 95 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/plots/flags/Flags.php: -------------------------------------------------------------------------------- 1 | $flag 49 | */ 50 | protected static function register(string $flagID, Flag $flag) : void{ 51 | self::_registryRegister($flagID, $flag); 52 | } 53 | 54 | protected static function setup() : void { 55 | $flagManager = FlagManager::getInstance(); 56 | self::register(FlagIDs::FLAG_BREAK, $flagManager->getFlagByID(FlagIDs::FLAG_BREAK)); 57 | self::register(FlagIDs::FLAG_BURNING, $flagManager->getFlagByID(FlagIDs::FLAG_BURNING)); 58 | self::register(FlagIDs::FLAG_EXPLOSION, $flagManager->getFlagByID(FlagIDs::FLAG_EXPLOSION)); 59 | self::register(FlagIDs::FLAG_FAREWELL, $flagManager->getFlagByID(FlagIDs::FLAG_FAREWELL)); 60 | self::register(FlagIDs::FLAG_FLOWING, $flagManager->getFlagByID(FlagIDs::FLAG_FLOWING)); 61 | self::register(FlagIDs::FLAG_GREETING, $flagManager->getFlagByID(FlagIDs::FLAG_GREETING)); 62 | self::register(FlagIDs::FLAG_GROWING, $flagManager->getFlagByID(FlagIDs::FLAG_GROWING)); 63 | self::register(FlagIDs::FLAG_ITEM_DROP, $flagManager->getFlagByID(FlagIDs::FLAG_ITEM_DROP)); 64 | self::register(FlagIDs::FLAG_ITEM_PICKUP, $flagManager->getFlagByID(FlagIDs::FLAG_ITEM_PICKUP)); 65 | self::register(FlagIDs::FLAG_PLACE, $flagManager->getFlagByID(FlagIDs::FLAG_PLACE)); 66 | self::register(FlagIDs::FLAG_PLAYER_INTERACT, $flagManager->getFlagByID(FlagIDs::FLAG_PLAYER_INTERACT)); 67 | self::register(FlagIDs::FLAG_PVE, $flagManager->getFlagByID(FlagIDs::FLAG_PVE)); 68 | self::register(FlagIDs::FLAG_PVP, $flagManager->getFlagByID(FlagIDs::FLAG_PVP)); 69 | self::register(FlagIDs::FLAG_SPAWN, $flagManager->getFlagByID(FlagIDs::FLAG_SPAWN)); 70 | self::register(FlagIDs::FLAG_USE, $flagManager->getFlagByID(FlagIDs::FLAG_USE)); 71 | } 72 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/InfoSubcommand.php: -------------------------------------------------------------------------------- 1 | getPosition(); 26 | $world = $position->getWorld(); 27 | if (!((yield DataProvider::getInstance()->awaitWorld($world->getFolderName())) instanceof WorldSettings)) { 28 | self::sendMessage($sender, ["prefix", "info.noPlotWorld"]); 29 | return; 30 | } 31 | 32 | $plot = yield Plot::awaitFromPosition($position); 33 | if (!($plot instanceof Plot)) { 34 | self::sendMessage($sender, ["prefix", "info.noPlot"]); 35 | return; 36 | } 37 | 38 | $owners = []; 39 | foreach($plot->getPlotOwners() as $plotPlayer) { 40 | $owners[] = self::translateForCommandSender($sender, ["format.list.player" => $plotPlayer->getPlayerData()->getPlayerName() ?? "Unknown"]); 41 | } 42 | $trusted = []; 43 | foreach($plot->getPlotTrusted() as $plotPlayer) { 44 | $trusted[] = self::translateForCommandSender($sender, ["format.list.player" => $plotPlayer->getPlayerData()->getPlayerName() ?? "Unknown"]); 45 | } 46 | $helpers = []; 47 | foreach($plot->getPlotHelpers() as $plotPlayer) { 48 | $helpers[] = self::translateForCommandSender($sender, ["format.list.player" => $plotPlayer->getPlayerData()->getPlayerName() ?? "Unknown"]); 49 | } 50 | $denied = []; 51 | foreach($plot->getPlotDenied() as $plotPlayer) { 52 | $denied[] = self::translateForCommandSender($sender, ["format.list.player" => $plotPlayer->getPlayerData()->getPlayerName() ?? "Unknown"]); 53 | } 54 | 55 | $flags = []; 56 | foreach($plot->getFlags() as $flagID => $flag) { 57 | if (!$flag instanceof InternalFlag) { 58 | $flags[] = self::translateForCommandSender($sender, ["format.list.attributeWithValue" => [$flagID, $flag->toReadableString()]]); 59 | } 60 | } 61 | 62 | $playerSeparator = self::translateForCommandSender($sender, "format.list.player.separator"); 63 | 64 | self::sendMessage( 65 | $sender, 66 | [ 67 | "prefix", 68 | "info.success" => [ 69 | $plot->getWorldName(), 70 | $plot->getX(), 71 | $plot->getZ(), 72 | implode($playerSeparator, $owners), 73 | $plot->getAlias() ?? "---", 74 | BiomeSubcommand::getBiomeNameByID($world->getBiomeId($position->getFloorX(), $position->getFloorY(), $position->getFloorZ())), 75 | implode($playerSeparator, $trusted), 76 | implode($playerSeparator, $helpers), 77 | implode($playerSeparator, $denied), 78 | implode(self::translateForCommandSender($sender, "format.list.attributeWithValue.separator"), $flags), 79 | ] 80 | ] 81 | ); 82 | } 83 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/commands/subcommands/WallSubcommand.php: -------------------------------------------------------------------------------- 1 | $args[0]]); 41 | return; 42 | } 43 | 44 | $worldSettings = yield DataProvider::getInstance()->awaitWorld($sender->getWorld()->getFolderName()); 45 | if (!($worldSettings instanceof WorldSettings)) { 46 | self::sendMessage($sender, ["prefix", "wall.noPlotWorld"]); 47 | return; 48 | } 49 | 50 | $plot = yield Plot::awaitFromPosition($sender->getPosition()); 51 | if (!($plot instanceof Plot)) { 52 | self::sendMessage($sender, ["prefix", "wall.noPlot"]); 53 | return; 54 | } 55 | if (!$sender->hasPermission("cplot.admin.wall")) { 56 | if (!$plot->hasPlotOwner()) { 57 | self::sendMessage($sender, ["prefix", "wall.noPlotOwner"]); 58 | return; 59 | } 60 | if (!$plot->isPlotOwner($sender)) { 61 | self::sendMessage($sender, ["prefix", "wall.notPlotOwner"]); 62 | return; 63 | } 64 | } 65 | 66 | $lock = new WallChangeLockID(); 67 | if (!PlotLockManager::getInstance()->lockPlotsSilent($lock, $plot)) { 68 | self::sendMessage($sender, ["prefix", "wall.plotLocked"]); 69 | return; 70 | } 71 | 72 | self::sendMessage($sender, ["prefix", "wall.start"]); 73 | /** @phpstan-var PlotWallChangeAsyncTask $task */ 74 | $task = yield from Await::promise( 75 | static fn($resolve) => $plot->setWallBlock($block, $resolve) 76 | ); 77 | $world = $sender->getWorld(); 78 | $plotCount = count($plot->getMergePlots()) + 1; 79 | $plots = array_map( 80 | static function (BasePlot $plot) : string { 81 | return $plot->toSmallString(); 82 | }, 83 | array_merge([$plot], $plot->getMergePlots()) 84 | ); 85 | $elapsedTimeString = $task->getElapsedTimeString(); 86 | Server::getInstance()->getLogger()->debug( 87 | "Changing plot wall to " . $block->getName() . " in world " . $world->getDisplayName() . " (folder: " . $world->getFolderName() . ") took " . $elapsedTimeString . " (" . $task->getElapsedTime() . "ms) for player " . $sender->getUniqueId()->getBytes() . " (" . $sender->getName() . ") for " . $plotCount . " plot" . ($plotCount > 1 ? "s" : "") . ": [" . implode(", ", $plots) . "]." 88 | ); 89 | self::sendMessage($sender, ["prefix", "wall.finish" => [$elapsedTimeString, $block->getName()]]); 90 | PlotLockManager::getInstance()->unlockPlots($lock, $plot); 91 | } 92 | } -------------------------------------------------------------------------------- /src/ColinHDev/CPlot/utils/promise/Promise.php: -------------------------------------------------------------------------------- 1 | $shared 24 | */ 25 | public function __construct(private PromiseSharedData $shared) {} 26 | 27 | /** 28 | * Provide callbacks to be called when the promise is resolved or rejected. 29 | * @phpstan-param (Closure(TValue): void)|(Closure(): void) $onSuccess 30 | * @phpstan-param (Closure(Throwable): void)|(Closure(): void) $onFailure 31 | */ 32 | public function onCompletion(Closure $onSuccess, Closure $onFailure) : void { 33 | if ($this->shared->result !== null) { 34 | $onSuccess($this->shared->result); 35 | } else if ($this->shared->error !== null) { 36 | $onFailure($this->shared->error); 37 | } else { 38 | $this->shared->onSuccess[spl_object_id($onSuccess)] = $onSuccess; 39 | $this->shared->onError[spl_object_id($onFailure)] = $onFailure; 40 | } 41 | } 42 | 43 | /** 44 | * Returns true if the promise has been resolved or rejected. 45 | */ 46 | public function isResolved() : bool { 47 | return $this->shared->result !== null || $this->shared->error !== null; 48 | } 49 | 50 | /** 51 | * Returns the result of the promise. 52 | * @phpstan-return TValue|null 53 | */ 54 | public function getResult() : mixed { 55 | return $this->shared->result; 56 | } 57 | 58 | /** 59 | * Returns the exception that was thrown when the promise was rejected. 60 | */ 61 | public function getError() : ?Throwable { 62 | return $this->shared->error; 63 | } 64 | 65 | /** 66 | * Utility method to create a promise that resolves once all the given promises have resolved. 67 | * 68 | * @param Promise ...$promises All the promises to wait for. 69 | * @phpstan-template UValue of mixed 70 | * @phpstan-param Promise ...$promises 71 | * 72 | * Returns a {@see Promise} that resolves with an array of all the results of the given promises. The results in the 73 | * array are in the same order in which the promises were given to the method. 74 | * If any of the given promises is rejected, the returned promise is rejected with the same exception. 75 | * @return Promise 76 | * @phpstan-return Promise> 77 | */ 78 | public static function all(Promise ...$promises) : Promise { 79 | /** @phpstan-var PromiseResolver> $resolver */ 80 | $resolver = new PromiseResolver(); 81 | /** @phpstan-var non-empty-array $results */ 82 | $results = []; 83 | foreach($promises as $key => $promise) { 84 | $promise->onCompletion( 85 | function(mixed $value) use($promises, $key, &$results, $resolver) : void { 86 | $results[$key] = $value; 87 | if (count($results) === count($promises)) { 88 | $resolver->resolveSilent($results); 89 | } 90 | }, 91 | function(Throwable $error) use($resolver) : void { 92 | $resolver->rejectSilent($error); 93 | } 94 | ); 95 | } 96 | return $resolver->getPromise(); 97 | } 98 | } --------------------------------------------------------------------------------