diff --git a/.poggit.yml b/.poggit.yml index 1be598b0..56b32546 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -4,6 +4,10 @@ projects: icon: "icon.png" path: "" libs: + - src: poggit/libasynql/libasynql + version: ^3.3.0 + - src: SOF3/await-generator/await-generator + version: ^3.1.1 - src: dktapps-pm-pl/pmforms/pmforms version: ^2.0.0 lint: false @@ -15,4 +19,4 @@ projects: - .gitignore - CONTRIBUTING.md - SECURITY.md -... \ No newline at end of file +... diff --git a/plugin.yml b/plugin.yml index 3c302b4e..464b0151 100644 --- a/plugin.yml +++ b/plugin.yml @@ -10,10 +10,11 @@ authors: description: "Plots and Protection Plugin for PocketMine-MP Servers" load: STARTUP softdepend: -- EconomyAPI +- Capital - DEVirion -- WorldStyler - EasyCommandAutofill +- EconomyAPI +- WorldStyler permissions: myplot.command: default: true diff --git a/resources/config.yml b/resources/config.yml index 098e7dbb..db635f29 100644 --- a/resources/config.yml +++ b/resources/config.yml @@ -37,17 +37,25 @@ Custom Messages: false UI Forms: true # The data provider where plot data is stored. -# Current providers are: sqlite, mysql, json, and yaml. -DataProvider: sqlite - -# contains settings for mysql provider to use when selected -MySQLSettings: - Host: 127.0.0.1 - Port: 3306 - Username: default - Password: password - DatabaseName: MyPlot - ShutdownOnFailure: false +Database: + # The database type. "sqlite" and "mysql" are supported. + type: sqlite + + # Edit these settings only if you choose "sqlite". + sqlite: + # The file name of the database in the plugin data folder. + # You can also put an absolute path here. + file: plots.db + # Edit these settings only if you choose "mysql". + mysql: + host: 127.0.0.1 + # Avoid using the "root" user for security reasons. + username: default + password: password + schema: myplot + # The maximum number of simultaneous SQL queries + # Recommended: 1 for sqlite, 2 for MySQL. You may want to further increase this value if your MySQL connection is very slow. + worker-limit: 1 # Use an economy with MyPlot. This will allow for plot pricing such as claiming, clearing, etc. # Currently supported economy plugins: Economy$ @@ -56,7 +64,7 @@ UseEconomy: false # Amount of plots to be cached. # Increasing this number will improve performance, but also increase memory usage. -PlotCacheSize: 256 +PlotCacheSize: 2500 # When a player enters a plot, a popup with basic info will be shown ShowPlotPopup: true @@ -121,12 +129,12 @@ DefaultWorld: RoadWidth: 7 # The block that the road is made of (Default is Oak Planks) - RoadBlock: '5:0' + RoadBlock: oak planks # The block that plot walls are made of (Default is Stone Slabs) - WallBlock: '44:0' + WallBlock: stone slab # The block used as the plot floor (Default is Grass) - PlotFloorBlock: '2:0' + PlotFloorBlock: grass # The block that fills the rest of the plot (Default is Dirt) - PlotFillBlock: '3:0' + PlotFillBlock: dirt # The block at the bottom (Default is Bedrock) - BottomBlock: '7:0' + BottomBlock: bedrock diff --git a/resources/eng.ini b/resources/eng.ini index 491acc77..8ed76f6a 100644 --- a/resources/eng.ini +++ b/resources/eng.ini @@ -14,6 +14,7 @@ command.name=plot command.alias=p command.desc=Claim and manage your plots command.usage=/p [help] +command.usable=You cannot use this command right now command.unknown=Unknown command. Try /p help for a list of commands subcommand.usage=Usage: {%0} @@ -282,8 +283,7 @@ clone.wrongid="The plot id should be in the format X;Z" clone.nomoney=You do not have enough money to clone this plot clone.success=Plot {%0} has been successfully cloned to plot {%1} clone.form=Clone -clone.formlabel1=Origin Plot Location -clone.formlabel2=Clone Plot Location +clone.formcoordslabel=Clone Plot Location clone.formxcoord=Plot X Coordinate clone.formzcoord=Plot Z Coordinate clone.formworld=Plot World Name diff --git a/resources/langtemplate.ini b/resources/langtemplate.ini index 5312c264..2f78159b 100644 --- a/resources/langtemplate.ini +++ b/resources/langtemplate.ini @@ -14,6 +14,7 @@ command.name=plot command.alias=p command.desc= command.usage=/p [help] +command.usable= command.unknown= subcommand.usage= @@ -269,8 +270,7 @@ clone.wrongid= clone.nomoney= clone.success= clone.form= -clone.formlabel1= -clone.formlabel2= +clone.formcoordslabel= clone.formxcoord= clone.formzcoord= clone.formworld= diff --git a/resources/mysql.sql b/resources/mysql.sql new file mode 100644 index 00000000..64796fbe --- /dev/null +++ b/resources/mysql.sql @@ -0,0 +1,223 @@ +-- #!mysql +-- #{myplot +-- # {init +-- # {plots +CREATE TABLE IF NOT EXISTS plotsV2 +( + level TEXT, + X INT, + Z INT, + name TEXT, + owner TEXT, + helpers TEXT, + denied TEXT, + biome TEXT, + pvp INT, + price FLOAT, + PRIMARY KEY (level, X, Z) +); +-- # } +-- # {mergedPlots +CREATE TABLE IF NOT EXISTS mergedPlotsV2 +( + level TEXT, + originX INT, + originZ INT, + mergedX INT, + mergedZ INT, + PRIMARY KEY (level, originX, originZ, mergedX, mergedZ) +); +-- # } +-- # } +-- # {test +-- # {table +-- # :tableName string +SELECT COUNT(*) AS tables +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = :tableName; +-- # } +-- # } +-- # {add +-- # {plot +-- # :level string +-- # :X int +-- # :Z int +-- # :name string +-- # :owner string +-- # :helpers string +-- # :denied string +-- # :biome string +-- # :pvp bool false +-- # :price float +INSERT INTO plotsV2 (level, X, Z, name, owner, helpers, denied, biome, pvp, price) +VALUES (:level, :X, :Z, :name, :owner, :helpers, :denied, :biome, :pvp, :price) +ON DUPLICATE KEY UPDATE name = VALUES(:name), + owner = VALUES(:owner), + helpers = VALUES(:helpers), + denied = VALUES(:denied), + biome = VALUES(:biome), + pvp = VALUES(:pvp), + price = VALUES(:price); +-- # } +-- # {merge +-- # :level string +-- # :originX int +-- # :originZ int +-- # :mergedX int +-- # :mergedZ int +INSERT IGNORE INTO mergedPlotsV2 (`level`, `originX`, `originZ`, `mergedX`, `mergedZ`) +VALUES (:level, :originX, :originZ, :mergedX, :mergedZ); +-- # } +-- # } +-- # {get +-- # {plot +-- # {by-xz +-- # :level string +-- # :X int +-- # :Z int +SELECT name, owner, helpers, denied, biome, pvp, price +FROM plotsV2 +WHERE level = :level + AND X = :x + AND Z = :z; +-- # } +-- # } +-- # {all-plots +-- # {by-owner +-- # :owner string +SELECT level, X, Z +FROM plotsV2 +WHERE owner = :owner; +-- # } +-- # } +-- # {all-plots +-- # {by-owner-and-level +-- # :owner string +-- # :level string +SELECT level, X, Z +FROM plotsV2 +WHERE owner = :owner + AND level = :level; +-- # } +-- # } +-- # {highest-existing +-- # {by-interval +-- # :level string +-- # :number int +SELECT X, Z +FROM plotsV2 +WHERE (level = :level AND ((abs(X) = :number AND abs(Z) <= :number) OR (abs(Z) = :number AND abs(X) <= :number))); +-- # } +-- # } +-- # {merge-plots +-- # {by-origin +-- # :level string +-- # :originX int +-- # :originZ int +SELECT plotsV2.level, + X, + Z, + name, + owner, + helpers, + denied, + biome, + pvp, + price +FROM plotsV2 + LEFT JOIN mergedPlotsV2 + ON mergedPlotsV2.level = plotsV2.level + AND mergedX = X + AND mergedZ = Z +WHERE mergedPlotsV2.level = :level + AND originX = :originX + AND originZ = :originZ; +-- # } +-- # } +-- # {merge-plots +-- # {by-merged +-- # :level string +-- # :mergedX int +-- # :mergedZ int +SELECT plotsV2.level, + X, + Z, + name, + owner, + helpers, + denied, + biome, + pvp, + price +FROM plotsV2 + LEFT JOIN mergedPlotsV2 + ON mergedPlotsV2.level = plotsV2.level + AND mergedX = X + AND mergedZ = Z +WHERE mergedPlotsV2.level = :level + AND originX = ( + SELECT originX + FROM mergedPlotsV2 + WHERE mergedX = :mergedX + AND mergedZ = :mergedZ + AND mergedPlotsV2.level = :level +) + AND originZ = ( + SELECT originZ + FROM mergedPlotsV2 + WHERE mergedX = :mergedX + AND mergedZ = :mergedZ + AND mergedPlotsV2.level = :level +); +-- # } +-- # } +-- # } +-- # {remove +-- # {plot +-- # {by-xz +-- # :level string +-- # :x int +-- # :z int +DELETE +FROM plotsV2 +WHERE level = :level + AND X = :X + AND Z = :Z; +-- # } +-- # } +-- # {merge +-- # {by-xz +-- # :level string +-- # :x int +-- # :z int +-- # :pvp bool false +-- # :price float +UPDATE plotsV2 +SET name = '', + owner = '', + helpers = '', + denied = '', + pvp = :pvp, + price = :price +WHERE level = :level + AND X = :x + AND Z = :z; +-- # } +-- # } +-- # {merge-entry +-- # :level string +-- # :originX int +-- # :originZ int +-- # :mergedX int +-- # :mergedZ int +DELETE +FROM mergedPlotsV2 +WHERE level = :level + AND originX = :originX + AND originZ = :originZ + AND mergedX = :mergedX + AND mergedZ = :mergedZ; +-- # } +-- # } +-- #} \ No newline at end of file diff --git a/resources/sqlite.sql b/resources/sqlite.sql new file mode 100644 index 00000000..6ba8e32f --- /dev/null +++ b/resources/sqlite.sql @@ -0,0 +1,220 @@ +-- #!mysql +-- #{myplot +-- # {init +-- # {plots +CREATE TABLE IF NOT EXISTS plotsV2 +( + level TEXT, + X INTEGER, + Z INTEGER, + name TEXT, + owner TEXT, + helpers TEXT, + denied TEXT, + biome TEXT, + pvp INTEGER, + price FLOAT, + PRIMARY KEY (level, X, Z) +); +-- # } +-- # {mergedPlots +CREATE TABLE IF NOT EXISTS mergedPlotsV2 +( + level TEXT, + originX INTEGER, + originZ INTEGER, + mergedX INTEGER, + mergedZ INTEGER, + PRIMARY KEY (level, originX, originZ, mergedX, mergedZ) +); +-- # } +-- # } +-- # {test +-- # {table +-- # :tableName string +SELECT COUNT(name) AS tables +FROM sqlite_master +WHERE type = 'table' + AND name = :tableName; +-- # } +-- # } +-- # {add +-- # {plot +-- # :level string +-- # :X int +-- # :Z int +-- # :name string +-- # :owner string +-- # :helpers string +-- # :denied string +-- # :biome string +-- # :pvp bool false +-- # :price float +INSERT OR +REPLACE +INTO plotsV2 (level, X, Z, name, owner, helpers, denied, biome, pvp, price) +VALUES (:level, :X, :Z, :name, :owner, :helpers, :denied, :biome, :pvp, :price); +-- # } +-- # {merge +-- # :level string +-- # :originX int +-- # :originZ int +-- # :mergedX int +-- # :mergedZ int +INSERT OR +REPLACE +INTO mergedPlotsV2 (level, originX, originZ, mergedX, mergedZ) +VALUES (:level, :originX, :originZ, :mergedX, :mergedZ); +-- # } +-- # } +-- # {get +-- # {plot +-- # {by-xz +-- # :level string +-- # :X int +-- # :Z int +SELECT name, owner, helpers, denied, biome, pvp, price +FROM plotsV2 +WHERE level = :level + AND X = :X + AND Z = :Z; +-- # } +-- # } +-- # {all-plots +-- # {by-owner +-- # :owner string +SELECT level, X, Z +FROM plotsV2 +WHERE owner = :owner; +-- # } +-- # } +-- # {all-plots +-- # {by-owner-and-level +-- # :owner string +-- # :level string +SELECT level, X, Z +FROM plotsV2 +WHERE owner = :owner + AND level = :level; +-- # } +-- # } +-- # {highest-existing +-- # {by-interval +-- # :level string +-- # :number int +SELECT X, Z +FROM plotsV2 +WHERE (level = :level AND ((abs(X) = :number AND abs(Z) <= :number) OR (abs(Z) = :number AND abs(X) <= :number))); +-- # } +-- # } +-- # {merge-plots +-- # {by-origin +-- # :level string +-- # :originX int +-- # :originZ int +SELECT plotsV2.level, + X, + Z, + name, + owner, + helpers, + denied, + biome, + pvp, + price +FROM plotsV2 + LEFT JOIN mergedPlotsV2 + ON mergedPlotsV2.level = plotsV2.level + AND mergedX = X + AND mergedZ = Z +WHERE mergedPlotsV2.level = :level + AND originX = :originX + AND originZ = :originZ; +-- # } +-- # } +-- # {merge-plots +-- # {by-merged +-- # :level string +-- # :mergedX int +-- # :mergedZ int +SELECT plotsV2.level, + X, + Z, + name, + owner, + helpers, + denied, + biome, + pvp, + price +FROM plotsV2 + LEFT JOIN mergedPlotsV2 + ON mergedPlotsV2.level = plotsV2.level + AND mergedX = X + AND mergedZ = Z +WHERE mergedPlotsV2.level = :level + AND originX = ( + SELECT originX + FROM mergedPlotsV2 + WHERE mergedX = :mergedX + AND mergedZ = :mergedZ + AND mergedPlotsV2.level = :level +) + AND originZ = ( + SELECT originZ + FROM mergedPlotsV2 + WHERE mergedX = :mergedX + AND mergedZ = :mergedZ + AND mergedPlotsV2.level = :level +); +-- # } +-- # } +-- # } +-- # {remove +-- # {plot +-- # {by-xz +-- # :level string +-- # :X int +-- # :Z int +DELETE +FROM plotsV2 +WHERE level = :level + AND X = :X + AND Z = :Z; +-- # } +-- # } +-- # {merge +-- # {by-xz +-- # :level string +-- # :X int +-- # :Z int +-- # :pvp bool false +-- # :price float +UPDATE plotsV2 +SET name = '', + owner = '', + helpers = '', + denied = '', + pvp = :pvp, + price = :price +WHERE level = :level + AND X = :X + AND Z = :Z; +-- # } +-- # } +-- # {merge-entry +-- # :level string +-- # :originX int +-- # :originZ int +-- # :mergedX int +-- # :mergedZ int +DELETE +FROM mergedPlotsV2 +WHERE level = :level + AND originX = :originX + AND originZ = :originZ + AND mergedX = :mergedX + AND mergedZ = :mergedZ; +-- # } +-- # } +-- #} \ No newline at end of file diff --git a/src/MyPlot/Commands.php b/src/MyPlot/Commands.php index 43f4a51e..d408568e 100644 --- a/src/MyPlot/Commands.php +++ b/src/MyPlot/Commands.php @@ -24,19 +24,18 @@ use MyPlot\subcommand\ListSubCommand; use MyPlot\subcommand\MergeSubCommand; use MyPlot\subcommand\MiddleSubCommand; +use MyPlot\subcommand\MyPlotSubCommand; use MyPlot\subcommand\NameSubCommand; use MyPlot\subcommand\PvpSubCommand; use MyPlot\subcommand\RemoveHelperSubCommand; use MyPlot\subcommand\ResetSubCommand; use MyPlot\subcommand\SellSubCommand; use MyPlot\subcommand\SetOwnerSubCommand; -use MyPlot\subcommand\SubCommand; use MyPlot\subcommand\UnDenySubCommand; use MyPlot\subcommand\WarpSubCommand; use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; -use pocketmine\network\mcpe\protocol\types\command\CommandData; use pocketmine\network\mcpe\protocol\types\command\CommandEnum; use pocketmine\network\mcpe\protocol\types\command\CommandParameter; use pocketmine\player\Player; @@ -44,162 +43,171 @@ use pocketmine\plugin\PluginOwnedTrait; use pocketmine\utils\TextFormat; -class Commands extends Command implements PluginOwned -{ +class Commands extends Command implements PluginOwned{ use PluginOwnedTrait; - /** @var SubCommand[] $subCommands */ + /** @var MyPlotSubCommand[] $subCommands */ private array $subCommands = []; - /** @var SubCommand[] $aliasSubCommands */ + /** @var MyPlotSubCommand[] $aliasSubCommands */ private array $aliasSubCommands = []; - /** - * Commands constructor. - * - * @param MyPlot $plugin - */ - public function __construct(MyPlot $plugin) { - parent::__construct($plugin->getLanguage()->get("command.name"), $plugin->getLanguage()->get("command.desc"), $plugin->getLanguage()->get("command.usage"), [$plugin->getLanguage()->get("command.alias")]); + public function __construct(MyPlot $owningPlugin, private InternalAPI $internalAPI){ + parent::__construct($owningPlugin->getLanguage()->get("command.name"), $owningPlugin->getLanguage()->get("command.desc"), $owningPlugin->getLanguage()->get("command.usage"), [$owningPlugin->getLanguage()->get("command.alias")]); $this->setPermission("myplot.command"); - $this->owningPlugin = $plugin; - $this->loadSubCommand(new HelpSubCommand($plugin, "help", $this)); - $this->loadSubCommand(new ClaimSubCommand($plugin, "claim")); - $this->loadSubCommand(new GenerateSubCommand($plugin, "generate")); - $this->loadSubCommand(new InfoSubCommand($plugin, "info")); - $this->loadSubCommand(new AddHelperSubCommand($plugin, "addhelper")); - $this->loadSubCommand(new RemoveHelperSubCommand($plugin, "removehelper")); - $this->loadSubCommand(new AutoSubCommand($plugin, "auto")); - $this->loadSubCommand(new ClearSubCommand($plugin, "clear")); - $this->loadSubCommand(new FillSubCommand($plugin, "fill")); - $this->loadSubCommand(new DisposeSubCommand($plugin, "dispose")); - $this->loadSubCommand(new ResetSubCommand($plugin, "reset")); - $this->loadSubCommand(new BiomeSubCommand($plugin, "biome")); - $this->loadSubCommand(new HomeSubCommand($plugin, "home")); - $this->loadSubCommand(new HomesSubCommand($plugin, "homes")); - $this->loadSubCommand(new NameSubCommand($plugin, "name")); - $this->loadSubCommand(new GiveSubCommand($plugin, "give")); - $this->loadSubCommand(new WarpSubCommand($plugin, "warp")); - $this->loadSubCommand(new MiddleSubCommand($plugin, "middle")); - $this->loadSubCommand(new DenyPlayerSubCommand($plugin, "denyplayer")); - $this->loadSubCommand(new UnDenySubCommand($plugin, "undenyplayer")); - $this->loadSubCommand(new SetOwnerSubCommand($plugin, "setowner")); - $this->loadSubCommand(new ListSubCommand($plugin, "list")); - $this->loadSubCommand(new PvpSubCommand($plugin, "pvp")); - $this->loadSubCommand(new KickSubCommand($plugin, "kick")); - $this->loadSubCommand(new MergeSubCommand($plugin, "merge")); - if($plugin->getEconomyProvider() !== null) { - $this->loadSubCommand(new SellSubCommand($plugin, "sell")); - $this->loadSubCommand(new BuySubCommand($plugin, "buy")); + $this->owningPlugin = $owningPlugin; + $this->loadSubCommand(new HelpSubCommand($owningPlugin, $internalAPI, "help", $this)); + $this->loadSubCommand(new ClaimSubCommand($owningPlugin, $internalAPI, "claim")); + $this->loadSubCommand(new GenerateSubCommand($owningPlugin, $internalAPI, "generate")); + $this->loadSubCommand(new InfoSubCommand($owningPlugin, $internalAPI, "info")); + $this->loadSubCommand(new AddHelperSubCommand($owningPlugin, $internalAPI, "addhelper")); + $this->loadSubCommand(new RemoveHelperSubCommand($owningPlugin, $internalAPI, "removehelper")); + $this->loadSubCommand(new AutoSubCommand($owningPlugin, $internalAPI, "auto")); + $this->loadSubCommand(new ClearSubCommand($owningPlugin, $internalAPI, "clear")); + $this->loadSubCommand(new FillSubCommand($owningPlugin, $internalAPI, "fill")); + $this->loadSubCommand(new DisposeSubCommand($owningPlugin, $internalAPI, "dispose")); + $this->loadSubCommand(new ResetSubCommand($owningPlugin, $internalAPI, "reset")); + $this->loadSubCommand(new BiomeSubCommand($owningPlugin, $internalAPI, "biome")); + $this->loadSubCommand(new HomeSubCommand($owningPlugin, $internalAPI, "home")); + $this->loadSubCommand(new HomesSubCommand($owningPlugin, $internalAPI, "homes")); + $this->loadSubCommand(new NameSubCommand($owningPlugin, $internalAPI, "name")); + $this->loadSubCommand(new GiveSubCommand($owningPlugin, $internalAPI, "give")); + $this->loadSubCommand(new WarpSubCommand($owningPlugin, $internalAPI, "warp")); + $this->loadSubCommand(new MiddleSubCommand($owningPlugin, $internalAPI, "middle")); + $this->loadSubCommand(new DenyPlayerSubCommand($owningPlugin, $internalAPI, "denyplayer")); + $this->loadSubCommand(new UnDenySubCommand($owningPlugin, $internalAPI, "undenyplayer")); + $this->loadSubCommand(new SetOwnerSubCommand($owningPlugin, $internalAPI, "setowner")); + $this->loadSubCommand(new ListSubCommand($owningPlugin, $internalAPI, "list")); + $this->loadSubCommand(new PvpSubCommand($owningPlugin, $internalAPI, "pvp")); + $this->loadSubCommand(new KickSubCommand($owningPlugin, $internalAPI, "kick")); + $this->loadSubCommand(new MergeSubCommand($owningPlugin, $internalAPI, "merge")); + if($internalAPI->getEconomyProvider() !== null){ + $this->loadSubCommand(new SellSubCommand($owningPlugin, $internalAPI, "sell")); + $this->loadSubCommand(new BuySubCommand($owningPlugin, $internalAPI, "buy")); } - $styler = $plugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); - if($styler !== null) { - $this->loadSubCommand(new CloneSubCommand($plugin, "clone")); + $styler = $owningPlugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); + if($styler !== null){ + $this->loadSubCommand(new CloneSubCommand($owningPlugin, $internalAPI, "clone")); } - $plugin->getLogger()->debug("Commands Registered to MyPlot"); + $owningPlugin->getLogger()->debug("Commands Registered to MyPlot"); - $autofill = $plugin->getServer()->getPluginManager()->getPlugin("EasyCommandAutofill"); - if($autofill instanceof Main) { + $autofill = $owningPlugin->getServer()->getPluginManager()->getPlugin("EasyCommandAutofill"); + if($autofill instanceof Main and $autofill->getDescription()->getVersion() === '3.0.2'){ $overloads = []; $enumCount = 0; $tree = 0; ksort($this->subCommands, SORT_NATURAL | SORT_FLAG_CASE); - foreach($this->subCommands as $subCommandName => $subCommand) { + foreach($this->subCommands as $subCommandName => $subCommand){ $overloads[$tree][0] = CommandParameter::enum("MyPlotSubCommand", new CommandEnum($subCommandName, [$subCommandName]), CommandParameter::FLAG_FORCE_COLLAPSE_ENUM, false); $usage = $subCommand->getUsage(); $commandString = explode(" ", $usage)[0]; - preg_match_all('/(\s?[<\[]?\s*)([a-zA-Z0-9|]+)\s*:?\s*(string|int|x y z|float|mixed|target|message|text|json|command|boolean|bool)?\s*[>\]]?\s?/iu', $usage, $matches, PREG_PATTERN_ORDER, strlen($commandString)); - $argumentCount = count($matches[0])-1; - for($argNumber = 1; $argNumber <= $argumentCount; ++$argNumber) { - $optional = $matches[1][$argNumber] === '['; + preg_match_all('/\h*([<\[])?\h*([\w|]+)\h*:?\h*([\w\h]+)?\h*[>\]]?\h*/iu', $usage, $matches, PREG_PATTERN_ORDER, strlen($commandString)); // https://regex101.com/r/1REoJG/22 + $argumentCount = count($matches[0]) - 1; + for($argNumber = 1; $argNumber <= $argumentCount; ++$argNumber){ + if(!isset($matches[1][$argNumber])){ + $paramName = strtolower($matches[2][$argNumber]); + $paramName = $paramName === 'bool' ? 'Boolean' : $paramName; + + $softEnums = $autofill->getSoftEnums(); + if(isset($softEnums[$paramName])){ + $enum = $softEnums[$paramName]; + }else{ + $autofill->addSoftEnum($enum = new CommandEnum($paramName, [$paramName]), false); + } + $overloads[$tree][$argNumber] = CommandParameter::enum($paramName, $enum, CommandParameter::FLAG_FORCE_COLLAPSE_ENUM, false); // collapse and assume required because no optional identifier exists in usage message + continue; + } + $optional = str_contains($matches[1][$argNumber], '['); $paramName = strtolower($matches[2][$argNumber]); - if(stripos($paramName, "|") === false) { - $paramType = match (strtolower($matches[3][$argNumber])) { - default => AvailableCommandsPacket::ARG_TYPE_STRING, - "int" => AvailableCommandsPacket::ARG_TYPE_INT, - "x y z" => AvailableCommandsPacket::ARG_TYPE_POSITION, - "float" => AvailableCommandsPacket::ARG_TYPE_FLOAT, - "target" => AvailableCommandsPacket::ARG_TYPE_TARGET, - "message" => AvailableCommandsPacket::ARG_TYPE_MESSAGE, - "json" => AvailableCommandsPacket::ARG_TYPE_JSON, - "command" => AvailableCommandsPacket::ARG_TYPE_COMMAND, - "boolean", "bool", "mixed" => AvailableCommandsPacket::ARG_TYPE_VALUE, - "text" => AvailableCommandsPacket::ARG_TYPE_RAWTEXT, - }; - $parameter = CommandParameter::standard($paramName, $paramType, 0, $optional); - }else{ + $paramType = strtolower($matches[3][$argNumber] ?? ''); + if(in_array($paramType, array_keys(array_merge($autofill->getSoftEnums(), $autofill->getHardcodedEnums())), true)){ + $paramType = $paramType === 'bool' ? 'Boolean' : $paramType; + $enum = $autofill->getSoftEnums()[$paramType] ?? $autofill->getHardcodedEnums()[$paramType]; + $overloads[$tree][$argNumber] = CommandParameter::enum($paramName, $enum, 0, $optional); + }elseif(str_contains($paramName, "|")){ + ++$enumCount; $enumValues = explode("|", $paramName); - $parameter = CommandParameter::enum($paramName, new CommandEnum($this->getName()." Enum#".$enumCount, $enumValues), CommandParameter::FLAG_FORCE_COLLAPSE_ENUM, $optional); + $autofill->addSoftEnum($enum = new CommandEnum($subCommandName . " Enum#" . $enumCount, $enumValues), false); + $overloads[$tree][$argNumber] = CommandParameter::enum($paramName, $enum, CommandParameter::FLAG_FORCE_COLLAPSE_ENUM, $optional); + }elseif(str_contains($paramName, "/")){ + ++$enumCount; + $enumValues = explode("/", $paramName); + $autofill->addSoftEnum($enum = new CommandEnum($subCommandName . " Enum#" . $enumCount, $enumValues), false); + $overloads[$tree][$argNumber] = CommandParameter::enum($paramName, $enum, CommandParameter::FLAG_FORCE_COLLAPSE_ENUM, $optional); + }else{ + $paramType = match ($paramType) { // ordered by constant value + 'int' => AvailableCommandsPacket::ARG_TYPE_INT, + 'float' => AvailableCommandsPacket::ARG_TYPE_FLOAT, + 'mixed' => AvailableCommandsPacket::ARG_TYPE_VALUE, + 'player', 'target' => AvailableCommandsPacket::ARG_TYPE_TARGET, + 'string' => AvailableCommandsPacket::ARG_TYPE_STRING, + 'x y z' => AvailableCommandsPacket::ARG_TYPE_POSITION, + 'message' => AvailableCommandsPacket::ARG_TYPE_MESSAGE, + default => AvailableCommandsPacket::ARG_TYPE_RAWTEXT, + 'json' => AvailableCommandsPacket::ARG_TYPE_JSON, + 'command' => AvailableCommandsPacket::ARG_TYPE_COMMAND, + }; + $overloads[$tree][$argNumber] = CommandParameter::standard($paramName, $paramType, 0, $optional); } - $overloads[$tree][$argNumber] = $parameter; } $tree++; } - $autofill->addManualOverride($this->getName(), new CommandData($this->getName(), $this->getDescription(), 0, 1, new CommandEnum(ucfirst($this->getName()) . "Aliases", array_merge([$this->getName()], $this->getAliases())), $overloads)); - $plugin->getLogger()->debug("Command Autofill Enabled"); + $data = $autofill->generateGenericCommandData($this->getName(), $this->getAliases(), $this->getDescription(), $this->getUsage()); + $data->overloads = $overloads; + $autofill->addManualOverride('myplot:' . $this->getName(), $data); + $owningPlugin->getLogger()->debug("Command Autofill Enabled"); } } /** - * @return SubCommand[] + * @return MyPlotSubCommand[] */ - public function getCommands() : array { + public function getCommands() : array{ return $this->subCommands; } - public function loadSubCommand(SubCommand $command) : void { + public function loadSubCommand(MyPlotSubCommand $command) : void{ $this->subCommands[$command->getName()] = $command; - if($command->getAlias() != "") { + if($command->getAlias() != ""){ $this->aliasSubCommands[$command->getAlias()] = $command; } } - public function unloadSubCommand(string $name) : void { + public function unloadSubCommand(string $name) : void{ $subcommand = $this->subCommands[$name] ?? $this->aliasSubCommands[$name] ?? null; - if($subcommand !== null) { + if($subcommand !== null){ unset($this->subCommands[$subcommand->getName()]); unset($this->aliasSubCommands[$subcommand->getAlias()]); } } - /** - * @param CommandSender $sender - * @param string $alias - * @param string[] $args - * - * @return bool - * @throws \ReflectionException - */ - public function execute(CommandSender $sender, string $alias, array $args) : bool { - /** @var MyPlot $plugin */ - $plugin = $this->getOwningPlugin(); - if($plugin->isDisabled()) { - $sender->sendMessage($plugin->getLanguage()->get("plugin.disabled")); + public function execute(CommandSender $sender, string $commandLabel, array $args) : bool{ + if($this->owningPlugin->isDisabled()){ + $sender->sendMessage($this->owningPlugin->getLanguage()->get("plugin.disabled")); return true; } - if(!isset($args[0])) { + if(!isset($args[0])){ $args[0] = "help"; - if($sender instanceof Player and $plugin->getConfig()->get("UI Forms", true) === true and class_exists('dktapps\\pmforms\\MenuForm')) { - $sender->sendForm(new MainForm($sender, $this->subCommands)); + if($sender instanceof Player and $this->owningPlugin->getConfig()->get("UI Forms", true) === true and class_exists('cosmicpe\\form\\PaginatedForm')){ + $sender->sendForm(new MainForm(1, $sender, $this->owningPlugin, $this->internalAPI)); return true; } } - $subCommand = strtolower((string)array_shift($args)); - if(isset($this->subCommands[$subCommand])) { + $subCommand = strtolower((string) array_shift($args)); + if(isset($this->subCommands[$subCommand])){ $command = $this->subCommands[$subCommand]; - }elseif(isset($this->aliasSubCommands[$subCommand])) { + }elseif(isset($this->aliasSubCommands[$subCommand])){ $command = $this->aliasSubCommands[$subCommand]; }else{ - $sender->sendMessage(TextFormat::RED . $plugin->getLanguage()->get("command.unknown")); + $sender->sendMessage(TextFormat::RED . $this->owningPlugin->getLanguage()->get("command.unknown")); return true; } - if($command->canUse($sender)) { - if(!$command->execute($sender, $args)) { - $usage = $plugin->getLanguage()->translateString("subcommand.usage", [$command->getUsage()]); - $sender->sendMessage($usage); - } - }else{ - $sender->sendMessage(TextFormat::RED . $plugin->getLanguage()->get("command.unknown")); + if(!$command->canUse($sender)){ + $sender->sendMessage(TextFormat::RED . $this->owningPlugin->getLanguage()->get("command.usable")); + return true; + } + if(!$command->execute($sender, $args)){ + $sender->sendMessage($this->owningPlugin->getLanguage()->translateString("subcommand.usage", [$command->getUsage()])); } return true; } diff --git a/src/MyPlot/EventListener.php b/src/MyPlot/EventListener.php index 70b984f0..9602ff74 100644 --- a/src/MyPlot/EventListener.php +++ b/src/MyPlot/EventListener.php @@ -7,6 +7,8 @@ use MyPlot\events\MyPlotPlayerEnterPlotEvent; use MyPlot\events\MyPlotPlayerLeavePlotEvent; use MyPlot\events\MyPlotPvpEvent; +use MyPlot\plot\BasePlot; +use MyPlot\plot\SinglePlot; use pocketmine\block\Liquid; use pocketmine\block\Sapling; use pocketmine\block\utils\TreeType; @@ -29,47 +31,34 @@ use pocketmine\utils\TextFormat; use pocketmine\world\World; -class EventListener implements Listener -{ - private MyPlot $plugin; +final class EventListener implements Listener{ + public function __construct(private MyPlot $plugin, private InternalAPI $internalAPI){ } /** - * EventListener constructor. - * - * @param MyPlot $plugin - */ - public function __construct(MyPlot $plugin) { - $this->plugin = $plugin; - } - - /** - * @ignoreCancelled false * @priority LOWEST * * @param WorldLoadEvent $event - * - * @throws \ReflectionException */ - public function onLevelLoad(WorldLoadEvent $event) : void { - if(file_exists($this->plugin->getDataFolder()."worlds".DIRECTORY_SEPARATOR.$event->getWorld()->getFolderName().".yml")) { + public function onLevelLoad(WorldLoadEvent $event) : void{ + if(file_exists($this->plugin->getDataFolder() . "worlds" . DIRECTORY_SEPARATOR . $event->getWorld()->getFolderName() . ".yml")){ $this->plugin->getLogger()->debug("MyPlot level " . $event->getWorld()->getFolderName() . " loaded!"); $settings = $event->getWorld()->getProvider()->getWorldData()->getGeneratorOptions(); $settings = json_decode($settings, true); - if($settings === false) { + if($settings === false){ return; } $levelName = $event->getWorld()->getFolderName(); - $default = array_filter((array) $this->plugin->getConfig()->get("DefaultWorld", []), function($key) : bool { + $default = array_filter((array) $this->plugin->getConfig()->get("DefaultWorld", []), function($key) : bool{ return !in_array($key, ["PlotSize", "GroundHeight", "RoadWidth", "RoadBlock", "WallBlock", "PlotFloorBlock", "PlotFillBlock", "BottomBlock"], true); }, ARRAY_FILTER_USE_KEY); - $config = new Config($this->plugin->getDataFolder()."worlds".DIRECTORY_SEPARATOR.$levelName.".yml", Config::YAML, $default); - foreach(array_keys($default) as $key) { - $settings[$key] = $config->get((string)$key); + $config = new Config($this->plugin->getDataFolder() . "worlds" . DIRECTORY_SEPARATOR . $levelName . ".yml", Config::YAML, $default); + foreach(array_keys($default) as $key){ + $settings[$key] = $config->get((string) $key); } - $this->plugin->addLevelSettings($levelName, new PlotLevelSettings($levelName, $settings)); + $this->internalAPI->addLevelSettings($levelName, new PlotLevelSettings($levelName, $settings)); - if($this->plugin->getConfig()->get('AllowFireTicking', false) === false) { - $ref = new \ReflectionClass($event->getWorld()); + if($this->plugin->getConfig()->get('AllowFireTicking', false) === false){ + $ref = new \ReflectionClass(World::class); $prop = $ref->getProperty('randomTickBlocks'); $prop->setAccessible(true); $randomTickBlocks = $prop->getValue($event->getWorld()); @@ -80,76 +69,83 @@ public function onLevelLoad(WorldLoadEvent $event) : void { } /** - * @ignoreCancelled false * @priority MONITOR * * @param WorldUnloadEvent $event */ - public function onLevelUnload(WorldUnloadEvent $event) : void { - if($event->isCancelled()) { - return; - } + public function onLevelUnload(WorldUnloadEvent $event) : void{ $levelName = $event->getWorld()->getFolderName(); - if($this->plugin->unloadLevelSettings($levelName)) { + if($this->internalAPI->unloadLevelSettings($levelName)){ $this->plugin->getLogger()->debug("Level " . $event->getWorld()->getFolderName() . " unloaded!"); } } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param BlockPlaceEvent $event */ - public function onBlockPlace(BlockPlaceEvent $event) : void { + public function onBlockPlace(BlockPlaceEvent $event) : void{ $this->onEventOnBlock($event); } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param BlockBreakEvent $event */ - public function onBlockBreak(BlockBreakEvent $event) : void { + public function onBlockBreak(BlockBreakEvent $event) : void{ $this->onEventOnBlock($event); } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param PlayerInteractEvent $event */ - public function onPlayerInteract(PlayerInteractEvent $event) : void { + public function onPlayerInteract(PlayerInteractEvent $event) : void{ $this->onEventOnBlock($event); } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param SignChangeEvent $event */ - public function onSignChange(SignChangeEvent $event) : void { + public function onSignChange(SignChangeEvent $event) : void{ $this->onEventOnBlock($event); } - private function onEventOnBlock(BlockPlaceEvent|SignChangeEvent|PlayerInteractEvent|BlockBreakEvent $event) : void { + private function onEventOnBlock(BlockPlaceEvent|SignChangeEvent|PlayerInteractEvent|BlockBreakEvent $event) : void{ $levelName = $event->getBlock()->getPosition()->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { + $plotLevel = $this->internalAPI->getLevelSettings($levelName); + if($plotLevel === null) return; - } - $plot = $this->plugin->getPlotByPosition($event->getBlock()->getPosition()); - if($plot !== null) { + + $pos = $event->getBlock()->getPosition(); + $x = $pos->x; + $z = $pos->z; + $plot = $this->internalAPI->getPlotFast($x, $z, $plotLevel); + + if($plot !== null){ $ev = new MyPlotBlockEvent($plot, $event->getBlock(), $event->getPlayer(), $event); - if($event->isCancelled()) { + if($event->isCancelled()) $ev->cancel(); - } + $ev->call(); $ev->isCancelled() ? $event->cancel() : $event->uncancel(); + $plot = $this->internalAPI->getPlotFromCache($plot, true); + if(!$plot instanceof SinglePlot){ + $event->cancel(); + $this->plugin->getLogger()->debug("Cancelled block change event at $x,$pos->y,$z in [$levelName]"); + return; + } $username = $event->getPlayer()->getName(); - if($plot->owner == $username or $plot->isHelper($username) or $plot->isHelper("*") or $event->getPlayer()->hasPermission("myplot.admin.build.plot")) { + if($plot->owner == $username or $plot->isHelper($username) or $plot->isHelper("*") or $event->getPlayer()->hasPermission("myplot.admin.build.plot")){ if(!($event instanceof PlayerInteractEvent and $event->getBlock() instanceof Sapling)) return; /* @@ -158,28 +154,35 @@ private function onEventOnBlock(BlockPlaceEvent|SignChangeEvent|PlayerInteractEv */ $block = $event->getBlock(); $maxLengthLeaves = $block->getIdInfo()->getVariant() === TreeType::SPRUCE()->getMagicNumber() ? 3 : 2; - $beginPos = $this->plugin->getPlotPosition($plot); + $beginPos = $this->internalAPI->getPlotPosition($plot); $endPos = clone $beginPos; $beginPos->x += $maxLengthLeaves; $beginPos->z += $maxLengthLeaves; - $plotSize = $this->plugin->getLevelSettings($levelName)->plotSize; + $plotSize = $plotLevel->plotSize; $endPos->x += $plotSize - $maxLengthLeaves; $endPos->z += $plotSize - $maxLengthLeaves; - if($block->getPosition()->x >= $beginPos->x and $block->getPosition()->z >= $beginPos->z and $block->getPosition()->x < $endPos->x and $block->getPosition()->z < $endPos->z) { + if($block->getPosition()->x >= $beginPos->x and $block->getPosition()->z >= $beginPos->z and $block->getPosition()->x < $endPos->x and $block->getPosition()->z < $endPos->z) return; - } } }elseif($event->getPlayer()->hasPermission("myplot.admin.build.road")) return; - elseif($this->plugin->isPositionBorderingPlot($event->getBlock()->getPosition()) and $this->plugin->getLevelSettings($levelName)->editBorderBlocks) { - $plot = $this->plugin->getPlotBorderingPosition($event->getBlock()->getPosition()); - if($plot instanceof Plot) { + elseif($plotLevel->editBorderBlocks){ + $plot = $this->internalAPI->getPlotBorderingPosition($event->getBlock()->getPosition()); + if($plot !== null){ + $plot = $this->internalAPI->getPlotFromCache($plot, true); + if(!$plot instanceof SinglePlot){ + $event->cancel(); + $this->plugin->getLogger()->debug("Cancelled block change event at $x,$pos->y,$z in [$levelName]"); + return; + } + $ev = new MyPlotBorderChangeEvent($plot, $event->getBlock(), $event->getPlayer(), $event); - if($event->isCancelled()) { + if($event->isCancelled()) $ev->cancel(); - } + $ev->call(); $ev->isCancelled() ? $event->cancel() : $event->uncancel(); + $username = $event->getPlayer()->getName(); if($plot->owner == $username or $plot->isHelper($username) or $plot->isHelper("*") or $event->getPlayer()->hasPermission("myplot.admin.build.plot")) if(!($event instanceof PlayerInteractEvent and $event->getBlock() instanceof Sapling)) @@ -187,35 +190,36 @@ private function onEventOnBlock(BlockPlaceEvent|SignChangeEvent|PlayerInteractEv } } $event->cancel(); - $this->plugin->getLogger()->debug("Block placement/break/interaction of {$event->getBlock()->getName()} was cancelled at ".$event->getBlock()->getPosition()->__toString()); + $this->plugin->getLogger()->debug("Block placement/break/interaction of {$event->getBlock()->getName()} was cancelled at " . $event->getBlock()->getPosition()->__toString()); } /** - * @ignoreCancelled false * @priority LOWEST * * @param EntityExplodeEvent $event */ - public function onExplosion(EntityExplodeEvent $event) : void { - if($event->isCancelled()) { - return; - } + public function onExplosion(EntityExplodeEvent $event) : void{ $levelName = $event->getEntity()->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) + $plotLevel = $this->internalAPI->getLevelSettings($levelName); + if($plotLevel === null) return; - $plot = $this->plugin->getPlotByPosition($event->getPosition()); - if($plot === null) { + + $pos = $event->getPosition(); + $x = $pos->x; + $z = $pos->z; + + $plot = $this->internalAPI->getPlotFast($x, $z, $plotLevel); + if($plot === null){ $event->cancel(); return; } - $beginPos = $this->plugin->getPlotPosition($plot); + $beginPos = $this->internalAPI->getPlotPosition($plot); $endPos = clone $beginPos; - $levelSettings = $this->plugin->getLevelSettings($levelName); - $plotSize = $levelSettings->plotSize; + $plotSize = $plotLevel->plotSize; $endPos->x += $plotSize; $endPos->z += $plotSize; - $blocks = array_filter($event->getBlockList(), function($block) use ($beginPos, $endPos) : bool { - if($block->getPosition()->x >= $beginPos->x and $block->getPosition()->z >= $beginPos->z and $block->getPosition()->x < $endPos->x and $block->getPosition()->z < $endPos->z) { + $blocks = array_filter($event->getBlockList(), function($block) use ($beginPos, $endPos) : bool{ + if($block->getPosition()->x >= $beginPos->x and $block->getPosition()->z >= $beginPos->z and $block->getPosition()->x < $endPos->x and $block->getPosition()->z < $endPos->z){ return true; } return false; @@ -224,174 +228,197 @@ public function onExplosion(EntityExplodeEvent $event) : void { } /** - * @ignoreCancelled false * @priority LOWEST * * @param EntityMotionEvent $event */ - public function onEntityMotion(EntityMotionEvent $event) : void { - if($event->isCancelled()) { - return; - } + public function onEntityMotion(EntityMotionEvent $event) : void{ $level = $event->getEntity()->getWorld(); if(!$level instanceof World) return; $levelName = $level->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) + if($this->internalAPI->getLevelSettings($levelName) === null) return; - $settings = $this->plugin->getLevelSettings($levelName); - if($settings->restrictEntityMovement and !($event->getEntity() instanceof Player)) { + $settings = $this->internalAPI->getLevelSettings($levelName); + if($settings->restrictEntityMovement and !($event->getEntity() instanceof Player)){ $event->cancel(); $this->plugin->getLogger()->debug("Cancelled entity motion on " . $levelName); } } /** - * @ignoreCancelled false * @priority LOWEST * * @param BlockSpreadEvent $event */ - public function onBlockSpread(BlockSpreadEvent $event) : void { - if($event->isCancelled()) { - return; - } + public function onBlockSpread(BlockSpreadEvent $event) : void{ $levelName = $event->getBlock()->getPosition()->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) + $plotLevel = $this->internalAPI->getLevelSettings($levelName); + if($plotLevel === null) return; - $settings = $this->plugin->getLevelSettings($levelName); - $newBlockInPlot = ($plotA = $this->plugin->getPlotByPosition($event->getBlock()->getPosition())) instanceof Plot; - $sourceBlockInPlot = ($plotB = $this->plugin->getPlotByPosition($event->getSource()->getPosition())) instanceof Plot; + $pos = $event->getBlock()->getPosition(); + $x = $pos->x; + $z = $pos->z; + $newBlockInPlot = ($plotA = $this->internalAPI->getPlotFast($x, $z, $plotLevel)) !== null; - $spreadIsSamePlot = (($newBlockInPlot and $sourceBlockInPlot)) && $plotA->isSame($plotB); + $pos = $event->getSource()->getPosition(); + $x = $pos->x; + $z = $pos->z; + $sourceBlockInPlot = ($plotB = $this->internalAPI->getPlotFast($x, $z, $plotLevel)) !== null; - if($event->getSource() instanceof Liquid) { - if(!$settings->updatePlotLiquids and ($sourceBlockInPlot or $this->plugin->isPositionBorderingPlot($event->getSource()->getPosition()))) { - $event->cancel(); - $this->plugin->getLogger()->debug("Cancelled {$event->getSource()->getName()} spread on [$levelName]"); - }elseif($settings->updatePlotLiquids and ($sourceBlockInPlot or $this->plugin->isPositionBorderingPlot($event->getSource()->getPosition())) and (!$newBlockInPlot or !$this->plugin->isPositionBorderingPlot($event->getBlock()->getPosition()) or !$spreadIsSamePlot)) { - $event->cancel(); - $this->plugin->getLogger()->debug("Cancelled {$event->getSource()->getName()} spread on [$levelName]"); - } - }elseif(!$settings->allowOutsidePlotSpread and (!$newBlockInPlot or !$spreadIsSamePlot)) { + $spreadIsSamePlot = (($newBlockInPlot and $sourceBlockInPlot)) and $plotA->isSame($plotB); + + if($event->getSource() instanceof Liquid and (!$plotLevel->updatePlotLiquids or !$spreadIsSamePlot)){ + $event->cancel(); + $this->plugin->getLogger()->debug("Cancelled {$event->getSource()->getName()} spread on [$levelName]"); + }elseif(!$plotLevel->allowOutsidePlotSpread and (!$newBlockInPlot or !$spreadIsSamePlot)){ $event->cancel(); //$this->plugin->getLogger()->debug("Cancelled block spread of {$event->getSource()->getName()} on ".$levelName); } } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param PlayerMoveEvent $event */ - public function onPlayerMove(PlayerMoveEvent $event) : void { + public function onPlayerMove(PlayerMoveEvent $event) : void{ $this->onEventOnMove($event->getPlayer(), $event); } /** - * @ignoreCancelled false + * @handleCancelled true * @priority LOWEST * * @param EntityTeleportEvent $event */ - public function onPlayerTeleport(EntityTeleportEvent $event) : void { + public function onPlayerTeleport(EntityTeleportEvent $event) : void{ $entity = $event->getEntity(); - if ($entity instanceof Player) { + if($entity instanceof Player){ $this->onEventOnMove($entity, $event); } } - private function onEventOnMove(Player $player, EntityTeleportEvent|PlayerMoveEvent $event) : void { + private function onEventOnMove(Player $player, EntityTeleportEvent|PlayerMoveEvent $event) : void{ $levelName = $player->getWorld()->getFolderName(); - if (!$this->plugin->isLevelLoaded($levelName)) + $plotLevel = $this->internalAPI->getLevelSettings($levelName); + if($plotLevel === null) return; - $plot = $this->plugin->getPlotByPosition($event->getTo()); - $plotFrom = $this->plugin->getPlotByPosition($event->getFrom()); - if($plot !== null and ($plotFrom === null or !$plot->isSame($plotFrom))) { - if(str_contains((string) $plot, "-0")) { + + $pos = $event->getTo(); + $x = $pos->x; + $z = $pos->z; + $plot = $this->internalAPI->getPlotFast($x, $z, $plotLevel); + + $pos = $event->getFrom(); + $x = $pos->x; + $z = $pos->z; + $plotFrom = $this->internalAPI->getPlotFast($x, $z, $plotLevel); + + if($plotFrom !== null and ($plot === null or !$plot->isSame($plotFrom))){ + if(str_contains((string) $plotFrom, "-0")) return; - } + + $ev = new MyPlotPlayerLeavePlotEvent($plotFrom, $player); + $event->isCancelled() ? $ev->cancel() : $ev->uncancel(); + $ev->call(); + $ev->isCancelled() ? $event->cancel() : $event->uncancel(); + } + + if($plot !== null) + $plot = $this->internalAPI->getPlotFromCache($plot, true); + + if($plot instanceof BasePlot and ($plotFrom === null or !$plot->isSame($plotFrom))){ + if(str_contains((string) $plot, "-0")) + return; + $plot = SinglePlot::fromBase($plot); + $ev = new MyPlotPlayerEnterPlotEvent($plot, $player); $event->isCancelled() ? $ev->cancel() : $ev->uncancel(); + $username = $ev->getPlayer()->getName(); - if($plot->owner !== $username and ($plot->isDenied($username) or $plot->isDenied("*")) and !$ev->getPlayer()->hasPermission("myplot.admin.denyplayer.bypass")) { + if($plot->owner !== $username and + ($plot->isDenied($username) or $plot->isDenied("*")) and + !$ev->getPlayer()->hasPermission("myplot.admin.denyplayer.bypass") + ) $ev->cancel(); - } + $ev->call(); $ev->isCancelled() ? $event->cancel() : $event->uncancel(); - if($event->isCancelled()) { + if($event->isCancelled()){ + $this->internalAPI->teleportPlayerToPlot($player, $plot); return; } - if(!(bool) $this->plugin->getConfig()->get("ShowPlotPopup", true)) + + if($this->plugin->getConfig()->get("ShowPlotPopup", true) === false) return; + $popup = $this->plugin->getLanguage()->translateString("popup", [TextFormat::GREEN . $plot]); $price = TextFormat::GREEN . $plot->price; - if($plot->owner !== "") { + if($plot->owner !== ""){ $owner = TextFormat::GREEN . $plot->owner; - if($plot->price > 0 and $plot->owner !== $player->getName()) { - $ownerPopup = $this->plugin->getLanguage()->translateString("popup.forsale", [$owner.TextFormat::WHITE, $price.TextFormat::WHITE]); + if($plot->price > 0 and $plot->owner !== $player->getName()){ + $ownerPopup = $this->plugin->getLanguage()->translateString("popup.forsale", [$owner . TextFormat::WHITE, $price . TextFormat::WHITE]); }else{ - $ownerPopup = $this->plugin->getLanguage()->translateString("popup.owner", [$owner.TextFormat::WHITE]); + $ownerPopup = $this->plugin->getLanguage()->translateString("popup.owner", [$owner . TextFormat::WHITE]); } }else{ - $ownerPopup = $this->plugin->getLanguage()->translateString("popup.available", [$price.TextFormat::WHITE]); + $ownerPopup = $this->plugin->getLanguage()->translateString("popup.available", [$price . TextFormat::WHITE]); } $paddingSize = (int) floor((strlen($popup) - strlen($ownerPopup)) / 2); $paddingPopup = str_repeat(" ", max(0, -$paddingSize)); $paddingOwnerPopup = str_repeat(" ", max(0, $paddingSize)); $popup = TextFormat::WHITE . $paddingPopup . $popup . "\n" . TextFormat::WHITE . $paddingOwnerPopup . $ownerPopup; $ev->getPlayer()->sendTip($popup); - }elseif($plotFrom !== null and ($plot === null or !$plot->isSame($plotFrom))) { - if(str_contains((string) $plotFrom, "-0")) { - return; - } - $ev = new MyPlotPlayerLeavePlotEvent($plotFrom, $player); - $event->isCancelled() ? $ev->cancel() : $ev->uncancel(); - $ev->call(); - $ev->isCancelled() ? $event->cancel() : $event->uncancel(); - }elseif($plotFrom !== null and $plot !== null and ($plot->isDenied($player->getName()) or $plot->isDenied("*")) and $plot->owner !== $player->getName() and !$player->hasPermission("myplot.admin.denyplayer.bypass")) { - $this->plugin->teleportPlayerToPlot($player, $plot); } } /** - * @ignoreCancelled false * @priority LOWEST * * @param EntityDamageByEntityEvent $event */ - public function onEntityDamage(EntityDamageByEntityEvent $event) : void { + public function onEntityDamage(EntityDamageByEntityEvent $event) : void{ $damaged = $event->getEntity(); $damager = $event->getDamager(); - if($damaged instanceof Player and $damager instanceof Player and !$event->isCancelled()) { + if($damaged instanceof Player and $damager instanceof Player){ $levelName = $damaged->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { + $plotLevel = $this->internalAPI->getLevelSettings($levelName); + if($plotLevel === null) return; - } - $settings = $this->plugin->getLevelSettings($levelName); - $plot = $this->plugin->getPlotByPosition($damaged->getPosition()); - if($plot !== null) { + + $pos = $damaged->getPosition(); + $x = $pos->x; + $z = $pos->z; + $plot = $this->internalAPI->getPlotFast($x, $z, $plotLevel); + if($plot !== null){ + $plot = $this->internalAPI->getPlotFromCache($plot); + if(!$plot instanceof SinglePlot){ + if($plotLevel->restrictPVP and !$damager->hasPermission("myplot.admin.pvp.bypass")) + $event->cancel(); + $this->plugin->getLogger()->debug("Cancelled player damage on [$levelName] due to plot not cached"); + return; + } + $ev = new MyPlotPvpEvent($plot, $damager, $damaged, $event); - if(!$plot->pvp and !$damager->hasPermission("myplot.admin.pvp.bypass")) { + if(!$plot->pvp and !$damager->hasPermission("myplot.admin.pvp.bypass")){ $ev->cancel(); - $this->plugin->getLogger()->debug("Cancelled pvp event in plot ".$plot->X.";".$plot->Z." on level '" . $levelName . "'"); + $this->plugin->getLogger()->debug("Cancelled pvp event in plot " . $plot->X . ";" . $plot->Z . " on level '" . $levelName . "'"); } $ev->call(); $ev->isCancelled() ? $event->cancel() : $event->uncancel(); - if($event->isCancelled()) { + if($event->isCancelled()){ $ev->getAttacker()->sendMessage(TextFormat::RED . $this->plugin->getLanguage()->translateString("pvp.disabled")); // generic message- we dont know if by config or plot } return; } - if($damager->hasPermission("myplot.admin.pvp.bypass")) { - return; - } - if($settings->restrictPVP) { + + if($plotLevel->restrictPVP and !$damager->hasPermission("myplot.admin.pvp.bypass")){ $event->cancel(); - $damager->sendMessage(TextFormat::RED.$this->plugin->getLanguage()->translateString("pvp.world")); - $this->plugin->getLogger()->debug("Cancelled pvp event on ".$levelName); + $damager->sendMessage(TextFormat::RED . $this->plugin->getLanguage()->translateString("pvp.world")); + $this->plugin->getLogger()->debug("Cancelled pvp event on " . $levelName); } } } diff --git a/src/MyPlot/InternalAPI.php b/src/MyPlot/InternalAPI.php new file mode 100644 index 00000000..ef5cdf75 --- /dev/null +++ b/src/MyPlot/InternalAPI.php @@ -0,0 +1,1392 @@ +getLogger()->debug(TF::BOLD . "Loading Data Provider settings"); + $this->dataProvider = new DataProvider($plugin, $this); + } + + public function getEconomyProvider() : ?InternalEconomyProvider{ + return $this->economyProvider; + } + + public function setEconomyProvider(?InternalEconomyProvider $economyProvider) : void{ + $this->economyProvider = $economyProvider; + } + + public function getAllLevelSettings() : array{ + return $this->levels; + } + + public function getLevelSettings(string $levelName) : ?PlotLevelSettings{ + return $this->levels[$levelName] ?? null; + } + + public function addLevelSettings(string $levelName, PlotLevelSettings $settings) : void{ + $this->levels[$levelName] = $settings; + } + + public function unloadLevelSettings(string $levelName) : bool{ + if(isset($this->levels[$levelName])){ + unset($this->levels[$levelName]); + return true; + } + return false; + } + + /** + * @param SinglePlot $plot + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function savePlot(SinglePlot $plot, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlotsToSave($plot), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generatePlotsToSave(SinglePlot $plot) : \Generator{ + $ev = new MyPlotSaveEvent($plot); + $ev->call(); + $plot = $ev->getPlot(); + if($plot instanceof MergedPlot){ + $failed = false; + for($x = $plot->X; $x < $plot->xWidth + $plot->X; ++$x){ + for($z = $plot->Z; $z < $plot->zWidth + $plot->Z; ++$z){ + $newPlot = clone $plot; + $newPlot->X = $x; + $newPlot->Z = $z; + if(yield from $this->dataProvider->savePlot($newPlot)){ + $failed = true; + } + } + } + return $failed; + } + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param string $username + * @param string|null $levelName + * @param callable|null $onComplete + * @phpstan-param (callable(array): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function getPlotsOfPlayer(string $username, ?string $levelName, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlotsOfPlayer($username, $levelName), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + /** + * @param string $username + * @param string|null $levelName + * + * @return \Generator> + */ + public function generatePlotsOfPlayer(string $username, ?string $levelName) : \Generator{ + return yield from $this->dataProvider->getPlotsByOwner($username, $levelName ?? ''); + } + + /** + * @param string $levelName + * @param int $limitXZ + * @param callable|null $onComplete + * @phpstan-param (callable(BasePlot): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function getNextFreePlot(string $levelName, int $limitXZ, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateNextFreePlot($levelName, $limitXZ), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateNextFreePlot(string $levelName, int $limitXZ) : \Generator{ + return yield from $this->dataProvider->getNextFreePlot($levelName, $limitXZ); + } + + /** + * @param BasePlot $plot + * @param callable|null $onComplete + * @phpstan-param (callable(SinglePlot|null): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function getPlot(BasePlot $plot, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlot($plot), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + /** + * @param BasePlot $plot + * + * @return \Generator + */ + public function generatePlot(BasePlot $plot) : \Generator{ + return yield from $this->dataProvider->getMergedPlot($plot); + } + + public function getPlotFast(float &$x, float &$z, PlotLevelSettings $plotLevel) : ?BasePlot{ + $plotSize = $plotLevel->plotSize; + $roadWidth = $plotLevel->roadWidth; + $totalSize = $plotSize + $roadWidth; + if($x >= 0){ + $difX = $x % $totalSize; + $x = (int) floor($x / $totalSize); + }else{ + $difX = abs(($x - $plotSize + 1) % $totalSize); + $x = (int) ceil(($x - $plotSize + 1) / $totalSize); + } + if($z >= 0){ + $difZ = $z % $totalSize; + $z = (int) floor($z / $totalSize); + }else{ + $difZ = abs(($z - $plotSize + 1) % $totalSize); + $z = (int) ceil(($z - $plotSize + 1) / $totalSize); + } + if(($difX > $plotSize - 1) or ($difZ > $plotSize - 1)) + return null; + + return new BasePlot($plotLevel->name, $x, $z); + } + + public function getPlotFromCache(BasePlot $plot, bool $orderCachePopulation = true) : BasePlot{ + $cachedPlot = $this->dataProvider->getPlotFromCache($plot->levelName, $plot->X, $plot->Z); + if(!$cachedPlot instanceof SinglePlot and $orderCachePopulation and !in_array("{$plot->levelName}:{$plot->X}:{$plot->Z}", $this->populatingCache, true)){ + $index = count($this->populatingCache); + $this->populatingCache[] = "{$plot->levelName}:{$plot->X}:{$plot->Z}"; + Await::g2c( + $this->generatePlot($plot), + function(?BasePlot $cachedPlot) use ($index) : void{ + unset($this->populatingCache[$index]); + }, + function(\Throwable $e) use ($plot, $index) : void{ + $this->plugin->getLogger()->debug("Plot {$plot->X};{$plot->Z} could not be generated"); + unset($this->populatingCache[$index]); + } + ); + } + return $cachedPlot; + } + + /** + * @param Position $position + * @param callable|null $onComplete + * @phpstan-param (callable(BasePlot): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function getPlotByPosition(Position $position, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlotByPosition($position), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generatePlotByPosition(Position $position) : \Generator{ + $x = $position->x; + $z = $position->z; + $levelName = $position->getWorld()->getFolderName(); + $plotLevel = $this->getLevelSettings($levelName); + if($plotLevel === null) + return null; + + $plot = $this->getPlotFast($x, $z, $plotLevel); + if($plot !== null) + return yield from $this->generatePlot($plot); + return null; + } + + /** + * @param BasePlot $plot + * + * @return Position + */ + public function getPlotPosition(BasePlot $plot) : Position{ + $plotLevel = $this->getLevelSettings($plot->levelName); + $plotSize = $plotLevel->plotSize; + $roadWidth = $plotLevel->roadWidth; + $totalSize = $plotSize + $roadWidth; + $x = $totalSize * $plot->X; + $z = $totalSize * $plot->Z; + $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + return new Position($x, $plotLevel->groundHeight, $z, $level); + } + + public function isPositionBorderingPlot(Position $position) : bool{ + return $this->getPlotBorderingPosition($position) instanceof BasePlot; + } + + public function getPlotBorderingPosition(Position $position) : ?BasePlot{ + if(!$position->isValid()) + return null; + foreach(Facing::HORIZONTAL as $i){ + $pos = $position->getSide($i); + $x = $pos->x; + $z = $pos->z; + $levelName = $pos->getWorld()->getFolderName(); + + $plotLevel = $this->getLevelSettings($levelName); + if($plotLevel === null) + return null; + + return $this->getPlotFast($x, $z, $plotLevel); + // TODO: checks for merged plots + } + return null; + } + + public function getPlotBB(BasePlot $plot) : ?AxisAlignedBB{ + $plotLevel = $this->getLevelSettings($plot->levelName); + if($plotLevel === null) + return null; + + $plotSize = $plotLevel->plotSize; + $totalSize = $plotSize + $plotLevel->roadWidth; + $pos = $this->getPlotPosition($plot); + $xMax = $pos->x + $plotSize - 1; + $zMax = $pos->z + $plotSize - 1; + if($plot instanceof MergedPlot){ + $xMax = $pos->x + $totalSize * $plot->xWidth - 1; + $zMax = $pos->z + $totalSize * $plot->zWidth - 1; + } + + return new AxisAlignedBB( + $pos->x, + $pos->getWorld()->getMinY(), + $pos->z, + $xMax, + $pos->getWorld()->getMaxY(), + $zMax + ); + } + + /** + * @param SinglePlot $plot + * @param int $direction + * @param int $maxBlocksPerTick + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function mergePlots(SinglePlot $plot, int $direction, int $maxBlocksPerTick, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateMergePlots($plot, $direction, $maxBlocksPerTick), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateMergePlots(SinglePlot $plot, int $direction, int $maxBlocksPerTick) : \Generator{ + $plotLevel = $this->getLevelSettings($plot->levelName); + if($plotLevel === null) + return false; + + $plot = yield from $this->generatePlot($plot); + + /** @var BasePlot[] $toMerge */ + $toMerge[] = $plot->getSide($direction); + if($plot instanceof MergedPlot){ + $toMerge[] = $plot->getSide( + Facing::rotateY($direction, Facing::isPositive($direction)), + Facing::axis($direction) === Axis::X ? $plot->xWidth : $plot->zWidth + ); + } + + /** @var SinglePlot[] $toMerge */ + $toMerge = yield AsyncVariants::array_map( + function(SinglePlot $plot) : \Generator{ + return yield from $this->generatePlot($plot); + }, + $toMerge + ); + + foreach($toMerge as $newPlot){ + if($newPlot === null or + $newPlot instanceof MergedPlot or + $newPlot->levelName !== $plot->levelName or + $newPlot->owner !== $plot->owner + ) + return false; + } + + if(!$plot instanceof MergedPlot){ + $plot = MergedPlot::fromSingle( + $plot, + Facing::axis($direction) === Axis::X ? count($toMerge) : 1, + Facing::axis($direction) === Axis::Z ? count($toMerge) : 1 + ); + } + + $ev = new MyPlotMergeEvent($plot, $direction, $toMerge); + $ev->call(); + if($ev->isCancelled()) + return false; + + $styler = $this->plugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); + if($this->plugin->getConfig()->get("FastClearing", false) === true and $styler instanceof WorldStyler) { + $world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + if($world === null) + return false; + + $plotSize = $plotLevel->plotSize; + $totalSize = $plotSize + $plotLevel->roadWidth; + + $aabb = $this->getPlotBB($plot); + + $aabbExpanded = $aabb->expandedCopy(1, 0, 1); // expanded to include plot borders + foreach($world->getEntities() as $entity){ + if($aabbExpanded->isVectorInXZ($entity->getPosition())){ + if(!$entity instanceof Player){ + $entity->flagForDespawn(); + }else{ + $this->teleportPlayerToPlot($entity, $plot, false); + } + } + } + + $aabb = match ($direction) { + Facing::NORTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->minZ - $plotLevel->roadWidth, + $aabb->maxX, + $aabb->maxY, + $aabb->minZ + ), + Facing::EAST => new AxisAlignedBB( + $aabb->maxX + ($totalSize * ($plot->xWidth - 1)), + $aabb->minY, + $aabb->minZ, + $aabb->maxX + ($totalSize * ($plot->xWidth - 1)) + $plotLevel->roadWidth, + $aabb->maxY, + $aabb->maxZ + ), + Facing::SOUTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->maxZ + ($totalSize * ($plot->zWidth - 1)), + $aabb->maxX, + $aabb->maxY, + $aabb->maxZ + ($totalSize * ($plot->zWidth - 1)) + $plotLevel->roadWidth + ), + Facing::WEST => new AxisAlignedBB( + $aabb->minX - $plotLevel->roadWidth, + $aabb->minY, + $aabb->minZ, + $aabb->minX, + $aabb->maxY, + $aabb->maxZ + ), + default => throw new \InvalidArgumentException("Invalid direction $direction") + }; + + // above ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->maxY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 2, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, VanillaBlocks::AIR()->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + if(Facing::axis($direction) === Axis::X) { + // min border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // max border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + }elseif(Facing::axis($direction) === Axis::Z){ + // min border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // max border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + } + + // ground height + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFloorBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // below ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight - 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFillBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // bottom block + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->minY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->bottomBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + $i = 0; + foreach($toMerge as $newPlot) { + $newPlot = MergedPlot::fromSingle( + SinglePlot::fromBase($newPlot), + Facing::axis($direction) === Axis::X ? $i : 1, + Facing::axis($direction) === Axis::Z ? $i : 1 + ); + $direction = Facing::rotateY($direction, true); + + $aabb = $this->getPlotBB($newPlot); + + $aabbExpanded = $aabb->expandedCopy(1, 0, 1); // expanded to include plot borders + foreach($world->getEntities() as $entity){ + if($aabbExpanded->isVectorInXZ($entity->getPosition())){ + if(!$entity instanceof Player){ + $entity->flagForDespawn(); + }else{ + $this->teleportPlayerToPlot($entity, $newPlot, false); + } + } + } + + $aabb = match ($direction) { + Facing::NORTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->minZ - $plotLevel->roadWidth, + $aabb->maxX, + $aabb->maxY, + $aabb->minZ + ), + Facing::EAST => new AxisAlignedBB( + $aabb->maxX + ($totalSize * ($newPlot->xWidth - 1)), + $aabb->minY, + $aabb->minZ, + $aabb->maxX + ($totalSize * ($newPlot->xWidth - 1)) + $plotLevel->roadWidth, + $aabb->maxY, + $aabb->maxZ + ), + Facing::SOUTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->maxZ + ($totalSize * ($newPlot->zWidth - 1)), + $aabb->maxX, + $aabb->maxY, + $aabb->maxZ + ($totalSize * ($newPlot->zWidth - 1)) + $plotLevel->roadWidth + ), + Facing::WEST => new AxisAlignedBB( + $aabb->minX - $plotLevel->roadWidth, + $aabb->minY, + $aabb->minZ, + $aabb->minX, + $aabb->maxY, + $aabb->maxZ + ), + default => throw new \InvalidArgumentException("Invalid direction $direction") + }; + + // above ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->maxY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 2, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, VanillaBlocks::AIR()->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + if(Facing::isPositive($direction)) { + if(Facing::axis($direction) === Axis::X) { + // max border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + }elseif(Facing::axis($direction) === Axis::Z){ + // max border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + } + }else{ + if(Facing::axis($direction) === Axis::X) { + // min border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + }elseif(Facing::axis($direction) === Axis::Z){ + // min border + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + } + } + + // ground height + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFloorBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // below ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight - 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFillBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // bottom block + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->minY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->bottomBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + ++$i; + } + + foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]){ + if($chunk === null) + continue; + foreach($chunk->getTiles() as $tile) + if($aabb->isVectorInXZ($tile->getPosition())) + $tile->close(); + $world->setChunk($chunkX, $chunkZ, $chunk); + } + + return yield from $this->dataProvider->mergePlots($plot, ...$toMerge); + } + + $this->plugin->getScheduler()->scheduleTask(new RoadFillTask($this->plugin, $plot, $direction, RoadFillTask::BOTH_BORDERS, $maxBlocksPerTick)); + + for($i = 0; $i < count($toMerge) - 1; ++$i){ + $this->plugin->getScheduler()->scheduleTask(new RoadFillTask( + $this->plugin, + MergedPlot::fromSingle( + SinglePlot::fromBase($toMerge[$i]), + Facing::axis($direction) === Axis::X ? $i : 1, + Facing::axis($direction) === Axis::Z ? $i : 1 + ), + Facing::rotateY($direction, true), + Facing::isPositive($direction) ? RoadFillTask::HIGH_BORDER : RoadFillTask::LOW_BORDER, + $maxBlocksPerTick + )); + } + + return yield from $this->dataProvider->mergePlots($plot, ...$toMerge); + } + + public function teleportPlayerToPlot(Player $player, BasePlot $plot, bool $center = false) : bool{ + $ev = new MyPlotTeleportEvent($plot, $player, $center); + $ev->call(); + if($ev->isCancelled()) + return false; + + $plotLevel = $this->getLevelSettings($plot->levelName); + $plotSize = $plotLevel->plotSize; + $totalWidth = $plotSize + $plotLevel->roadWidth; + $pos = $this->getPlotPosition($plot); + $pos->y += 1.5; + + if($center and $plot instanceof MergedPlot){ + $pos->x += $pos->x + ($totalWidth * $plot->xWidth) / 2; + $pos->z += $pos->z + ($totalWidth * $plot->zWidth) / 2; + }elseif($center){ + $pos->x += $plotSize / 2; + $pos->z += $plotSize / 2; + }elseif($plot instanceof MergedPlot){ + $pos->x += $pos->x + ($totalWidth * $plot->xWidth) / 2; + $pos->z -= 1; + }else{ + $pos->x += $plotSize / 2; + $pos->z -= 1; + } + return $player->teleport($pos); + } + + /** + * @param SinglePlot $plot + * @param string $claimer + * @param string $plotName + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function claimPlot(SinglePlot $plot, string $claimer, string $plotName, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateClaimPlot($plot, $claimer, $plotName), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateClaimPlot(SinglePlot $plot, string $claimer, string $plotName) : \Generator{ + $newPlot = clone $plot; + $newPlot->owner = $claimer; + $newPlot->helpers = []; + $newPlot->denied = []; + if($plotName !== "") + $newPlot->name = $plotName; + $newPlot->price = 0; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $ev->call(); + if($ev->isCancelled()){ + return false; + } + return yield from $this->generatePlotsToSave($ev->getPlot()); // TODO: figure out why cache is not updated + } + + /** + * @param SinglePlot $plot + * @param string $newName + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function renamePlot(SinglePlot $plot, string $newName, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateRenamePlot($plot, $newName), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateRenamePlot(SinglePlot $plot, string $newName) : \Generator{ + $newPlot = clone $plot; + $newPlot->name = $newName; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $ev->call(); + if($ev->isCancelled()){ + return false; + } + return yield from $this->generatePlotsToSave($ev->getPlot()); + } + + public function clonePlot(SinglePlot $plotFrom, SinglePlot $plotTo) : bool{ + $styler = $this->plugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); + if(!$styler instanceof WorldStyler) + return false; + + $ev = new MyPlotCloneEvent($plotFrom, $plotTo); + $ev->call(); + if($ev->isCancelled()) + return false; + + $plotFrom = $ev->getPlot(); + $plotTo = $ev->getClonePlot(); + + if($this->getLevelSettings($plotFrom->levelName) === null or $this->getLevelSettings($plotTo->levelName) === null) + return false; + + $fromMerge = $plotFrom instanceof MergedPlot; + $toMerge = $plotTo instanceof MergedPlot; + if(($fromMerge and !$toMerge) or (!$toMerge and $fromMerge)) + return false; + if($fromMerge and $toMerge and ($plotFrom->xWidth !== $plotTo->xWidth or $plotFrom->zWidth !== $plotTo->zWidth)) + return false; + + $selection = $styler->getSelection(99997) ?? new Selection(99997); + + $world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plotFrom->levelName); + $fromAABB = $this->getPlotBB($plotFrom); + + $vec1 = new Vector3($fromAABB->minX - 1, $fromAABB->minY, $fromAABB->minZ - 1); + $selection->setPosition(1, $vec1); + $selection->setPosition(2, new Vector3($fromAABB->maxX, $fromAABB->maxY, $fromAABB->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); // do not use async because WorldStyler async is very broken right now + $cuboid->copy($world, $vec1, function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug(TF::GREEN . 'Copied ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's to the MyPlot clipboard.'); + }); + + $world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plotTo->levelName); + $toAABB = $this->getPlotBB($plotTo); + foreach($world->getEntities() as $entity){ + if($toAABB->isVectorInXZ($entity->getPosition())){ + if($entity instanceof Player){ + $this->teleportPlayerToPlot($entity, $plotTo, false); + }else{ + $entity->flagForDespawn(); + } + } + } + + $vec1 = new Vector3($toAABB->minX - 1, $toAABB->minY, $toAABB->minZ - 1); + $selection->setPosition(1, $vec1); + $selection->setPosition(2, new Vector3($toAABB->maxX, $toAABB->maxY, $toAABB->maxZ)); + $commonShape = CommonShape::fromSelection($selection); + //$commonShape = $commonShape->async(); // do not use async because WorldStyler async is very broken right now + $commonShape->paste($world, $vec1, true, function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug(TF::GREEN . 'Pasted ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's from the MyPlot clipboard.'); + }); + $styler->removeSelection(99997); + + foreach($this->getPlotChunks($plotTo) as [$chunkX, $chunkZ, $chunk]){ + $world->setChunk($chunkX, $chunkZ, $chunk); + } + return true; + } + + public function clearPlot(BasePlot $plot, int $maxBlocksPerTick) : bool{ + $ev = new MyPlotClearEvent($plot, $maxBlocksPerTick); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + $maxBlocksPerTick = $ev->getMaxBlocksPerTick(); + + $plotLevel = $this->getLevelSettings($plot->levelName); + if($plotLevel === null) + return false; + + $styler = $this->plugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); + if($this->plugin->getConfig()->get("FastClearing", false) === true and $styler instanceof WorldStyler){ + $world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + if($world === null) + return false; + + $aabb = $this->getPlotBB($plot)->expand(1, 0, 1); // expanded to include plot borders + foreach($world->getEntities() as $entity){ + if($aabb->isVectorInXZ($entity->getPosition())){ + if(!$entity instanceof Player){ + $entity->flagForDespawn(); + }else{ + $this->teleportPlayerToPlot($entity, $plot, false); + } + } + } + + // Above ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->maxY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, VanillaBlocks::AIR()->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Ground Surface + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFloorBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight - 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->plotFillBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Bottom of world + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->minY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->bottomBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Border +X + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Border +Z + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $plotLevel->groundHeight + 1, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Border -X + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->minX, $aabb->minY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + // Border -Z + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->minY, $aabb->minZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotLevel->wallBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]){ + if($chunk === null) + continue; + foreach($chunk->getTiles() as $tile) + if($aabb->isVectorInXZ($tile->getPosition())) + $tile->close(); + $world->setChunk($chunkX, $chunkZ, $chunk); + } + return true; + } + $this->plugin->getScheduler()->scheduleTask(new ClearPlotTask($this->plugin, $plot, $maxBlocksPerTick)); + return true; + } + + public function fillPlot(BasePlot $plot, Block $plotFillBlock, int $maxBlocksPerTick) : bool{ + $ev = new MyPlotFillEvent($plot, $maxBlocksPerTick); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + $maxBlocksPerTick = $ev->getMaxBlocksPerTick(); + + $plotLevel = $this->getLevelSettings($plot->levelName); + if($plotLevel === null) + return false; + + $styler = $this->plugin->getServer()->getPluginManager()->getPlugin("WorldStyler"); + if($this->plugin->getConfig()->get("FastFilling", false) === true and $styler instanceof WorldStyler){ + $world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + if($world === null) + return false; + + $aabb = $this->getPlotBB($plot); + $aabb->maxY = $this->getLevelSettings($plot->levelName)->groundHeight; + foreach($world->getEntities() as $entity){ + if($aabb->isVectorInside($entity->getPosition())){ + if(!$entity instanceof Player){ + $entity->flagForDespawn(); + }else{ + $this->teleportPlayerToPlot($entity, $plot, false); + } + } + } + + // Ground + $selection = $styler->getSelection(99998) ?? new Selection(99998); + $selection->setPosition(1, new Vector3($aabb->minX, $aabb->minY + 1, $aabb->minZ)); + $selection->setPosition(2, new Vector3($aabb->maxX, $aabb->maxY, $aabb->maxZ)); + $cuboid = Cuboid::fromSelection($selection); + //$cuboid = $cuboid->async(); + $cuboid->set($world, $plotFillBlock->getFullId(), function(float $time, int $changed) : void{ + $this->plugin->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); + }); + $styler->removeSelection(99998); + + foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]){ + $world->setChunk($chunkX, $chunkZ, $chunk); + } + return true; + } + $this->plugin->getScheduler()->scheduleTask(new FillPlotTask($this->plugin, $plot, $plotFillBlock, $maxBlocksPerTick)); + return true; + } + + /** + * @param SinglePlot $plot + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function disposePlot(BasePlot $plot, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateDisposePlot($plot), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateDisposePlot(BasePlot $plot) : \Generator{ + $ev = new MyPlotDisposeEvent($plot); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->deletePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param int $maxBlocksPerTick + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function resetPlot(SinglePlot $plot, int $maxBlocksPerTick, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateResetPlot($plot, $maxBlocksPerTick), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateResetPlot(SinglePlot $plot, int $maxBlocksPerTick) : \Generator{ + $ev = new MyPlotResetEvent($plot); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + if(!yield from $this->generateDisposePlot($plot)){ + return false; + } + if(!$this->clearPlot($plot, $maxBlocksPerTick)){ + yield from $this->generatePlotsToSave($plot); + return false; + } + return true; + } + + /** + * @param SinglePlot $plot + * @param Biome $biome + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function setPlotBiome(SinglePlot $plot, Biome $biome, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlotBiome($plot, $biome), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generatePlotBiome(SinglePlot $plot, Biome $biome) : \Generator{ + $newPlot = clone $plot; + $newPlot->biome = str_replace(" ", "_", strtoupper($biome->getName())); + $ev = new MyPlotSettingEvent($plot, $newPlot); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + if($this->getLevelSettings($plot->levelName) === null) + return false; + + $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + if($level === null) + return false; + + if(defined(BiomeIds::class . "::" . $plot->biome) and is_int(constant(BiomeIds::class . "::" . $plot->biome))){ + $biome = constant(BiomeIds::class . "::" . $plot->biome); + }else{ + $biome = BiomeIds::PLAINS; + } + $biome = BiomeRegistry::getInstance()->getBiome($biome); + + $aabb = $this->getPlotBB($plot); + foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]){ + if($chunk === null) + continue; + + for($x = 0; $x < Chunk::EDGE_LENGTH; ++$x){ + for($z = 0; $z < Chunk::EDGE_LENGTH; ++$z){ + if($aabb->isVectorInXZ(new Vector3(($chunkX << Chunk::COORD_MASK) + $x, 0, ($chunkZ << Chunk::COORD_MASK) + $z))){ + $chunk->setBiomeId($x, $z, $biome->getId()); + } + } + } + $level->setChunk($chunkX, $chunkZ, $chunk); + } + return yield from $this->generatePlotsToSave($plot); + } + + /** + * @param SinglePlot $plot + * @param bool $pvp + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function setPlotPvp(SinglePlot $plot, bool $pvp, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generatePlotPvp($plot, $pvp), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generatePlotPvp(SinglePlot $plot, bool $pvp) : \Generator{ + $newPlot = clone $plot; + $newPlot->pvp = $pvp; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param string $player + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function addPlotHelper(SinglePlot $plot, string $player, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateAddPlotHelper($plot, $player), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateAddPlotHelper(SinglePlot $plot, string $player) : \Generator{ + $newPlot = clone $plot; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $newPlot->addHelper($player) ? $ev->uncancel() : $ev->cancel(); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param string $player + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function removePlotHelper(SinglePlot $plot, string $player, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateRemovePlotHelper($plot, $player), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateRemovePlotHelper(SinglePlot $plot, string $player) : \Generator{ + $newPlot = clone $plot; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $newPlot->removeHelper($player) ? $ev->uncancel() : $ev->cancel(); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param string $player + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function addPlotDenied(SinglePlot $plot, string $player, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateAddPlotDenied($plot, $player), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateAddPlotDenied(SinglePlot $plot, string $player) : \Generator{ + $newPlot = clone $plot; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $newPlot->denyPlayer($player) ? $ev->uncancel() : $ev->cancel(); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param string $player + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function removePlotDenied(SinglePlot $plot, string $player, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateRemovePlotDenied($plot, $player), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateRemovePlotDenied(SinglePlot $plot, string $player) : \Generator{ + $newPlot = clone $plot; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $newPlot->unDenyPlayer($player) ? $ev->uncancel() : $ev->cancel(); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param int $price + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function sellPlot(SinglePlot $plot, int $price, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateSellPlot($plot, $price), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateSellPlot(SinglePlot $plot, int $price) : \Generator{ + if($this->economyProvider === null or $price <= 0){ + return false; + } + + $newPlot = clone $plot; + $newPlot->price = $price; + $ev = new MyPlotSettingEvent($plot, $newPlot); + $ev->call(); + if($ev->isCancelled()) + return false; + $plot = $ev->getPlot(); + return yield from $this->dataProvider->savePlot($plot); + } + + /** + * @param SinglePlot $plot + * @param Player $player + * @param callable|null $onComplete + * @phpstan-param (callable(bool): void)|null $onComplete + * @param callable|null $onFail + * @phpstan-param (callable(\Throwable): void)|null $catches + */ + public function buyPlot(SinglePlot $plot, Player $player, ?callable $onComplete = null, ?callable $onFail = null) : void{ + Await::g2c( + $this->generateBuyPlot($plot, $player), + $onComplete, + $onFail === null ? [] : [$onFail] + ); + } + + public function generateBuyPlot(SinglePlot $plot, Player $player) : \Generator{ + if($this->economyProvider === null){ + return false; + } + if(!yield from $this->economyProvider->reduceMoney($player, $plot->price)){ + return false; + } + if(!yield from $this->economyProvider->addMoney($this->plugin->getServer()->getOfflinePlayer($plot->owner), $plot->price)){ + yield from $this->economyProvider->addMoney($player, $plot->price); + return false; + } + + return yield from $this->generateClaimPlot($plot, $player->getName(), ''); + } + + /** + * @param BasePlot $plot + * + * @return array + * @phpstan-return array> + */ + public function getPlotChunks(BasePlot $plot) : array{ + $plotLevel = $this->getLevelSettings($plot->levelName); + if($plotLevel === null) + return []; + + $aabb = $this->getPlotBB($plot); + $xMin = $aabb->minX >> Chunk::COORD_MASK; + $zMin = $aabb->minZ >> Chunk::COORD_MASK; + $xMax = $aabb->maxX >> Chunk::COORD_MASK; + $zMax = $aabb->maxZ >> Chunk::COORD_MASK; + + $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + $chunks = []; + for($x = $xMin; $x <= $xMax; ++$x){ + for($z = $zMin; $z <= $zMax; ++$z){ + $chunks[] = [$x, $z, $level->getChunk($x, $z)]; + } + } + return $chunks; + } + + public function onDisable() : void{ + $this->dataProvider->close(); + } +} \ No newline at end of file diff --git a/src/MyPlot/MyPlot.php b/src/MyPlot/MyPlot.php index 1d0fbdbb..df0e3f0f 100644 --- a/src/MyPlot/MyPlot.php +++ b/src/MyPlot/MyPlot.php @@ -2,37 +2,18 @@ declare(strict_types=1); namespace MyPlot; -use muqsit\worldstyler\Selection; -use muqsit\worldstyler\shapes\CommonShape; -use muqsit\worldstyler\shapes\Cuboid; -use muqsit\worldstyler\WorldStyler; -use MyPlot\events\MyPlotClearEvent; -use MyPlot\events\MyPlotCloneEvent; -use MyPlot\events\MyPlotDisposeEvent; -use MyPlot\events\MyPlotFillEvent; +use cooldogedev\BedrockEconomy\api\BedrockEconomyAPI; +use cooldogedev\BedrockEconomy\BedrockEconomy; use MyPlot\events\MyPlotGenerationEvent; -use MyPlot\events\MyPlotMergeEvent; -use MyPlot\events\MyPlotResetEvent; -use MyPlot\events\MyPlotSettingEvent; -use MyPlot\events\MyPlotTeleportEvent; -use MyPlot\provider\ConfigDataProvider; -use MyPlot\provider\DataProvider; -use MyPlot\provider\EconomyProvider; -use MyPlot\provider\EconomySProvider; -use MyPlot\provider\MySQLProvider; -use MyPlot\provider\SQLiteDataProvider; -use MyPlot\task\ClearBorderTask; -use MyPlot\task\ClearPlotTask; -use MyPlot\task\FillPlotTask; -use MyPlot\task\RoadFillTask; -use onebone\economyapi\EconomyAPI; +use MyPlot\plot\BasePlot; +use MyPlot\plot\SinglePlot; +use MyPlot\provider\EconomyWrapper; +use MyPlot\provider\InternalBedrockEconomyProvider; +use MyPlot\provider\InternalCapitalProvider; +use MyPlot\provider\InternalEconomySProvider; use pocketmine\block\Block; -use pocketmine\block\VanillaBlocks; -use pocketmine\data\bedrock\BiomeIds; -use pocketmine\event\world\WorldLoadEvent; use pocketmine\lang\Language; use pocketmine\math\AxisAlignedBB; -use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\permission\DefaultPermissions; use pocketmine\permission\Permission; @@ -40,27 +21,24 @@ use pocketmine\permission\PermissionManager; use pocketmine\player\Player; use pocketmine\plugin\PluginBase; -use pocketmine\utils\AssumptionFailedError; +use pocketmine\promise\Promise; +use pocketmine\promise\PromiseResolver; use pocketmine\utils\Config; use pocketmine\utils\TextFormat as TF; use pocketmine\world\biome\Biome; -use pocketmine\world\biome\BiomeRegistry; use pocketmine\world\format\Chunk; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\Position; -use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; +use SOFe\Capital\Capital; -class MyPlot extends PluginBase -{ +final class MyPlot extends PluginBase{ private static MyPlot $instance; - /** @var PlotLevelSettings[] $levels */ - private array $levels = []; - private DataProvider $dataProvider; - private ?EconomyProvider $economyProvider = null; - private Language $Language; + private Language $language; + private InternalAPI $internalAPI; + private ?EconomyWrapper $economyProvider = null; - public static function getInstance() : self { + public static function getInstance() : self{ return self::$instance; } @@ -71,8 +49,8 @@ public static function getInstance() : self { * * @return Language */ - public function getLanguage() : Language { - return $this->Language; + public function getLanguage() : Language{ + return $this->language; } /** @@ -82,67 +60,80 @@ public function getLanguage() : Language { * * @return Language */ - public function getFallBackLang() : Language { + public function getFallBackLang() : Language{ return new Language(Language::FALLBACK_LANGUAGE, $this->getFile() . "resources/"); } /** - * Returns the DataProvider that is being used + * Returns the EconomyWrapper instance which is used to access the economy provider * * @api * - * @return DataProvider + * @return EconomyWrapper|null */ - public function getProvider() : DataProvider { - return $this->dataProvider; + public function getEconomyProvider() : ?EconomyWrapper{ + return $this->economyProvider; } /** - * Returns the EconomyProvider that is being used + * Allows setting the economy provider to a custom provider or to null to disable economy mode * * @api * - * @return EconomyProvider|null + * @param bool $enable */ - public function getEconomyProvider() : ?EconomyProvider { - return $this->economyProvider; + public function toggleEconomy(bool $enable) : void{ + if(!$enable){ + $this->getLogger()->info("Economy mode has been disabled via API"); + $this->internalAPI->setEconomyProvider(null); + $this->economyProvider = null; + $this->getConfig()->set("UseEconomy", false); + }else{ + $this->getLogger()->info("Economy mode has been enabled via API"); + $this->internalAPI->setEconomyProvider($this->checkEconomy()); + } } /** - * Allows setting the economy provider to a custom provider or to null to disable economy mode + * Returns the PlotLevelSettings of all the loaded Worlds * * @api * - * @param EconomyProvider|null $provider + * @return PlotLevelSettings[] */ - public function setEconomyProvider(?EconomyProvider $provider) : void { - if($provider === null) { - $this->getConfig()->set("UseEconomy", false); - $this->getLogger()->info("Economy mode disabled!"); - }else{ - $this->getLogger()->info("A custom economy provider has been registered. Economy mode now enabled!"); - $this->getConfig()->set("UseEconomy", true); - $this->economyProvider = $provider; - } + public function getAllLevelSettings() : array{ + return $this->internalAPI->getAllLevelSettings(); } /** - * Returns a PlotLevelSettings object which contains all the settings of a level + * Returns a PlotLevelSettings object which contains all the settings of a world * * @api * * @param string $levelName * - * @return PlotLevelSettings + * @return PlotLevelSettings|null + */ + public function getLevelSettings(string $levelName) : ?PlotLevelSettings{ + return $this->internalAPI->getLevelSettings($levelName); + } + + /** + * Registers a new PlotLevelSettings object to the loaded worlds list + * + * @api + * + * @param string $levelName + * @param PlotLevelSettings $settings + * + * @return void */ - public function getLevelSettings(string $levelName) : PlotLevelSettings { - if(!isset($this->levels[$levelName])) - throw new AssumptionFailedError("Provided level name is not a MyPlot level"); - return $this->levels[$levelName]; + public function addLevelSettings(string $levelName, PlotLevelSettings $settings) : void{ + $this->internalAPI->addLevelSettings($levelName, $settings); } /** - * Checks if a plot level is loaded + * Unregisters a PlotLevelSettings object from the loaded worlds list * * @api * @@ -150,8 +141,8 @@ public function getLevelSettings(string $levelName) : PlotLevelSettings { * * @return bool */ - public function isLevelLoaded(string $levelName) : bool { - return isset($this->levels[$levelName]); + public function unloadLevelSettings(string $levelName) : bool{ + return $this->internalAPI->unloadLevelSettings($levelName); } /** @@ -159,27 +150,27 @@ public function isLevelLoaded(string $levelName) : bool { * * @api * - * @param string $levelName - * @param string $generator + * @param string $levelName + * @param string $generator * @param mixed[] $settings * * @return bool */ - public function generateLevel(string $levelName, string $generator = MyPlotGenerator::NAME, array $settings = []) : bool { + public function generateLevel(string $levelName, string $generator = MyPlotGenerator::NAME, array $settings = []) : bool{ $ev = new MyPlotGenerationEvent($levelName, $generator, $settings); $ev->call(); - if($ev->isCancelled() or $this->getServer()->getWorldManager()->isWorldGenerated($levelName)) { + if($ev->isCancelled() or $this->getServer()->getWorldManager()->isWorldGenerated($levelName)){ return false; } $generator = GeneratorManager::getInstance()->getGenerator($generator); - if(count($settings) === 0) { + if(count($settings) === 0){ $this->getConfig()->reload(); $settings = $this->getConfig()->get("DefaultWorld", []); } - $default = array_filter((array) $this->getConfig()->get("DefaultWorld", []), function($key) : bool { + $default = array_filter((array) $this->getConfig()->get("DefaultWorld", []), function($key) : bool{ return !in_array($key, ["PlotSize", "GroundHeight", "RoadWidth", "RoadBlock", "WallBlock", "PlotFloorBlock", "PlotFillBlock", "BottomBlock"], true); }, ARRAY_FILTER_USE_KEY); - new Config($this->getDataFolder()."worlds".DIRECTORY_SEPARATOR.$levelName.".yml", Config::YAML, $default); + new Config($this->getDataFolder() . "worlds" . DIRECTORY_SEPARATOR . $levelName . ".yml", Config::YAML, $default); $return = $this->getServer()->getWorldManager()->generateWorld($levelName, WorldCreationOptions::create()->setGeneratorClass($generator->getGeneratorClass())->setGeneratorOptions(json_encode($settings)), true); $level = $this->getServer()->getWorldManager()->getWorldByName($levelName); $level?->setSpawnLocation(new Vector3(0, $this->getConfig()->getNested("DefaultWorld.GroundHeight", 64) + 1, 0)); @@ -191,12 +182,19 @@ public function generateLevel(string $levelName, string $generator = MyPlotGener * * @api * - * @param Plot $plot + * @param SinglePlot $plot * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function savePlot(Plot $plot) : bool { - return $this->dataProvider->savePlot($plot); + public function savePlot(SinglePlot $plot) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->savePlot( + $plot, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -204,13 +202,21 @@ public function savePlot(Plot $plot) : bool { * * @api * - * @param string $username - * @param string $levelName + * @param string $username + * @param string|null $levelName * - * @return Plot[] + * @return Promise + * @phpstan-return Promise> */ - public function getPlotsOfPlayer(string $username, string $levelName) : array { - return $this->dataProvider->getPlotsByOwner($username, $levelName); + public function getPlotsOfPlayer(string $username, ?string $levelName = null) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->getPlotsOfPlayer( + $username, + $levelName, + fn(array $plots) => $resolver->resolve($plots), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -219,87 +225,68 @@ public function getPlotsOfPlayer(string $username, string $levelName) : array { * @api * * @param string $levelName - * @param int $limitXZ + * @param int $limitXZ + * + * @return Promise + * @phpstan-return Promise + */ + public function getNextFreePlot(string $levelName, int $limitXZ = 0) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->getNextFreePlot( + $levelName, + $limitXZ, + fn(?SinglePlot $plot) => $resolver->resolve($plot), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); + } + + /** + * @param string $levelName + * @param int $X + * @param int $Z * - * @return Plot|null + * @return Promise */ - public function getNextFreePlot(string $levelName, int $limitXZ = 0) : ?Plot { - return $this->dataProvider->getNextFreePlot($levelName, $limitXZ); + public function getPlot(string $levelName, int $X, int $Z) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->getPlot( + new BasePlot($levelName, $X, $Z), + fn(?SinglePlot $plot) => $resolver->resolve($plot), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** - * Finds the plot at a certain position or null if there is no plot at that position - * - * @api - * - * @param Position $position + * @param float &$x + * @param float &$z + * @param PlotLevelSettings $plotLevel * - * @return Plot|null + * @return BasePlot|null */ - public function getPlotByPosition(Position $position) : ?Plot { - $x = $position->x; - $z = $position->z; - $levelName = $position->getWorld()->getFolderName(); - if(!$this->isLevelLoaded($levelName)) - return null; - $plotLevel = $this->getLevelSettings($levelName); - - $plot = $this->getPlotFast($x, $z, $plotLevel); - if($plot instanceof Plot) - return $this->dataProvider->getMergeOrigin($plot); - - if(!($basePlot = $this->dataProvider->getPlot($levelName, $x, $z))->isMerged()) - return null; - - // no plot found at current location yet, so search cardinal directions - $plotN = $basePlot->getSide(Facing::NORTH); - if($plotN->isSame($basePlot)) - return $this->dataProvider->getMergeOrigin($plotN); - - $plotS = $basePlot->getSide(Facing::SOUTH); - if($plotS->isSame($basePlot)) - return $this->dataProvider->getMergeOrigin($plotS); - - $plotE = $basePlot->getSide(Facing::EAST); - if($plotE->isSame($basePlot)) - return $this->dataProvider->getMergeOrigin($plotE); - - $plotW = $basePlot->getSide(Facing::WEST); - if($plotW->isSame($basePlot)) - return $this->dataProvider->getMergeOrigin($plotW); - - return null; + public function getPlotFast(float &$x, float &$z, PlotLevelSettings $plotLevel) : ?BasePlot{ + return $this->internalAPI->getPlotFast($x, $z, $plotLevel); } /** - * @param float $x - * @param float $z - * @param PlotLevelSettings $plotLevel + * Finds the plot at a certain position or null if there is no plot at that position + * + * @api * - * @return Plot|null + * @param Position $position + * + * @return Promise + * @phpstan-return Promise */ - private function getPlotFast(float &$x, float &$z, PlotLevelSettings $plotLevel) : ?Plot { - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $totalSize = $plotSize + $roadWidth; - if($x >= 0) { - $difX = $x % $totalSize; - $x = (int) floor($x / $totalSize); - }else{ - $difX = abs(($x - $plotSize + 1) % $totalSize); - $x = (int) ceil(($x - $plotSize + 1) / $totalSize); - } - if($z >= 0) { - $difZ = $z % $totalSize; - $z = (int) floor($z / $totalSize); - }else{ - $difZ = abs(($z - $plotSize + 1) % $totalSize); - $z = (int) ceil(($z - $plotSize + 1) / $totalSize); - } - if(($difX > $plotSize - 1) or ($difZ > $plotSize - 1)) - return null; - - return $this->dataProvider->getPlot($plotLevel->name, $x, $z); + public function getPlotByPosition(Position $position) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->getPlotByPosition( + $position, + fn(?SinglePlot $plot) => $resolver->resolve($plot), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -307,26 +294,12 @@ private function getPlotFast(float &$x, float &$z, PlotLevelSettings $plotLevel) * * @api * - * @param Plot $plot - * @param bool $mergeOrigin + * @param BasePlot $plot * * @return Position */ - public function getPlotPosition(Plot $plot, bool $mergeOrigin = true) : Position { - $plotLevel = $this->getLevelSettings($plot->levelName); - $origin = $this->dataProvider->getMergeOrigin($plot); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $totalSize = $plotSize + $roadWidth; - if ($mergeOrigin) { - $x = $totalSize * $origin->X; - $z = $totalSize * $origin->Z; - } else { - $x = $totalSize * $plot->X; - $z = $totalSize * $plot->Z; - } - $level = $this->getServer()->getWorldManager()->getWorldByName($plot->levelName); - return new Position($x, $plotLevel->groundHeight, $z, $level); + public function getPlotPosition(BasePlot $plot) : Position{ + return $this->internalAPI->getPlotPosition($plot); } /** @@ -338,67 +311,8 @@ public function getPlotPosition(Plot $plot, bool $mergeOrigin = true) : Position * * @return bool */ - public function isPositionBorderingPlot(Position $position) : bool { - if(!$position->isValid()) - return false; - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - $pos = $position->getSide($i); - $x = $pos->x; - $z = $pos->z; - $levelName = $pos->getWorld()->getFolderName(); - - if(!$this->isLevelLoaded($levelName)) - return false; - - $plotLevel = $this->getLevelSettings($levelName); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $totalSize = $plotSize + $roadWidth; - if($x >= 0) { - $difX = $x % $totalSize; - }else{ - $difX = abs(($x - $plotSize + 1) % $totalSize); - } - if($z >= 0) { - $difZ = $z % $totalSize; - }else{ - $difZ = abs(($z - $plotSize + 1) % $totalSize); - } - if(($difX > $plotSize - 1) or ($difZ > $plotSize - 1)) { - continue; - } - return true; - } - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - for($n = Facing::NORTH; $n <= Facing::EAST; ++$n) { - if($i === $n or Facing::opposite($i) === $n) - continue; - $pos = $position->getSide($i)->getSide($n); - $x = $pos->x; - $z = $pos->z; - $levelName = $pos->getWorld()->getFolderName(); - - $plotLevel = $this->getLevelSettings($levelName); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $totalSize = $plotSize + $roadWidth; - if($x >= 0) { - $difX = $x % $totalSize; - }else{ - $difX = abs(($x - $plotSize + 1) % $totalSize); - } - if($z >= 0) { - $difZ = $z % $totalSize; - }else{ - $difZ = abs(($z - $plotSize + 1) % $totalSize); - } - if(($difX > $plotSize - 1) or ($difZ > $plotSize - 1)) { - continue; - } - return true; - } - } - return false; + public function isPositionBorderingPlot(Position $position) : bool{ + return $this->internalAPI->isPositionBorderingPlot($position); } /** @@ -408,47 +322,10 @@ public function isPositionBorderingPlot(Position $position) : bool { * * @param Position $position * - * @return Plot|null + * @return BasePlot|null */ - public function getPlotBorderingPosition(Position $position) : ?Plot { - if(!$position->isValid()) - return null; - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - $pos = $position->getSide($i); - $x = $pos->x; - $z = $pos->z; - $levelName = $pos->getWorld()->getFolderName(); - - if(!$this->isLevelLoaded($levelName)) - return null; - - $plotLevel = $this->getLevelSettings($levelName); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $totalSize = $plotSize + $roadWidth; - if($x >= 0) { - $X = (int) floor($x / $totalSize); - $difX = $x % $totalSize; - }else{ - $X = (int) ceil(($x - $plotSize + 1) / $totalSize); - $difX = abs(($x - $plotSize + 1) % $totalSize); - } - if($z >= 0) { - $Z = (int) floor($z / $totalSize); - $difZ = $z % $totalSize; - }else{ - $Z = (int) ceil(($z - $plotSize + 1) / $totalSize); - $difZ = abs(($z - $plotSize + 1) % $totalSize); - } - if(($difX > $plotSize - 1) or ($difZ > $plotSize - 1)) { - if($this->getPlotByPosition($pos) instanceof Plot) { - return $this->getPlotByPosition($pos); - } - continue; - } - return $this->dataProvider->getPlot($levelName, $X, $Z); - } - return null; + public function getPlotBorderingPosition(Position $position) : ?BasePlot{ + return $this->internalAPI->getPlotBorderingPosition($position); } /** @@ -456,186 +333,51 @@ public function getPlotBorderingPosition(Position $position) : ?Plot { * * @api * - * @param Plot $plot + * @param BasePlot $plot * * @return AxisAlignedBB */ - public function getPlotBB(Plot $plot) : AxisAlignedBB { - $plotLevel = $this->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize-1; - $pos = $this->getPlotPosition($plot, false); - $xMax = (int)($pos->x + $plotSize); - $zMax = (int)($pos->z + $plotSize); - foreach ($this->dataProvider->getMergedPlots($plot) as $mergedPlot){ - $xplot = $this->getPlotPosition($mergedPlot, false)->x; - $zplot = $this->getPlotPosition($mergedPlot, false)->z; - $xMaxPlot = (int)($xplot + $plotSize); - $zMaxPlot = (int)($zplot + $plotSize); - if($pos->x > $xplot) $pos->x = $xplot; - if($pos->z > $zplot) $pos->z = $zplot; - if($xMax < $xMaxPlot) $xMax = $xMaxPlot; - if($zMax < $zMaxPlot) $zMax = $zMaxPlot; - } - - return new AxisAlignedBB( - min($pos->x, $xMax), - 0, - min($pos->z, $zMax), - max($pos->x, $xMax), - $pos->getWorld()->getMaxY(), - max($pos->z, $zMax) - ); + public function getPlotBB(BasePlot $plot) : AxisAlignedBB{ + return $this->internalAPI->getPlotBB($plot); } /** - * @param Plot $plot The plot that is to be expanded - * @param int $direction The Vector3 direction value to expand towards - * @param int $maxBlocksPerTick - * - * @return bool - * @throws \Exception - */ - public function mergePlots(Plot $plot, int $direction, int $maxBlocksPerTick = 256) : bool { - if (!$this->isLevelLoaded($plot->levelName)) - return false; - /** @var Plot[][] $toMerge */ - $toMerge = []; - $mergedPlots = $this->getProvider()->getMergedPlots($plot); - $newPlot = $plot->getSide($direction); - $alreadyMerged = false; - foreach ($mergedPlots as $mergedPlot) { - if ($mergedPlot->isSame($newPlot)) { - $alreadyMerged = true; - } - } - if ($alreadyMerged === false and $newPlot->isMerged()) { - $this->getLogger()->debug("Failed to merge due to plot origin mismatch"); - return false; - } - $toMerge[] = [$plot, $newPlot]; - - foreach ($mergedPlots as $mergedPlot) { - $newPlot = $mergedPlot->getSide($direction); - $alreadyMerged = false; - foreach ($mergedPlots as $mergedPlot2) { - if ($mergedPlot2->isSame($newPlot)) { - $alreadyMerged = true; - } - } - if ($alreadyMerged === false and $newPlot->isMerged()) { - $this->getLogger()->debug("Failed to merge due to plot origin mismatch"); - return false; - } - $toMerge[] = [$mergedPlot, $newPlot]; - } - /** @var Plot[][] $toFill */ - $toFill = []; - foreach ($toMerge as $pair) { - foreach ($toMerge as $pair2) { - for ($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - if ($pair[1]->getSide($i)->isSame($pair2[1])) { - $toFill[] = [$pair[1], $pair2[1]]; - } - } - } - } - $ev = new MyPlotMergeEvent($this->getProvider()->getMergeOrigin($plot), $toMerge); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - foreach ($toMerge as $pair) { - if ($pair[1]->owner === "") { - $this->getLogger()->debug("Failed to merge due to plot not claimed"); - return false; - } elseif ($plot->owner !== $pair[1]->owner) { - $this->getLogger()->debug("Failed to merge due to owner mismatch"); - return false; - } - } - - // TODO: WorldStyler clearing - - foreach ($toMerge as $pair) - $this->getScheduler()->scheduleTask(new RoadFillTask($this, $pair[0], $pair[1], false, -1, $maxBlocksPerTick)); - - foreach ($toFill as $pair) - $this->getScheduler()->scheduleTask(new RoadFillTask($this, $pair[0], $pair[1], true, $direction, $maxBlocksPerTick)); - - return $this->getProvider()->mergePlots($this->getProvider()->getMergeOrigin($plot), ...array_map(function (array $val) : Plot { - return $val[1]; - }, $toMerge)); - } - - /** - * Teleport a player to a plot + * TODO: description * * @api * - * @param Player $player - * @param Plot $plot - * @param bool $center + * @param SinglePlot $plot The plot that is to be expanded + * @param int $direction The Vector3 direction value to expand towards + * @param int $maxBlocksPerTick * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function teleportPlayerToPlot(Player $player, Plot $plot, bool $center = false) : bool { - $ev = new MyPlotTeleportEvent($plot, $player, $center); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - if($plot->isMerged()){ - return $this->teleportPlayerToMerge($player, $plot, $center); - } - if($center) - return $this->teleportMiddle($player, $plot); - $plotLevel = $this->getLevelSettings($plot->levelName); - $pos = $this->getPlotPosition($plot); - $pos->x += floor($plotLevel->plotSize / 2); - $pos->y += 1.5; - $pos->z -= 1; - return $player->teleport($pos); + public function mergePlots(SinglePlot $plot, int $direction, int $maxBlocksPerTick = 256) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->mergePlots( + $plot, + $direction, + $maxBlocksPerTick, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** - * Teleport a player to a Merge + * Teleport a player to a plot * * @api * - * @param Player $player - * @param Plot $plot - * @param bool $center + * @param Player $player + * @param SinglePlot $plot + * @param bool $center * * @return bool */ - public function teleportPlayerToMerge(Player $player, Plot $plot, bool $center = false) : bool { - $ev = new MyPlotTeleportEvent($plot, $player, $center); - $ev->call(); - if ($ev->isCancelled()) { - return false; - } - if(!$plot->isMerged()){ - $this->teleportPlayerToPlot($player, $plot, $center); - } - if ($center) - return $this->teleportMiddle($player, $plot); - $plotLevel = $this->getLevelSettings($plot->levelName); - $mergedPlots = $this->getProvider()->getMergedPlots($plot); - $minx = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->x < $this->getPlotPosition($b, false)->x ? $a : $b; - }, $mergedPlots[0]), false)->x; - $maxx = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->x > $this->getPlotPosition($b, false)->x ? $a : $b; - }, $mergedPlots[0]), false)->x + $plotLevel->plotSize; - $minz = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->z < $this->getPlotPosition($b, false)->z ? $a : $b; - }, $mergedPlots[0]), false)->z; - - $pos = new Position($minx,$plotLevel->groundHeight, $minz, $this->getServer()->getWorldManager()->getWorldByName($plot->levelName)); - $pos->x = floor(($minx + $maxx) / 2); - $pos->y += 1.5; - $pos->z -= 1; - return $player->teleport($pos); + public function teleportPlayerToPlot(Player $player, BasePlot $plot, bool $center = false) : bool{ + return $this->internalAPI->teleportPlayerToPlot($player, $plot, $center); } /** @@ -643,33 +385,23 @@ public function teleportPlayerToMerge(Player $player, Plot $plot, bool $center = * * @api * - * @param Plot $plot - * @param string $claimer - * @param string $plotName + * @param SinglePlot $plot + * @param string $claimer + * @param string $plotName * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function claimPlot(Plot $plot, string $claimer, string $plotName = "") : bool { - $newPlot = clone $plot; - $newPlot->owner = $claimer; - $newPlot->price = 0.0; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plot = $ev->getPlot(); - $failed = false; - foreach($this->getProvider()->getMergedPlots($plot) as $merged) { - if($plotName !== "") { - $this->renamePlot($merged, $plotName); - } - $merged->owner = $claimer; - $merged->price = 0.0; - if(!$this->savePlot($merged)) - $failed = true; - } - return !$failed; + public function claimPlot(SinglePlot $plot, string $claimer, string $plotName = "") : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->claimPlot( + $plot, + $claimer, + $plotName, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -677,20 +409,21 @@ public function claimPlot(Plot $plot, string $claimer, string $plotName = "") : * * @api * - * @param Plot $plot - * @param string $newName + * @param SinglePlot $plot + * @param string $newName * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function renamePlot(Plot $plot, string $newName = "") : bool { - $newPlot = clone $plot; - $newPlot->name = $newName; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + public function renamePlot(SinglePlot $plot, string $newName = "") : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->renamePlot( + $plot, + $newName, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -698,95 +431,13 @@ public function renamePlot(Plot $plot, string $newName = "") : bool { * * @api * - * @param Plot $plotFrom - * @param Plot $plotTo + * @param SinglePlot $plotFrom + * @param SinglePlot $plotTo * * @return bool */ - public function clonePlot(Plot $plotFrom, Plot $plotTo) : bool { - $styler = $this->getServer()->getPluginManager()->getPlugin("WorldStyler"); - if(!$styler instanceof WorldStyler) { - return false; - } - if(!$this->isLevelLoaded($plotFrom->levelName) or !$this->isLevelLoaded($plotTo->levelName)) { - return false; - } - $world = $this->getServer()->getWorldManager()->getWorldByName($plotTo->levelName); - $aabb = $this->getPlotBB($plotTo); - foreach($world->getEntities() as $entity) { - if($aabb->isVectorInXZ($entity->getPosition())) { - if($entity instanceof Player){ - $this->teleportPlayerToPlot($entity, $plotTo); - } - } - } - $ev = new MyPlotCloneEvent($plotFrom, $plotTo); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plotFrom = $ev->getPlot(); - $plotTo = $ev->getClonePlot(); - if(!$this->isLevelLoaded($plotFrom->levelName) or !$this->isLevelLoaded($plotTo->levelName)) { - return false; - } - $plotLevel = $this->getLevelSettings($plotFrom->levelName); - $plotSize = $plotLevel->plotSize-1; - $plotBeginPos = $this->getPlotPosition($plotFrom); - $level = $plotBeginPos->getWorld(); - $plotBeginPos = $plotBeginPos->subtract(1, 0, 1); - $plotBeginPos->y = 0; - $xMax = (int)($plotBeginPos->x + $plotSize); - $zMax = (int)($plotBeginPos->z + $plotSize); - foreach ($this->getProvider()->getMergedPlots($plotFrom) as $mergedPlot){ - $pos = $this->getPlotPosition($mergedPlot, false)->subtract(1,0,1); - $xMaxPlot = (int)($pos->x + $plotSize); - $zMaxPlot = (int)($pos->z + $plotSize); - if($plotBeginPos->x > $pos->x) $plotBeginPos->x = $pos->x; - if($plotBeginPos->z > $pos->z) $plotBeginPos->z = $pos->z; - if($xMax < $xMaxPlot) $xMax = $xMaxPlot; - if($zMax < $zMaxPlot) $zMax = $zMaxPlot; - } - $selection = $styler->getSelection(99997) ?? new Selection(99997); - $selection->setPosition(1, $plotBeginPos); - $vec2 = new Vector3($xMax + 1, $level->getMaxY() - 1, $zMax + 1); - $selection->setPosition(2, $vec2); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); // do not use async because WorldStyler async is very broken right now - $cuboid->copy($level, $vec2, function (float $time, int $changed) : void { - $this->getLogger()->debug(TF::GREEN . 'Copied ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's to the MyPlot clipboard.'); - }); - - $plotLevel = $this->getLevelSettings($plotTo->levelName); - $plotSize = $plotLevel->plotSize-1; - $plotBeginPos = $this->getPlotPosition($plotTo); - $level = $plotBeginPos->getWorld(); - $plotBeginPos = $plotBeginPos->subtract(1, 0, 1); - $plotBeginPos->y = 0; - $xMax = (int)($plotBeginPos->x + $plotSize); - $zMax = (int)($plotBeginPos->z + $plotSize); - foreach ($this->getProvider()->getMergedPlots($plotTo) as $mergedPlot){ - $pos = $this->getPlotPosition($mergedPlot, false)->subtract(1,0,1); - $xMaxPlot = (int)($pos->x + $plotSize); - $zMaxPlot = (int)($pos->z + $plotSize); - if($plotBeginPos->x > $pos->x) $plotBeginPos->x = $pos->x; - if($plotBeginPos->z > $pos->z) $plotBeginPos->z = $pos->z; - if($xMax < $xMaxPlot) $xMax = $xMaxPlot; - if($zMax < $zMaxPlot) $zMax = $zMaxPlot; - } - $selection->setPosition(1, $plotBeginPos); - $vec2 = new Vector3($xMax + 1, $level->getMaxY() - 1, $zMax + 1); - $selection->setPosition(2, $vec2); - $commonShape = CommonShape::fromSelection($selection); - //$commonShape = $commonShape->async(); // do not use async because WorldStyler async is very broken right now - $commonShape->paste($level, $vec2, true, function (float $time, int $changed) : void { - $this->getLogger()->debug(TF::GREEN . 'Pasted ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's from the MyPlot clipboard.'); - }); - $styler->removeSelection(99997); - foreach($this->getPlotChunks($plotTo) as [$chunkX, $chunkZ, $chunk]) { - $level->setChunk($chunkX, $chunkZ, $chunk); - } - return true; + public function clonePlot(SinglePlot $plotFrom, SinglePlot $plotTo) : bool{ + return $this->internalAPI->clonePlot($plotFrom, $plotTo); } /** @@ -794,106 +445,13 @@ public function clonePlot(Plot $plotFrom, Plot $plotTo) : bool { * * @api * - * @param Plot $plot - * @param int $maxBlocksPerTick + * @param BasePlot $plot + * @param int $maxBlocksPerTick * * @return bool */ - public function clearPlot(Plot $plot, int $maxBlocksPerTick = 256) : bool { - $ev = new MyPlotClearEvent($plot, $maxBlocksPerTick); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plot = $ev->getPlot(); - if(!$this->isLevelLoaded($plot->levelName)) { - return false; - } - $maxBlocksPerTick = $ev->getMaxBlocksPerTick(); - $level = $this->getServer()->getWorldManager()->getWorldByName($plot->levelName); - if($level === null) - return false; - foreach($level->getEntities() as $entity) { - if($this->getPlotBB($plot)->isVectorInXZ($entity->getPosition())) { - if(!$entity instanceof Player) { - $entity->flagForDespawn(); - }else{ - $this->teleportPlayerToPlot($entity, $plot); - } - } - } - if($this->getConfig()->get("FastClearing", false) === true) { - $styler = $this->getServer()->getPluginManager()->getPlugin("WorldStyler"); - if(!$styler instanceof WorldStyler) { - return false; - } - $plotLevel = $this->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize-1; - $plotBeginPos = $this->getPlotPosition($plot); - $xMax = (int)($plotBeginPos->x + $plotSize); - $zMax = (int)($plotBeginPos->z + $plotSize); - foreach ($this->getProvider()->getMergedPlots($plot) as $mergedPlot){ - $xplot = $this->getPlotPosition($mergedPlot, false)->x; - $zplot = $this->getPlotPosition($mergedPlot, false)->z; - $xMaxPlot = (int)($xplot + $plotSize); - $zMaxPlot = (int)($zplot + $plotSize); - if($plotBeginPos->x > $xplot) $plotBeginPos->x = $xplot; - if($plotBeginPos->z > $zplot) $plotBeginPos->z = $zplot; - if($xMax < $xMaxPlot) $xMax = $xMaxPlot; - if($zMax < $zMaxPlot) $zMax = $zMaxPlot; - } - // Above ground - $selection = $styler->getSelection(99998) ?? new Selection(99998); - $plotBeginPos->y = $plotLevel->groundHeight+1; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($xMax, World::Y_MAX, $zMax)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), VanillaBlocks::AIR()->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - // Ground Surface - $selection = $styler->getSelection(99998) ?? new Selection(99998); - $plotBeginPos->y = $plotLevel->groundHeight; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($xMax, $plotLevel->groundHeight, $zMax)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), $plotLevel->plotFloorBlock->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - // Ground - $selection = $styler->getSelection(99998) ?? new Selection(99998); - $plotBeginPos->y = 1; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($xMax, $plotLevel->groundHeight-1, $zMax)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), $plotLevel->plotFillBlock->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - // Bottom of world - $selection = $styler->getSelection(99998) ?? new Selection(99998); - $plotBeginPos->y = 0; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($xMax, 0, $zMax)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), $plotLevel->bottomBlock->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]) { - $plotBeginPos->getWorld()->setChunk($chunkX, $chunkZ, $chunk); - } - $this->getScheduler()->scheduleDelayedTask(new ClearBorderTask($this, $plot), 1); - return true; - } - $this->getScheduler()->scheduleTask(new ClearPlotTask($this, $plot, $maxBlocksPerTick)); - return true; + public function clearPlot(BasePlot $plot, int $maxBlocksPerTick = 256) : bool{ + return $this->internalAPI->clearPlot($plot, $maxBlocksPerTick); } /** @@ -901,69 +459,18 @@ public function clearPlot(Plot $plot, int $maxBlocksPerTick = 256) : bool { * * @api * - * @param Plot $plot - * @param Block $plotFillBlock - * @param int $maxBlocksPerTick + * @param SinglePlot $plot + * @param Block $plotFillBlock + * @param int $maxBlocksPerTick * * @return bool */ - public function fillPlot(Plot $plot, Block $plotFillBlock, int $maxBlocksPerTick = 256) : bool { - $ev = new MyPlotFillEvent($plot, $maxBlocksPerTick); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plot = $ev->getPlot(); - if(!$this->isLevelLoaded($plot->levelName)) { - return false; - } - $maxBlocksPerTick = $ev->getMaxBlocksPerTick(); - foreach($this->getServer()->getWorldManager()->getWorldByName($plot->levelName)->getEntities() as $entity) { - if($this->getPlotBB($plot)->isVectorInXZ($entity->getPosition()) && $entity->getPosition()->y <= $this->getLevelSettings($plot->levelName)->groundHeight) { - if(!$entity instanceof Player) { - $entity->flagForDespawn(); - }else{ - $this->teleportPlayerToPlot($entity, $plot); - } - } - } - if($this->getConfig()->get("FastFilling", false) === true) { - $styler = $this->getServer()->getPluginManager()->getPlugin("WorldStyler"); - if(!$styler instanceof WorldStyler) { - return false; - } - $plotLevel = $this->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize-1; - $plotBeginPos = $this->getPlotPosition($plot); - // Ground - $selection = $styler->getSelection(99998); - $plotBeginPos->y = 1; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($plotBeginPos->x + $plotSize, $plotLevel->groundHeight, $plotBeginPos->z + $plotSize)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), $plotFillBlock->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - // Bottom of world - $selection = $styler->getSelection(99998); - $plotBeginPos->y = 0; - $selection->setPosition(1, $plotBeginPos); - $selection->setPosition(2, new Vector3($plotBeginPos->x + $plotSize, 0, $plotBeginPos->z + $plotSize)); - $cuboid = Cuboid::fromSelection($selection); - //$cuboid = $cuboid->async(); - $cuboid->set($plotBeginPos->getWorld(), $plotLevel->bottomBlock->getFullId(), function (float $time, int $changed) : void { - $this->getLogger()->debug('Set ' . number_format($changed) . ' blocks in ' . number_format($time, 10) . 's'); - }); - $styler->removeSelection(99998); - foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]) { - $plotBeginPos->getWorld()?->setChunk($chunkX, $chunkZ, $chunk); - } - return true; - } - $this->getScheduler()->scheduleTask(new FillPlotTask($this, $plot, $plotFillBlock, $maxBlocksPerTick)); - return true; + public function fillPlot(BasePlot $plot, Block $plotFillBlock, int $maxBlocksPerTick = 256) : bool{ + return $this->internalAPI->fillPlot( + $plot, + $plotFillBlock, + $maxBlocksPerTick + ); } /** @@ -971,17 +478,19 @@ public function fillPlot(Plot $plot, Block $plotFillBlock, int $maxBlocksPerTick * * @api * - * @param Plot $plot + * @param SinglePlot $plot * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function disposePlot(Plot $plot) : bool { - $ev = new MyPlotDisposeEvent($plot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->getProvider()->deletePlot($plot); + public function disposePlot(SinglePlot $plot) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->disposePlot( + $plot, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -989,20 +498,21 @@ public function disposePlot(Plot $plot) : bool { * * @api * - * @param Plot $plot - * @param int $maxBlocksPerTick + * @param SinglePlot $plot + * @param int $maxBlocksPerTick * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function resetPlot(Plot $plot, int $maxBlocksPerTick = 256) : bool { - $ev = new MyPlotResetEvent($plot); - $ev->call(); - if($ev->isCancelled()) - return false; - if($this->disposePlot($plot)) { - return $this->clearPlot($plot, $maxBlocksPerTick); - } - return false; + public function resetPlot(SinglePlot $plot, int $maxBlocksPerTick = 256) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->resetPlot( + $plot, + $maxBlocksPerTick, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -1010,173 +520,175 @@ public function resetPlot(Plot $plot, int $maxBlocksPerTick = 256) : bool { * * @api * - * @param Plot $plot - * @param Biome $biome + * @param SinglePlot $plot + * @param Biome $biome * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function setPlotBiome(Plot $plot, Biome $biome) : bool { - $newPlot = clone $plot; - $newPlot->biome = str_replace(" ", "_", strtoupper($biome->getName())); - $ev = new MyPlotSettingEvent($plot, $newPlot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plot = $ev->getPlot(); - if(defined(BiomeIds::class."::".$plot->biome) and is_int(constant(BiomeIds::class."::".$plot->biome))) { - $biome = constant(BiomeIds::class."::".$plot->biome); - }else{ - $biome = BiomeIds::PLAINS; - } - $biome = BiomeRegistry::getInstance()->getBiome($biome); - if(!$this->isLevelLoaded($plot->levelName)) - return false; - $failed = false; - foreach($this->getProvider()->getMergedPlots($plot) as $merged) { - $merged->biome = $plot->biome; - if(!$this->savePlot($merged)) - $failed = true; - } - $plotLevel = $this->getLevelSettings($plot->levelName); - $level = $this->getServer()->getWorldManager()->getWorldByName($plot->levelName); - if($level === null) - return false; - foreach($this->getPlotChunks($plot) as [$chunkX, $chunkZ, $chunk]) { - for($x = 0; $x < 16; ++$x) { - for($z = 0; $z < 16; ++$z) { - $chunkPlot = $this->getPlotByPosition(new Position(($chunkX << 4) + $x, $plotLevel->groundHeight, ($chunkZ << 4) + $z, $level)); - if($chunkPlot instanceof Plot and $chunkPlot->isSame($plot)) { - $chunk->setBiomeId($x, $z, $biome->getId()); - } - } - } - $level->setChunk($chunkX, $chunkZ, $chunk); - } - return !$failed; - } - - public function setPlotPvp(Plot $plot, bool $pvp) : bool { - $newPlot = clone $plot; - $newPlot->pvp = $pvp; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + public function setPlotBiome(SinglePlot $plot, Biome $biome) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->setPlotBiome( + $plot, + $biome, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } - public function addPlotHelper(Plot $plot, string $player) : bool { - $newPlot = clone $plot; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $newPlot->addHelper($player) ? $ev->uncancel() : $ev->cancel(); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + /** + * TODO: description + * + * @api + * + * @param SinglePlot $plot + * @param bool $pvp + * + * @return Promise + * @phpstan-return Promise + */ + public function setPlotPvp(SinglePlot $plot, bool $pvp) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->setPlotPvp( + $plot, + $pvp, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } - public function removePlotHelper(Plot $plot, string $player) : bool { - $newPlot = clone $plot; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $newPlot->removeHelper($player) ? $ev->uncancel() : $ev->cancel(); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + /** + * TODO: description + * + * @api + * + * @param SinglePlot $plot + * @param string $player + * + * @return Promise + * @phpstan-return Promise + */ + public function addPlotHelper(SinglePlot $plot, string $player) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->addPlotHelper( + $plot, + $player, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } - public function addPlotDenied(Plot $plot, string $player) : bool { - $newPlot = clone $plot; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $newPlot->denyPlayer($player) ? $ev->uncancel() : $ev->cancel(); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + /** + * TODO: description + * + * @api + * + * @param SinglePlot $plot + * @param string $player + * + * @return Promise + * @phpstan-return Promise + */ + public function removePlotHelper(SinglePlot $plot, string $player) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->removePlotHelper( + $plot, + $player, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } - public function removePlotDenied(Plot $plot, string $player) : bool { - $newPlot = clone $plot; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $newPlot->unDenyPlayer($player) ? $ev->uncancel() : $ev->cancel(); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - return $this->savePlot($ev->getPlot()); + /** + * TODO: description + * + * @api + * + * @param SinglePlot $plot + * @param string $player + * + * @return Promise + * @phpstan-return Promise + */ + public function addPlotDenied(SinglePlot $plot, string $player) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->addPlotDenied( + $plot, + $player, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** - * Assigns a price to a plot + * TODO: description * * @api * - * @param Plot $plot - * @param float $price + * @param SinglePlot $plot + * @param string $player * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function sellPlot(Plot $plot, float $price) : bool { - if($this->getEconomyProvider() === null or $price < 0) - return false; - - $newPlot = clone $plot; - $newPlot->price = $price; - $ev = new MyPlotSettingEvent($plot, $newPlot); - $ev->call(); - if($ev->isCancelled()) { - return false; - } - $plot = $ev->getPlot(); - return $this->savePlot($plot); + public function removePlotDenied(SinglePlot $plot, string $player) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->removePlotDenied( + $plot, + $player, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** - * Resets the price, adds the money to the player's account and claims a plot in a players name + * Assigns a price to a plot * * @api * - * @param Plot $plot - * @param Player $player + * @param SinglePlot $plot + * @param int $price * - * @return bool + * @return Promise + * @phpstan-return Promise */ - public function buyPlot(Plot $plot, Player $player) : bool { - if($this->getEconomyProvider() === null or !$this->getEconomyProvider()->reduceMoney($player, $plot->price) or !$this->getEconomyProvider()->addMoney($this->getServer()->getOfflinePlayer($plot->owner), $plot->price)) - return false; - $failed = false; - foreach ($this->dataProvider->getMergedPlots($plot) as $mergedPlot) { - $newPlot = clone $mergedPlot; - $newPlot->owner = $player->getName(); - $newPlot->helpers = []; - $newPlot->denied = []; - $newPlot->price = 0.0; - $ev = new MyPlotSettingEvent($mergedPlot, $newPlot); - $ev->call(); - if ($ev->isCancelled()) { - return false; - } - $mergedPlot = $ev->getPlot(); - if($this->savePlot($mergedPlot)) - $failed = true; - } - return !$failed; + public function sellPlot(SinglePlot $plot, int $price) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->sellPlot( + $plot, + $price, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** - * Returns the PlotLevelSettings of all the loaded levels + * Resets the price, adds the money to the player's account and claims a plot in a players name * * @api * - * @return PlotLevelSettings[] + * @param SinglePlot $plot + * @param Player $player + * + * @return Promise + * @phpstan-return Promise */ - public function getPlotLevels() : array { - return $this->levels; + public function buyPlot(SinglePlot $plot, Player $player) : Promise{ + $resolver = new PromiseResolver(); + $this->internalAPI->buyPlot( + $plot, + $player, + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); } /** @@ -1184,30 +696,13 @@ public function getPlotLevels() : array { * * @api * - * @param Plot $plot + * @param SinglePlot $plot * - * @return array> + * @return array + * @phpstan-return array> */ - public function getPlotChunks(Plot $plot) : array { - if(!$this->isLevelLoaded($plot->levelName)) - return []; - $plotLevel = $this->getLevelSettings($plot->levelName); - $level = $this->getServer()->getWorldManager()->getWorldByName($plot->levelName); - if($level === null) - return []; - $plotSize = $plotLevel->plotSize; - $chunks = []; - foreach ($this->dataProvider->getMergedPlots($plot) as $mergedPlot){ - $pos = $this->getPlotPosition($mergedPlot, false); - $xMax = ($pos->x + $plotSize) >> 4; - $zMax = ($pos->z + $plotSize) >> 4; - for($x = $pos->x >> 4; $x <= $xMax; $x++) { - for($z = $pos->z >> 4; $z <= $zMax; $z++) { - $chunks[] = [$x, $z, $level->getChunk($x, $z)]; - } - } - } - return $chunks; + public function getPlotChunks(BasePlot $plot) : array{ + return $this->internalAPI->getPlotChunks($plot); } /** @@ -1219,228 +714,121 @@ public function getPlotChunks(Plot $plot) : array { * * @return int */ - public function getMaxPlotsOfPlayer(Player $player) : int { + public function getMaxPlotsOfPlayer(Player $player) : int{ if($player->hasPermission("myplot.claimplots.unlimited")) return PHP_INT_MAX; - $perms = array_map(fn(PermissionAttachmentInfo $attachment) => [$attachment->getPermission(), $attachment->getValue()], $player->getEffectivePermissions()); + $perms = array_map(fn(PermissionAttachmentInfo $attachment) => $attachment->getValue(), $player->getEffectivePermissions()); // outputs permission string => value $perms = array_merge(PermissionManager::getInstance()->getPermission(DefaultPermissions::ROOT_USER)->getChildren(), $perms); - $perms = array_filter($perms, function(string $name) : bool { + $perms = array_filter($perms, function(string $name) : bool{ return (str_starts_with($name, "myplot.claimplots.")); }, ARRAY_FILTER_USE_KEY); if(count($perms) === 0) return 0; krsort($perms, SORT_FLAG_CASE | SORT_NATURAL); /** - * @var string $name + * @var string $name * @var Permission $perm */ - foreach($perms as $name => $perm) { + foreach($perms as $name => $perm){ $maxPlots = substr($name, 18); - if(is_numeric($maxPlots)) { + if(is_numeric($maxPlots)){ return (int) $maxPlots; } } return 0; } - /** - * Finds the exact center of the plot at ground level - * - * @api - * - * @param Plot $plot - * - * @return Position|null - */ - public function getPlotMid(Plot $plot) : ?Position { - if(!$this->isLevelLoaded($plot->levelName)) - return null; - $plotLevel = $this->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize; - $pos = $this->getPlotPosition($plot); - return new Position($pos->x + ($plotSize / 2), $pos->y + 1, $pos->z + ($plotSize / 2), $pos->getWorld()); - } - - /** - * Finds the exact center of the Merge at ground level - * - * @api - * - * @param Plot $plot - * - * @return Position|null - */ - public function getMergeMid(Plot $plot) : ?Position { - $plotLevel = $this->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize; - $mergedPlots = $this->getProvider()->getMergedPlots($plot); - $minx = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->x < $this->getPlotPosition($b, false)->x ? $a : $b; - }, $mergedPlots[0]), false)->x; - $maxx = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->x > $this->getPlotPosition($b, false)->x ? $a : $b; - }, $mergedPlots[0]), false)->x + $plotSize; - $minz = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->z < $this->getPlotPosition($b, false)->z ? $a : $b; - }, $mergedPlots[0]), false)->z; - $maxz = $this->getPlotPosition(array_reduce($mergedPlots, function(Plot $a, Plot $b) : Plot { - return $this->getPlotPosition($a, false)->z > $this->getPlotPosition($b, false)->z ? $a : $b; - }, $mergedPlots[0]), false)->z + $plotSize; - return new Position(($minx + $maxx) / 2, $plotLevel->groundHeight, ($minz + $maxz) / 2, $this->getServer()->getWorldManager()->getWorldByName($plot->levelName)); - } + /* -------------------------- Non-API part -------------------------- */ - /** - * Teleports the player to the exact center of the plot at nearest open space to the ground level - * - * @internal - * - * @param Plot $plot - * @param Player $player - * - * @return bool - */ - private function teleportMiddle(Player $player, Plot $plot) : bool { - if($plot->isMerged()){ - $mid = $this->getMergeMid($plot); - }else { - $mid = $this->getPlotMid($plot); - } - if ($mid === null) { - return false; + private function checkEconomy() : InternalEconomySProvider{ + $this->getLogger()->debug(TF::BOLD . "Loading economy settings"); + $economyProvider = null; + if(($plugin = $this->getServer()->getPluginManager()->getPlugin("EconomyAPI")) !== null){ + if($plugin instanceof EconomyAPI){ + $economyProvider = new InternalEconomySProvider($plugin); + $this->getLogger()->info("Economy set to EconomyAPI"); + }else + $this->getLogger()->debug("Invalid instance of EconomyAPI"); + } + if(($plugin = $this->getServer()->getPluginManager()->getPlugin("BedrockEconomy")) !== null){ + if($plugin instanceof BedrockEconomy){ + $economyProvider = new InternalBedrockEconomyProvider(BedrockEconomyAPI::getInstance()); + $this->getLogger()->info("Economy set to BedrockEconomy"); + }else + $this->getLogger()->debug("Invalid instance of BedrockEconomy"); + } + if(($plugin = $this->getServer()->getPluginManager()->getPlugin("Capital")) !== null){ + if($plugin instanceof Capital){ + $economyProvider = new InternalCapitalProvider(); + $this->getLogger()->info("Economy set to Capital"); + }else + $this->getLogger()->debug("Invalid instance of Capital"); + } + if(!isset($economyProvider)){ + $this->getLogger()->warning("No supported economy plugin found!"); + $this->getConfig()->set("UseEconomy", false); + //$this->getConfig()->save(); + }else{ + $this->economyProvider = new EconomyWrapper($economyProvider); } - return $player->teleport($mid); + return $economyProvider; } - /* -------------------------- Non-API part -------------------------- */ - public function onLoad() : void { + public function onLoad() : void{ self::$instance = $this; + $this->getLogger()->debug(TF::BOLD . "Loading Configs"); $this->reloadConfig(); @mkdir($this->getDataFolder() . "worlds"); + $this->getLogger()->debug(TF::BOLD . "Loading MyPlot Generator"); GeneratorManager::getInstance()->addGenerator(MyPlotGenerator::class, "myplot", fn() => null, true); + $this->getLogger()->debug(TF::BOLD . "Loading Languages"); - // Loading Languages /** @var string $lang */ $lang = $this->getConfig()->get("Language", Language::FALLBACK_LANGUAGE); - if($this->getConfig()->get("Custom Messages", false) === true) { - if(!file_exists($this->getDataFolder()."lang.ini")) { + if($this->getConfig()->get("Custom Messages", false) === true){ + if(!file_exists($this->getDataFolder() . "lang.ini")){ /** @var string|resource $resource */ - $resource = $this->getResource($lang.".ini") ?? file_get_contents($this->getFile()."resources/".Language::FALLBACK_LANGUAGE.".ini"); - file_put_contents($this->getDataFolder()."lang.ini", $resource); - if(is_resource($resource)) { + $resource = $this->getResource($lang . ".ini") ?? file_get_contents($this->getFile() . "resources/" . Language::FALLBACK_LANGUAGE . ".ini"); + file_put_contents($this->getDataFolder() . "lang.ini", $resource); + if(is_resource($resource)){ fclose($resource); } - $this->saveResource(Language::FALLBACK_LANGUAGE.".ini", true); + $this->saveResource(Language::FALLBACK_LANGUAGE . ".ini", true); $this->getLogger()->debug("Custom Language ini created"); } - $this->Language = new Language("lang", $this->getDataFolder()); + $this->language = new Language("lang", $this->getDataFolder()); }else{ - if(file_exists($this->getDataFolder()."lang.ini")) { - unlink($this->getDataFolder()."lang.ini"); - unlink($this->getDataFolder().Language::FALLBACK_LANGUAGE.".ini"); + if(file_exists($this->getDataFolder() . "lang.ini")){ + unlink($this->getDataFolder() . "lang.ini"); + unlink($this->getDataFolder() . Language::FALLBACK_LANGUAGE . ".ini"); $this->getLogger()->debug("Custom Language ini deleted"); } - $this->Language = new Language($lang, $this->getFile() . "resources/"); + $this->language = new Language($lang, $this->getFile() . "resources/"); } - $this->getLogger()->debug(TF::BOLD . "Loading Data Provider settings"); - // Initialize DataProvider - /** @var int $cacheSize */ - $cacheSize = $this->getConfig()->get("PlotCacheSize", 256); - $dataProvider = $this->getConfig()->get("DataProvider", "sqlite3"); - if(!is_string($dataProvider)) - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - else - try { - switch(strtolower($dataProvider)) { - case "mysqli": - case "mysql": - if(extension_loaded("mysqli")) { - $settings = (array) $this->getConfig()->get("MySQLSettings"); - $this->dataProvider = new MySQLProvider($this, $cacheSize, $settings); - }else { - $this->getLogger()->warning("MySQLi is not installed in your php build! JSON will be used instead."); - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - } - break; - case "yaml": - if(extension_loaded("yaml")) { - $this->dataProvider = new ConfigDataProvider($this, $cacheSize, true); - }else { - $this->getLogger()->warning("YAML is not installed in your php build! JSON will be used instead."); - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - } - break; - case "sqlite3": - case "sqlite": - if(extension_loaded("sqlite3")) { - $this->dataProvider = new SQLiteDataProvider($this, $cacheSize); - }else { - $this->getLogger()->warning("SQLite3 is not installed in your php build! JSON will be used instead."); - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - } - break; - case "json": - default: - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - break; - } - }catch(\Exception $e) { - $this->getLogger()->error("The selected data provider crashed. JSON will be used instead."); - $this->dataProvider = new ConfigDataProvider($this, $cacheSize); - } - $this->getLogger()->debug(TF::BOLD . "Loading Plot Clearing settings"); - if($this->getConfig()->get("FastClearing", false) === true and $this->getServer()->getPluginManager()->getPlugin("WorldStyler") === null) { + + $this->getLogger()->debug(TF::BOLD . "Loading Plot Clearing settings"); // TODO: finish libEfficientWE + if($this->getConfig()->get("FastClearing", false) === true and $this->getServer()->getPluginManager()->getPlugin("WorldStyler") === null){ $this->getConfig()->set("FastClearing", false); $this->getLogger()->info(TF::BOLD . "WorldStyler not found. Legacy clearing will be used."); } - $this->getLogger()->debug(TF::BOLD . "Loading economy settings"); - // Initialize EconomyProvider - if($this->getConfig()->get("UseEconomy", false) === true) { - if(($plugin = $this->getServer()->getPluginManager()->getPlugin("EconomyAPI")) !== null) { - if($plugin instanceof EconomyAPI) { - $this->economyProvider = new EconomySProvider($plugin); - $this->getLogger()->debug("Eco set to EconomySProvider"); - }else - $this->getLogger()->debug("Eco not instance of EconomyAPI"); - } - if(!isset($this->economyProvider)) { - $this->getLogger()->info("No supported economy plugin found!"); - $this->getConfig()->set("UseEconomy", false); - //$this->getConfig()->save(); - } - } - $this->getLogger()->debug(TF::BOLD . "Loading MyPlot Commands"); - // Register command - $this->getServer()->getCommandMap()->register("myplot", new Commands($this)); - } - public function onEnable() : void { - $this->getLogger()->debug(TF::BOLD . "Loading Events"); - $eventListener = new EventListener($this); - $this->getServer()->getPluginManager()->registerEvents($eventListener, $this); - $this->getLogger()->debug(TF::BOLD . "Registering Loaded Levels"); - foreach($this->getServer()->getWorldManager()->getWorlds() as $level) { - $eventListener->onLevelLoad(new WorldLoadEvent($level)); - } - $this->getLogger()->debug(TF::BOLD.TF::GREEN."Enabled!"); - } + $this->internalAPI = new InternalAPI( + $this, + $this->getConfig()->get("UseEconomy", false) === true ? $this->checkEconomy() : null + ); - public function addLevelSettings(string $levelName, PlotLevelSettings $settings) : bool { - $this->levels[$levelName] = $settings; - return true; + $this->getLogger()->debug(TF::BOLD . "Loading MyPlot Commands"); + $this->getServer()->getCommandMap()->register("myplot", new Commands($this, $this->internalAPI)); } - public function unloadLevelSettings(string $levelName) : bool { - if(isset($this->levels[$levelName])) { - unset($this->levels[$levelName]); - $this->getLogger()->debug("Level " . $levelName . " settings unloaded!"); - return true; - } - return false; + public function onEnable() : void{ + $this->getLogger()->debug(TF::BOLD . "Loading Events"); + $this->getServer()->getPluginManager()->registerEvents(new EventListener($this, $this->internalAPI), $this); } - public function onDisable() : void { - $this->dataProvider->close(); + public function onDisable() : void{ + $this->internalAPI->onDisable(); } -} +} \ No newline at end of file diff --git a/src/MyPlot/MyPlotGenerator.php b/src/MyPlot/MyPlotGenerator.php index acdab337..fa7be64f 100644 --- a/src/MyPlot/MyPlotGenerator.php +++ b/src/MyPlot/MyPlotGenerator.php @@ -9,7 +9,7 @@ use pocketmine\world\format\Chunk; use pocketmine\world\generator\Generator; -class MyPlotGenerator extends Generator { +class MyPlotGenerator extends Generator{ protected Block $roadBlock; protected Block $bottomBlock; protected Block $plotFillBlock; @@ -29,9 +29,9 @@ class MyPlotGenerator extends Generator { * @param int $seed * @param string $preset */ - public function __construct(int $seed, string $preset) { + public function __construct(int $seed, string $preset){ $settings = json_decode($preset, true); - if($settings === false or is_null($settings)) { + if($settings === false or is_null($settings)){ $settings = []; } $this->roadBlock = PlotLevelSettings::parseBlock($settings, "RoadBlock", VanillaBlocks::OAK_PLANKS()); @@ -54,7 +54,7 @@ public function __construct(int $seed, string $preset) { ])); } - public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void { + public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{ $shape = $this->getShape($chunkX << 4, $chunkZ << 4); $chunk = $world->getChunk($chunkX, $chunkZ); $bottomBlockId = $this->bottomBlock->getFullId(); @@ -63,17 +63,17 @@ public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : v $roadBlockId = $this->roadBlock->getFullId(); $wallBlockId = $this->wallBlock->getFullId(); $groundHeight = $this->groundHeight; - for($Z = 0; $Z < 16; ++$Z) { - for($X = 0; $X < 16; ++$X) { + for($Z = 0; $Z < 16; ++$Z){ + for($X = 0; $X < 16; ++$X){ $chunk->setBiomeId($X, $Z, BiomeIds::PLAINS); $chunk->setFullBlock($X, 0, $Z, $bottomBlockId); - for($y = 1; $y < $groundHeight; ++$y) { + for($y = 1; $y < $groundHeight; ++$y){ $chunk->setFullBlock($X, $y, $Z, $plotFillBlockId); } $type = $shape[($Z << 4) | $X]; - if($type === self::PLOT) { + if($type === self::PLOT){ $chunk->setFullBlock($X, $groundHeight, $Z, $plotFloorBlockId); - }elseif($type === self::ROAD) { + }elseif($type === self::ROAD){ $chunk->setFullBlock($X, $groundHeight, $Z, $roadBlockId); }else{ $chunk->setFullBlock($X, $groundHeight, $Z, $roadBlockId); @@ -92,47 +92,47 @@ public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : v * * @return \SplFixedArray */ - public function getShape(int $x, int $z) : \SplFixedArray { + public function getShape(int $x, int $z) : \SplFixedArray{ $totalSize = $this->plotSize + $this->roadWidth; - if($x >= 0) { + if($x >= 0){ $X = $x % $totalSize; }else{ $X = $totalSize - abs($x % $totalSize); } - if($z >= 0) { + if($z >= 0){ $Z = $z % $totalSize; }else{ $Z = $totalSize - abs($z % $totalSize); } $startX = $X; $shape = new \SplFixedArray(256); - for($z = 0; $z < 16; $z++, $Z++) { - if($Z === $totalSize) { + for($z = 0; $z < 16; $z++, $Z++){ + if($Z === $totalSize){ $Z = 0; } - if($Z < $this->plotSize) { + if($Z < $this->plotSize){ $typeZ = self::PLOT; - }elseif($Z === $this->plotSize or $Z === ($totalSize - 1)) { + }elseif($Z === $this->plotSize or $Z === ($totalSize - 1)){ $typeZ = self::WALL; }else{ $typeZ = self::ROAD; } - for($x = 0, $X = $startX; $x < 16; $x++, $X++) { - if($X === $totalSize) { + for($x = 0, $X = $startX; $x < 16; $x++, $X++){ + if($X === $totalSize){ $X = 0; } - if($X < $this->plotSize) { + if($X < $this->plotSize){ $typeX = self::PLOT; - }elseif($X === $this->plotSize or $X === ($totalSize - 1)) { + }elseif($X === $this->plotSize or $X === ($totalSize - 1)){ $typeX = self::WALL; }else{ $typeX = self::ROAD; } - if($typeX === $typeZ) { + if($typeX === $typeZ){ $type = $typeX; - }elseif($typeX === self::PLOT) { + }elseif($typeX === self::PLOT){ $type = $typeZ; - }elseif($typeZ === self::PLOT) { + }elseif($typeZ === self::PLOT){ $type = $typeX; }else{ $type = self::ROAD; @@ -143,5 +143,5 @@ public function getShape(int $x, int $z) : \SplFixedArray { return $shape; } - public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void {} + public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{ } } \ No newline at end of file diff --git a/src/MyPlot/Plot.php b/src/MyPlot/Plot.php deleted file mode 100644 index f5963f0b..00000000 --- a/src/MyPlot/Plot.php +++ /dev/null @@ -1,209 +0,0 @@ -levelName = $levelName; - $this->X = $X; - $this->Z = $Z; - $this->name = $name; - $this->owner = $owner; - $this->helpers = $helpers; - $this->denied = $denied; - $this->biome = strtoupper($biome); - $settings = MyPlot::getInstance()->getLevelSettings($levelName); - if(!isset($pvp)) { - $this->pvp = !$settings->restrictPVP; - }else{ - $this->pvp = $pvp; - } - if(MyPlot::getInstance()->getConfig()->get('UseEconomy', false) === true) - $this->price = $price < 0 ? $settings->claimPrice : $price; - else - $this->price = 0; - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function isHelper(string $username) : bool { - return in_array($username, $this->helpers, true); - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function addHelper(string $username) : bool { - if(!$this->isHelper($username)) { - $this->unDenyPlayer($username); - $this->helpers[] = $username; - return true; - } - return false; - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function removeHelper(string $username) : bool { - if(!$this->isHelper($username)) { - return false; - } - $key = array_search($username, $this->helpers, true); - if($key === false) { - return false; - } - unset($this->helpers[$key]); - return true; - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function isDenied(string $username) : bool { - return in_array($username, $this->denied, true); - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function denyPlayer(string $username) : bool { - if(!$this->isDenied($username)) { - $this->removeHelper($username); - $this->denied[] = $username; - return true; - } - return false; - } - - /** - * @api - * - * @param string $username - * - * @return bool - */ - public function unDenyPlayer(string $username) : bool { - if(!$this->isDenied($username)) { - return false; - } - $key = array_search($username, $this->denied, true); - if($key === false) { - return false; - } - unset($this->denied[$key]); - return true; - } - - /** - * @api - * - * @param Plot $plot - * @param bool $checkMerge - * - * @return bool - */ - public function isSame(Plot $plot, bool $checkMerge = true) : bool { - if($checkMerge) - $plot = MyPlot::getInstance()->getProvider()->getMergeOrigin($plot); - return $this->X === $plot->X and $this->Z === $plot->Z and $this->levelName === $plot->levelName; - } - - /** - * @api - * - * @return bool - */ - public function isMerged() : bool { - return count(MyPlot::getInstance()->getProvider()->getMergedPlots($this, true)) > 1; // only calculate the adjacent to save resources - } - - /** - * @api - * - * @param int $side - * @param int $step - * - * @return Plot - */ - public function getSide(int $side, int $step = 1) : Plot { - $levelSettings = MyPlot::getInstance()->getLevelSettings($this->levelName); - $pos = MyPlot::getInstance()->getPlotPosition($this, false); - $sidePos = $pos->getSide($side, $step * ($levelSettings->plotSize + $levelSettings->roadWidth)); - $sidePlot = MyPlot::getInstance()->getPlotByPosition($sidePos); - if($sidePlot === null) { - switch($side) { - case Facing::NORTH: - $sidePlot = new self($this->levelName, $this->X, $this->Z - $step); - break; - case Facing::SOUTH: - $sidePlot = new self($this->levelName, $this->X, $this->Z + $step); - break; - case Facing::WEST: - $sidePlot = new self($this->levelName, $this->X - $step, $this->Z); - break; - case Facing::EAST: - $sidePlot = new self($this->levelName, $this->X + $step, $this->Z); - break; - default: - return clone $this; - } - } - return $sidePlot; - } - - public function __toString() : string { - return "(" . $this->X . ";" . $this->Z . ")"; - } -} \ No newline at end of file diff --git a/src/MyPlot/PlotLevelSettings.php b/src/MyPlot/PlotLevelSettings.php index f6fa631e..72e3178a 100644 --- a/src/MyPlot/PlotLevelSettings.php +++ b/src/MyPlot/PlotLevelSettings.php @@ -3,11 +3,11 @@ namespace MyPlot; use pocketmine\block\Block; -use pocketmine\block\BlockFactory; use pocketmine\block\VanillaBlocks; +use pocketmine\item\ItemBlock; +use pocketmine\item\StringToItemParser; -class PlotLevelSettings -{ +class PlotLevelSettings{ public string $name; public Block $roadBlock; public Block $bottomBlock; @@ -22,22 +22,22 @@ class PlotLevelSettings public int $disposePrice = 0; public int $resetPrice = 0; public int $clonePrice = 0; + public int $fillPrice = 0; public bool $restrictEntityMovement = true; public bool $restrictPVP = false; public bool $updatePlotLiquids = false; public bool $allowOutsidePlotSpread = false; - public bool $displayDoneNametags = false; public bool $editBorderBlocks = true; /** * PlotLevelSettings constructor. * - * @param string $name + * @param string $name * @param mixed[] $settings */ - public function __construct(string $name, array $settings = []) { + public function __construct(string $name, array $settings = []){ $this->name = $name; - if(count($settings) > 0) { + if(count($settings) > 0){ $this->roadBlock = self::parseBlock($settings, "RoadBlock", VanillaBlocks::OAK_PLANKS()); $this->wallBlock = self::parseBlock($settings, "WallBlock", VanillaBlocks::STONE_SLAB()); $this->plotFloorBlock = self::parseBlock($settings, "PlotFloorBlock", VanillaBlocks::GRASS()); @@ -60,40 +60,26 @@ public function __construct(string $name, array $settings = []) { } /** - * @param string[] $array + * @param string[] $array * @param string|int $key - * @param Block $default + * @param Block $default * * @return Block */ - public static function parseBlock(array $array, string|int $key, Block $default) : Block { - if(isset($array[$key])) { - $id = $array[$key]; - if(is_numeric($id)) { - $block = BlockFactory::getInstance()->get((int) $id); - }else{ - $split = explode(":", $id); - if(count($split) === 2 and is_numeric($split[0]) and is_numeric($split[1])) { - $block = BlockFactory::getInstance()->get((int) $split[0], (int) $split[1]); - }else{ - $block = $default; - } - } - }else{ - $block = $default; - } - return $block; + public static function parseBlock(array $array, string|int $key, Block $default) : Block{ + $item = StringToItemParser::getInstance()->parse($array[$key]); + return $item instanceof ItemBlock ? $item->getBlock() : $default; } /** - * @param string[] $array + * @param string[] $array * @param string|int $key - * @param int $default + * @param int $default * * @return int */ - public static function parseNumber(array $array, string|int $key, int $default) : int { - if(isset($array[$key]) and is_numeric($array[$key])) { + public static function parseNumber(array $array, string|int $key, int $default) : int{ + if(isset($array[$key]) and is_numeric($array[$key])){ return (int) $array[$key]; }else{ return $default; @@ -101,14 +87,14 @@ public static function parseNumber(array $array, string|int $key, int $default) } /** - * @param mixed[] $array + * @param mixed[] $array * @param string|int $key - * @param bool $default + * @param bool $default * * @return bool */ - public static function parseBool(array $array, string|int $key, bool $default) : bool { - if(isset($array[$key]) and is_bool($array[$key])) { + public static function parseBool(array $array, string|int $key, bool $default) : bool{ + if(isset($array[$key]) and is_bool($array[$key])){ return $array[$key]; }else{ return $default; diff --git a/src/MyPlot/events/MyPlotBlockEvent.php b/src/MyPlot/events/MyPlotBlockEvent.php index 3f77ea55..2c69cc41 100644 --- a/src/MyPlot/events/MyPlotBlockEvent.php +++ b/src/MyPlot/events/MyPlotBlockEvent.php @@ -2,7 +2,7 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\block\Block; use pocketmine\event\block\BlockBreakEvent; use pocketmine\event\block\BlockPlaceEvent; @@ -13,7 +13,7 @@ use pocketmine\event\player\PlayerInteractEvent; use pocketmine\player\Player; -class MyPlotBlockEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotBlockEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; private Block $block; @@ -24,30 +24,30 @@ class MyPlotBlockEvent extends MyPlotPlotEvent implements Cancellable { /** * MyPlotBlockEvent constructor. * - * @param Plot $plot - * @param Block $block - * @param Player $player + * @param BasePlot $plot + * @param Block $block + * @param Player $player * @param BlockPlaceEvent|BlockBreakEvent|PlayerInteractEvent|SignChangeEvent $event */ - public function __construct(Plot $plot, Block $block, Player $player, Event $event) { + public function __construct(BasePlot $plot, Block $block, Player $player, Event $event){ $this->block = $block; $this->player = $player; $this->event = $event; parent::__construct($plot); } - public function getBlock() : Block { + public function getBlock() : Block{ return $this->block; } /** * @return BlockPlaceEvent|BlockBreakEvent|PlayerInteractEvent|SignChangeEvent */ - public function getEvent() : Event { + public function getEvent() : Event{ return $this->event; } - public function getPlayer() : Player { + public function getPlayer() : Player{ return $this->player; } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotBorderChangeEvent.php b/src/MyPlot/events/MyPlotBorderChangeEvent.php index cf387f78..b3c9cdff 100644 --- a/src/MyPlot/events/MyPlotBorderChangeEvent.php +++ b/src/MyPlot/events/MyPlotBorderChangeEvent.php @@ -4,6 +4,6 @@ namespace MyPlot\events; -class MyPlotBorderChangeEvent extends MyPlotBlockEvent { +class MyPlotBorderChangeEvent extends MyPlotBlockEvent{ } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotClearEvent.php b/src/MyPlot/events/MyPlotClearEvent.php index 8ea187a4..8c1fe6e9 100644 --- a/src/MyPlot/events/MyPlotClearEvent.php +++ b/src/MyPlot/events/MyPlotClearEvent.php @@ -2,11 +2,11 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotClearEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotClearEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; private int $maxBlocksPerTick; @@ -14,19 +14,19 @@ class MyPlotClearEvent extends MyPlotPlotEvent implements Cancellable { /** * MyPlotClearEvent constructor. * - * @param Plot $plot - * @param int $maxBlocksPerTick + * @param BasePlot $plot + * @param int $maxBlocksPerTick */ - public function __construct(Plot $plot, int $maxBlocksPerTick = 256) { + public function __construct(BasePlot $plot, int $maxBlocksPerTick = 256){ $this->maxBlocksPerTick = $maxBlocksPerTick; parent::__construct($plot); } - public function getMaxBlocksPerTick() : int { + public function getMaxBlocksPerTick() : int{ return $this->maxBlocksPerTick; } - public function setMaxBlocksPerTick(int $maxBlocksPerTick) : self { + public function setMaxBlocksPerTick(int $maxBlocksPerTick) : self{ $this->maxBlocksPerTick = $maxBlocksPerTick; return $this; } diff --git a/src/MyPlot/events/MyPlotCloneEvent.php b/src/MyPlot/events/MyPlotCloneEvent.php index 91eb0e0c..01c724e6 100644 --- a/src/MyPlot/events/MyPlotCloneEvent.php +++ b/src/MyPlot/events/MyPlotCloneEvent.php @@ -2,31 +2,25 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotCloneEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotCloneEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; - protected Plot $clonePlot; + protected BasePlot $clonePlot; - /** - * MyPlotCloneEvent constructor. - * - * @param Plot $originPlot - * @param Plot $clonePlot - */ - public function __construct(Plot $originPlot, Plot $clonePlot) { + public function __construct(BasePlot $originPlot, BasePlot $clonePlot){ $this->clonePlot = $clonePlot; parent::__construct($originPlot); } - public function setClonePlot(Plot $clonePlot) : void { + public function setClonePlot(BasePlot $clonePlot) : void{ $this->clonePlot = $clonePlot; } - public function getClonePlot() : Plot { + public function getClonePlot() : BasePlot{ return $this->clonePlot; } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotDenyEvent.php b/src/MyPlot/events/MyPlotDenyEvent.php deleted file mode 100644 index 6a88361d..00000000 --- a/src/MyPlot/events/MyPlotDenyEvent.php +++ /dev/null @@ -1,57 +0,0 @@ -type = $type; - $this->player = $player; - parent::__construct($plot); - } - - public function getType() : int { - return $this->type; - } - - public function setType(int $type) : self { - $this->type = $type; - return $this; - } - - public function getDenied() : string { - return $this->player; - } - - /** - * @param IPlayer|string $player - * - * @return self - */ - public function setDenied(IPlayer|string $player) : self { - if($player instanceof IPlayer) { - $this->player = $player->getName(); - }else { - $this->player = $player; - } - return $this; - } -} \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotDisposeEvent.php b/src/MyPlot/events/MyPlotDisposeEvent.php index 04a5d56d..5c86cfcf 100644 --- a/src/MyPlot/events/MyPlotDisposeEvent.php +++ b/src/MyPlot/events/MyPlotDisposeEvent.php @@ -2,19 +2,9 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotDisposeEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotDisposeEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; - - /** - * MyPlotClearEvent constructor. - * - * @param Plot $plot - */ - public function __construct(Plot $plot) { - parent::__construct($plot); - } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotFillEvent.php b/src/MyPlot/events/MyPlotFillEvent.php index fdeb9fb7..ce7f27f9 100644 --- a/src/MyPlot/events/MyPlotFillEvent.php +++ b/src/MyPlot/events/MyPlotFillEvent.php @@ -2,11 +2,11 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotFillEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotFillEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; /** @var int $maxBlocksPerTick */ @@ -15,10 +15,10 @@ class MyPlotFillEvent extends MyPlotPlotEvent implements Cancellable { /** * MyPlotFillEvent constructor. * - * @param Plot $plot - * @param int $maxBlocksPerTick + * @param BasePlot $plot + * @param int $maxBlocksPerTick */ - public function __construct(Plot $plot, int $maxBlocksPerTick = 256) { + public function __construct(BasePlot $plot, int $maxBlocksPerTick = 256){ $this->maxBlocksPerTick = $maxBlocksPerTick; parent::__construct($plot); } @@ -26,7 +26,7 @@ public function __construct(Plot $plot, int $maxBlocksPerTick = 256) { /** * @return int */ - public function getMaxBlocksPerTick() : int { + public function getMaxBlocksPerTick() : int{ return $this->maxBlocksPerTick; } @@ -35,7 +35,7 @@ public function getMaxBlocksPerTick() : int { * * @return self */ - public function setMaxBlocksPerTick(int $maxBlocksPerTick) : self { + public function setMaxBlocksPerTick(int $maxBlocksPerTick) : self{ $this->maxBlocksPerTick = $maxBlocksPerTick; return $this; } diff --git a/src/MyPlot/events/MyPlotGenerationEvent.php b/src/MyPlot/events/MyPlotGenerationEvent.php index 958d12bc..627b3527 100644 --- a/src/MyPlot/events/MyPlotGenerationEvent.php +++ b/src/MyPlot/events/MyPlotGenerationEvent.php @@ -6,7 +6,7 @@ use pocketmine\event\CancellableTrait; use pocketmine\event\Event; -class MyPlotGenerationEvent extends Event implements Cancellable { +class MyPlotGenerationEvent extends Event implements Cancellable{ use CancellableTrait; private string $levelName; @@ -17,30 +17,30 @@ class MyPlotGenerationEvent extends Event implements Cancellable { /** * MyPlotGenerationEvent constructor. * - * @param string $levelName - * @param string $generator + * @param string $levelName + * @param string $generator * @param string[] $settings */ - public function __construct(string $levelName, string $generator = "myplot", array $settings = []) { + public function __construct(string $levelName, string $generator = "myplot", array $settings = []){ $this->levelName = $levelName; $this->generator = $generator; $this->settings = $settings; } - public function getLevelName() : string { + public function getLevelName() : string{ return $this->levelName; } - public function setLevelName(string $levelName) : self { + public function setLevelName(string $levelName) : self{ $this->levelName = $levelName; return $this; } - public function getGenerator() : string { + public function getGenerator() : string{ return $this->generator; } - public function setGenerator(string $generator) : self { + public function setGenerator(string $generator) : self{ $this->generator = $generator; return $this; } @@ -48,7 +48,7 @@ public function setGenerator(string $generator) : self { /** * @return string[] */ - public function getSettings() : array { + public function getSettings() : array{ return $this->settings; } @@ -58,7 +58,7 @@ public function getSettings() : array { * @return self * @throws \JsonException */ - public function setSettings(array $settings) : self { + public function setSettings(array $settings) : self{ $this->settings = $settings; $this->settings["preset"] = json_encode($settings, JSON_THROW_ON_ERROR); return $this; diff --git a/src/MyPlot/events/MyPlotMergeEvent.php b/src/MyPlot/events/MyPlotMergeEvent.php index 7411ff9e..4cd821db 100644 --- a/src/MyPlot/events/MyPlotMergeEvent.php +++ b/src/MyPlot/events/MyPlotMergeEvent.php @@ -2,33 +2,38 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; +use MyPlot\plot\MergedPlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotMergeEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotMergeEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; - /** @var Plot[][] $toMerge */ - private array $toMerge; + /** @var BasePlot[] $toMerge */ + private array $toMerge; + private int $direction; - /** - * MyPlotMergeEvent constructor. - * @param Plot $plot - * @param Plot[][] $toMerge - */ - public function __construct(Plot $plot, array $toMerge) { - $this->toMerge = $toMerge; + /** + * MyPlotMergeEvent constructor. + * + * @param MergedPlot $plot + * @param int $direction + * @param BasePlot[] $toMerge + */ + public function __construct(MergedPlot $plot, int $direction, array $toMerge){ parent::__construct($plot); + $this->direction = $direction; + $this->toMerge = $toMerge; } - /** - * @return Plot[][] - */ - public function getToMergePairs() : array { - return $this->toMerge; - } + /** + * @return BasePlot[] + */ + public function getToMergePairs() : array{ + return $this->toMerge; + } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotPlayerEnterPlotEvent.php b/src/MyPlot/events/MyPlotPlayerEnterPlotEvent.php index a1ae4af4..9a17d66d 100644 --- a/src/MyPlot/events/MyPlotPlayerEnterPlotEvent.php +++ b/src/MyPlot/events/MyPlotPlayerEnterPlotEvent.php @@ -2,12 +2,12 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\player\Player; -class MyPlotPlayerEnterPlotEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotPlayerEnterPlotEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; private Player $player; @@ -15,19 +15,19 @@ class MyPlotPlayerEnterPlotEvent extends MyPlotPlotEvent implements Cancellable /** * MyPlotPlayerEnterPlotEvent constructor. * - * @param Plot $plot - * @param Player $player + * @param BasePlot $plot + * @param Player $player */ - public function __construct(Plot $plot, Player $player) { + public function __construct(BasePlot $plot, Player $player){ $this->player = $player; parent::__construct($plot); } - public function getPlayer() : Player { + public function getPlayer() : Player{ return $this->player; } - public function setPlayer(Player $player) : self { + public function setPlayer(Player $player) : self{ $this->player = $player; return $this; } diff --git a/src/MyPlot/events/MyPlotPlayerLeavePlotEvent.php b/src/MyPlot/events/MyPlotPlayerLeavePlotEvent.php index b2afdeb7..eb5b5125 100644 --- a/src/MyPlot/events/MyPlotPlayerLeavePlotEvent.php +++ b/src/MyPlot/events/MyPlotPlayerLeavePlotEvent.php @@ -2,12 +2,12 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\player\Player; -class MyPlotPlayerLeavePlotEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotPlayerLeavePlotEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; private Player $player; @@ -15,15 +15,15 @@ class MyPlotPlayerLeavePlotEvent extends MyPlotPlotEvent implements Cancellable /** * MyPlotPlayerLeavePlotEvent constructor. * - * @param Plot $plot - * @param Player $player + * @param BasePlot $plot + * @param Player $player */ - public function __construct(Plot $plot, Player $player) { + public function __construct(BasePlot $plot, Player $player){ $this->player = $player; parent::__construct($plot); } - public function getPlayer() : Player { + public function getPlayer() : Player{ return $this->player; } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotPlotEvent.php b/src/MyPlot/events/MyPlotPlotEvent.php index abb7a585..4b766845 100644 --- a/src/MyPlot/events/MyPlotPlotEvent.php +++ b/src/MyPlot/events/MyPlotPlotEvent.php @@ -2,21 +2,21 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Event; -class MyPlotPlotEvent extends Event { - protected Plot $plot; +class MyPlotPlotEvent extends Event{ + protected BasePlot $plot; - public function __construct(Plot $plot) { + public function __construct(BasePlot $plot){ $this->plot = $plot; } - public function getPlot() : Plot { + public function getPlot() : BasePlot{ return $this->plot; } - public function setPlot(Plot $plot) : self { + public function setPlot(BasePlot $plot) : self{ $this->plot = $plot; return $this; } diff --git a/src/MyPlot/events/MyPlotPvpEvent.php b/src/MyPlot/events/MyPlotPvpEvent.php index 01c70373..85dfc755 100644 --- a/src/MyPlot/events/MyPlotPvpEvent.php +++ b/src/MyPlot/events/MyPlotPvpEvent.php @@ -2,35 +2,35 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\player\Player; -class MyPlotPvpEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotPvpEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; private Player $attacker; private Player $damaged; private ?EntityDamageByEntityEvent $event; - public function __construct(Plot $plot, Player $attacker, Player $damaged, ?EntityDamageByEntityEvent $event = null) { + public function __construct(BasePlot $plot, Player $attacker, Player $damaged, ?EntityDamageByEntityEvent $event = null){ $this->attacker = $attacker; $this->damaged = $damaged; $this->event = $event; parent::__construct($plot); } - public function getAttacker() : Player { + public function getAttacker() : Player{ return $this->attacker; } - public function getDamaged() : Player { + public function getDamaged() : Player{ return $this->damaged; } - public function getEvent() : ?EntityDamageByEntityEvent { + public function getEvent() : ?EntityDamageByEntityEvent{ return $this->event; } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotResetEvent.php b/src/MyPlot/events/MyPlotResetEvent.php index 86ab7cef..90139456 100644 --- a/src/MyPlot/events/MyPlotResetEvent.php +++ b/src/MyPlot/events/MyPlotResetEvent.php @@ -2,19 +2,22 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; +use MyPlot\plot\SinglePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotResetEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotResetEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; + public function __construct(SinglePlot $plot){ + parent::__construct($plot); + } + /** - * MyPlotClearEvent constructor. - * - * @param Plot $plot + * @return SinglePlot */ - public function __construct(Plot $plot) { - parent::__construct($plot); + public function getPlot() : BasePlot{ + return parent::getPlot(); } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotSaveEvent.php b/src/MyPlot/events/MyPlotSaveEvent.php index d4a0e9e8..46a82fb9 100644 --- a/src/MyPlot/events/MyPlotSaveEvent.php +++ b/src/MyPlot/events/MyPlotSaveEvent.php @@ -2,26 +2,18 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; -use pocketmine\event\Cancellable; -use pocketmine\event\CancellableTrait; +use MyPlot\plot\BasePlot; +use MyPlot\plot\SinglePlot; -class MyPlotSaveEvent extends MyPlotPlotEvent implements Cancellable { - use CancellableTrait; - - public const SQLITE3 = 0; - public const MySQL = 1; - public const JSON = 2; - public const YAML = 3; - public const OTHER = -1; - private int $type; - - public function __construct(int $type, Plot $plot) { - $this->type = $type; +class MyPlotSaveEvent extends MyPlotPlotEvent{ + public function __construct(SinglePlot $plot){ parent::__construct($plot); } - public function getSaveType() : int { - return $this->type; + /** + * @return SinglePlot + */ + public function getPlot() : BasePlot{ + return parent::getPlot(); } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotSettingEvent.php b/src/MyPlot/events/MyPlotSettingEvent.php index b2116784..55f937c4 100644 --- a/src/MyPlot/events/MyPlotSettingEvent.php +++ b/src/MyPlot/events/MyPlotSettingEvent.php @@ -2,26 +2,29 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; +use MyPlot\plot\SinglePlot; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; -class MyPlotSettingEvent extends MyPlotPlotEvent implements Cancellable { +class MyPlotSettingEvent extends MyPlotPlotEvent implements Cancellable{ use CancellableTrait; - private Plot $oldPlot; + private SinglePlot $oldPlot; - public function __construct(Plot $oldPlot, Plot $newPlot) { + public function __construct(SinglePlot $oldPlot, SinglePlot $newPlot){ $this->oldPlot = $oldPlot; parent::__construct($newPlot); } - public function getOldPlot() : Plot { + public function getOldPlot() : SinglePlot{ return $this->oldPlot; } - public function setOldPlot(Plot $oldPlot) : self { - $this->oldPlot = $oldPlot; - return $this; + /** + * @return SinglePlot + */ + public function getPlot() : BasePlot{ + return parent::getPlot(); } } \ No newline at end of file diff --git a/src/MyPlot/events/MyPlotTeleportEvent.php b/src/MyPlot/events/MyPlotTeleportEvent.php index ed4b548c..c5c17bfa 100644 --- a/src/MyPlot/events/MyPlotTeleportEvent.php +++ b/src/MyPlot/events/MyPlotTeleportEvent.php @@ -2,22 +2,22 @@ declare(strict_types=1); namespace MyPlot\events; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; use pocketmine\player\Player; -class MyPlotTeleportEvent extends MyPlotPlayerEnterPlotEvent { +class MyPlotTeleportEvent extends MyPlotPlayerEnterPlotEvent{ private bool $center; - public function __construct(Plot $plot, Player $player, bool $center = false) { + public function __construct(BasePlot $plot, Player $player, bool $center = false){ $this->center = $center; parent::__construct($plot, $player); } - public function toCenter() : bool { + public function toCenter() : bool{ return $this->center; } - public function setToCenter(bool $center) : self { + public function setToCenter(bool $center) : self{ $this->center = $center; return $this; } diff --git a/src/MyPlot/forms/ComplexMyPlotForm.php b/src/MyPlot/forms/ComplexMyPlotForm.php deleted file mode 100644 index b7e77b25..00000000 --- a/src/MyPlot/forms/ComplexMyPlotForm.php +++ /dev/null @@ -1,28 +0,0 @@ -getServer()->dispatchCommand($player, MyPlot::getInstance()->getLanguage()->get("command.name"), true); - } - ); - } - - public function setPlot(?Plot $plot) : void { - $this->plot = $plot; - } - - public function getPlot() : ?Plot { - return $this->plot; - } -} \ No newline at end of file diff --git a/src/MyPlot/forms/MainForm.php b/src/MyPlot/forms/MainForm.php index 47ca1743..ad1dfb40 100644 --- a/src/MyPlot/forms/MainForm.php +++ b/src/MyPlot/forms/MainForm.php @@ -1,55 +1,89 @@ setPlot($plugin->getPlotByPosition($player->getPosition())); - - $elements = []; - foreach($subCommands as $command) { - if(!$command->canUse($player) or $command->getForm($player) === null) - continue; - $name = (new \ReflectionClass($command))->getShortName(); - $name = preg_replace('/([a-z])([A-Z])/s','$1 $2', $name); - if($name === null) - continue; - $length = strlen($name) - strlen("Sub Command"); - $name = substr($name, 0, $length); - $elements[] = new MenuOption(TextFormat::DARK_RED.ucfirst($name)); - $this->link[] = $command; + private array $formNames; + + public function __construct(int $current_page, private Player $player, private MyPlot $owningPlugin, private InternalAPI $internalAPI){ + $owningPlugin = MyPlot::getInstance(); + /** @var Commands $mainCommand */ + $mainCommand = $owningPlugin->getCommand($owningPlugin->getLanguage()->get("command.name")); + foreach($mainCommand->getCommands() as $subCommand){ + if($subCommand->getFormClass() !== null and $subCommand->canUse($player)){ + $name = (new \ReflectionClass($subCommand))->getShortName(); + $name = preg_replace('/([a-z])([A-Z])/s', '$1 $2', $name); + $length = strlen($name) - strlen("SubCommand"); // TODO: validate + $name = substr($name, 0, $length); + $this->formNames[TextFormat::DARK_RED . ucfirst($name)] = $subCommand->getFormClass(); + } } parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", ["Main"]), - "", - $elements, - function(Player $player, int $selectedOption) : void { - $form = $this->link[$selectedOption]->getForm($player); - if($form === null) - return; - $form->setPlot($this->plot); - $player->sendForm($form); - }, - function(Player $player) : void {} + TextFormat::BLACK . MyPlot::getInstance()->getLanguage()->translateString("form.header", ["Main"]), + '', + $current_page ); } + + protected function getPreviousButton() : Button{ + return new Button("<- Go back"); + } + + protected function getNextButton() : Button{ + return new Button("Next Page ->"); + } + + protected function getPages() : int{ + // Returns the maximum number of pages. + // This will alter the visibility of previous and next buttons. + // For example: + // * If we are on page 7 of 7, the "next" button wont be visible + // * If we are on page 6 of 7, the "next" and "previous" button WILL be visible + // * If we are on page 1 of 7, the "previous" button won't be visible + return (int) ceil(count($this->formNames) / self::ENTRIES_PER_PAGE); + } + + protected function populatePage() : void{ + // populate this page with buttons + /** + * @var string $formName + * @var MyPlotForm $formClass + */ + foreach($this->formNames as $formName => $formClass){ + $this->addButton( + new Button($formName), // TODO: icons + \Closure::fromCallable(function() use ($formClass){ + Await::f2c( + function() use ($formClass){ + $plot = yield from $this->internalAPI->generatePlotByPosition($this->player->getPosition()); + $this->player->sendForm(new $formClass($this->owningPlugin, $this->player, $plot)); + } + ); + }) + ); + } + } + + protected function sendPreviousPage(Player $player) : void{ + $player->sendForm(new self($this->current_page - 1, $this->player, $this->owningPlugin, $this->internalAPI)); + } + + protected function sendNextPage(Player $player) : void{ + $player->sendForm(new self($this->current_page + 1, $this->player, $this->owningPlugin, $this->internalAPI)); + } } \ No newline at end of file diff --git a/src/MyPlot/forms/MyPlotForm.php b/src/MyPlot/forms/MyPlotForm.php index c942c662..d64f2932 100644 --- a/src/MyPlot/forms/MyPlotForm.php +++ b/src/MyPlot/forms/MyPlotForm.php @@ -2,9 +2,11 @@ declare(strict_types=1); namespace MyPlot\forms; -use MyPlot\Plot; +use MyPlot\MyPlot; +use MyPlot\plot\BasePlot; use pocketmine\form\Form; +use pocketmine\player\Player; -interface MyPlotForm extends Form { - public function setPlot(?Plot $plot) : void; +interface MyPlotForm extends Form{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot); } \ No newline at end of file diff --git a/src/MyPlot/forms/SimpleMyPlotForm.php b/src/MyPlot/forms/SimpleMyPlotForm.php deleted file mode 100644 index ba98e01c..00000000 --- a/src/MyPlot/forms/SimpleMyPlotForm.php +++ /dev/null @@ -1,28 +0,0 @@ -getServer()->dispatchCommand($player, MyPlot::getInstance()->getLanguage()->get("command.name"), true); - } - ); - } - - public function setPlot(?Plot $plot) : void { - $this->plot = $plot; - } - - public function getPlot() : ?Plot { - return $this->plot; - } -} \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/AddHelperForm.php b/src/MyPlot/forms/subforms/AddHelperForm.php index 47f37dc5..710ae6a1 100644 --- a/src/MyPlot/forms/subforms/AddHelperForm.php +++ b/src/MyPlot/forms/subforms/AddHelperForm.php @@ -1,46 +1,46 @@ helpers, true)) { + if(!in_array("*", $plot->helpers, true)){ $players = ["*"]; - $this->players = ["*"]; + $this->players['*'] = ["*"]; } - foreach($plugin->getServer()->getOnlinePlayers() as $player) { - $players[] = $player->getDisplayName(); - $this->players[] = $player->getName(); + foreach($plugin->getServer()->getOnlinePlayers() as $onlinePlayer){ + $players[] = $onlinePlayer->getDisplayName(); + $this->players[$onlinePlayer->getDisplayName()] = $onlinePlayer->getName(); } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("addhelper.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("addhelper.dropdown"), - array_map( - function(string $text) : string { - return TextFormat::DARK_BLUE.$text; - }, $players - ) + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("addhelper.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("addhelper.dropdown"), + ...array_map( + function(string $text) : string{ + return TextFormat::DARK_BLUE . $text; + }, + $players ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("addhelper.name").' "'.$this->players[$response->getInt("0")].'"', true); - } + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("addhelper.name") . ' "' . $this->players[$entry->getValue()] . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/BiomeForm.php b/src/MyPlot/forms/subforms/BiomeForm.php index b6e07963..1d022d3a 100644 --- a/src/MyPlot/forms/subforms/BiomeForm.php +++ b/src/MyPlot/forms/subforms/BiomeForm.php @@ -1,38 +1,27 @@ getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("biome.form")])); - $elements = []; - $this->biomeNames = $biomes; - foreach($biomes as $biomeName) { - $elements[] = new MenuOption(TextFormat::DARK_RED.ucfirst(strtolower(str_replace("_", " ", $biomeName)))); // TODO: add images + $biomes = array_keys(BiomeSubCommand::BIOMES); + foreach($biomes as $biomeName){ + $this->addButton( + new Button(TextFormat::DARK_RED . ucfirst(strtolower(str_replace("_", " ", $biomeName)))), // TODO: add images + \Closure::fromCallable(fn(Player $player, int $entry) => $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("biome.name") . ' "' . $biomes[$entry] . '"', true)) + ); } - - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("biome.form")]), - "", - $elements, - function(Player $player, int $selectedOption) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("biome.name").' "'.$this->biomeNames[$selectedOption].'"', true); - } - ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/ClaimForm.php b/src/MyPlot/forms/subforms/ClaimForm.php index 52654f1c..86d5debf 100644 --- a/src/MyPlot/forms/subforms/ClaimForm.php +++ b/src/MyPlot/forms/subforms/ClaimForm.php @@ -1,93 +1,41 @@ setPlot($plot); - if($plot === null) { - $plot = new \stdClass(); - $plot->X = ""; - $plot->Z = ""; - $plot->levelName = $player->getWorld()->getFolderName(); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("claim.form")]), - [ - new Input( - "0", - $plugin->getLanguage()->get("claim.formxcoord"), - "2", - (string)$plot->X - ), - new Input( - "1", - $plugin->getLanguage()->get("claim.formzcoord"), - "2", - (string)$plot->Z - ), - new Input( - "2", - $plugin->getLanguage()->get("claim.formworld"), - "world", - $plot->levelName - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - if(is_numeric($response->getString("0")) and is_numeric($response->getString("1")) and $plugin->isLevelLoaded($response->getString("2"))) - $data = MyPlot::getInstance()->getProvider()->getPlot( - $response->getString("2") === '' ? $player->getWorld()->getFolderName() : $response->getString("2"), - (int)$response->getString("0"), - (int)$response->getString("1") - ); - elseif($response->getString("0") === '' or $response->getString("1") === '') { - $data = $this->plot; - }else { - throw new FormValidationException("Unexpected form data returned"); - } +class ClaimForm extends CustomForm implements MyPlotForm{ + public function __construct(Myplot $plugin, Player $player, ?BasePlot $plot){ + if($plot === null) + throw new \InvalidArgumentException("Plot must be a SinglePlot"); - if($data->owner != "") { - if($data->owner === $player->getName()) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("claim.yourplot")); - }else{ - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("claim.alreadyclaimed", [$data->owner])); - } - return; - } - $maxPlots = $plugin->getMaxPlotsOfPlayer($player); - $plotsOfPlayer = 0; - foreach($plugin->getPlotLevels() as $level => $settings) { - $level = $plugin->getServer()->getWorldManager()->getWorldByName((string)$level); - if($level !== null and $level->isLoaded()) { - $plotsOfPlayer += count($plugin->getPlotsOfPlayer($player->getName(), $level->getFolderName())); - } - } - if($plotsOfPlayer >= $maxPlots) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("claim.maxplots", [$maxPlots])); - return; - } - $economy = $plugin->getEconomyProvider(); - if($economy !== null and !$economy->reduceMoney($player, $data->price)) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("claim.nomoney")); - return; - } - if($plugin->claimPlot($data, $player->getName())) { - $player->sendMessage($plugin->getLanguage()->translateString("claim.success")); - }else{ - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("error")); - } - } + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("claim.form")])); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("claim.formxcoord"), + '2', + (string) $plot->X + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plot->X = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("claim.formzcoord"), + '2', + (string) $plot->Z + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plot->Z = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry($plugin->getLanguage()->get("claim.formname")), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . ' ' . $plugin->getLanguage()->get("claim.name") . ' ' . $plot->X . ';' . $plot->Z . ($entry->getValue() === '' ?: ' ' . $entry->getValue()), true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/CloneForm.php b/src/MyPlot/forms/subforms/CloneForm.php index a7bcdff0..4bb0ae20 100644 --- a/src/MyPlot/forms/subforms/CloneForm.php +++ b/src/MyPlot/forms/subforms/CloneForm.php @@ -1,103 +1,38 @@ getPlotByPosition($player->getPosition()); - $this->setPlot($plot); - if($plot === null) { - $plot = new \stdClass(); - $plot->X = ""; - $plot->Z = ""; - $plot->levelName = $player->getWorld()->getFolderName(); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("clone.form")]), - [ - new Label( - "0", - $plugin->getLanguage()->get("clone.formlabel1") - ), - new Input( - "1", - $plugin->getLanguage()->get("clone.formxcoord"), - "2", - (string)$plot->X - ), - new Input( - "2", - $plugin->getLanguage()->get("clone.formzcoord"), - "-4", - (string)$plot->Z - ), - new Input( - "3", - $plugin->getLanguage()->get("clone.formworld"), - "world", - $plot->levelName - ), - new Label( - "4", - $plugin->getLanguage()->get("clone.formlabel2") - ), - new Input( - "5", - $plugin->getLanguage()->get("clone.formxcoord"), - "2" - ), - new Input( - "6", - $plugin->getLanguage()->get("clone.formzcoord"), - "-4" - ), - new Input( - "7", - $plugin->getLanguage()->get("clone.formworld"), - "world", - $plot->levelName - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - if(is_numeric($response->getString("1")) and is_numeric($response->getString("2")) and is_numeric($response->getString("5")) and is_numeric($response->getString("6"))) { - $originPlot = MyPlot::getInstance()->getProvider()->getPlot($response->getString("3") === '' ? $player->getWorld()->getFolderName() : $response->getString("3"), (int)$response->getString("1"), (int)$response->getString("2")); - $clonedPlot = MyPlot::getInstance()->getProvider()->getPlot($response->getString("7") === '' ? $player->getWorld()->getFolderName() : $response->getString("7"), (int)$response->getString("5"), (int)$response->getString("6")); - }else - throw new FormValidationException("Unexpected form data returned"); + public function __construct(Myplot $plugin, Player $player, ?BasePlot $plot){ + if($plot === null) + throw new \InvalidArgumentException("A plot must be provided"); - if($originPlot->owner !== $player->getName() and !$player->hasPermission("myplot.admin.clone")) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("notowner")); - return; - } - if($clonedPlot->owner !== $player->getName() and !$player->hasPermission("myplot.admin.clone")) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("notowner")); - return; - } - if(!$plugin->isLevelLoaded($originPlot->levelName)) - throw new FormValidationException("Invalid world given"); - $plotLevel = $plugin->getLevelSettings($originPlot->levelName); - $economy = $plugin->getEconomyProvider(); - if($economy !== null and !$economy->reduceMoney($player, $plotLevel->clonePrice)) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("clone.nomoney")); - return; - } - if($plugin->clonePlot($originPlot, $clonedPlot)) { - $player->sendMessage($plugin->getLanguage()->translateString("clone.success", [$clonedPlot->__toString(), $originPlot->__toString()])); - }else{ - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("error")); - } - } + $this->clonedPlot = new BasePlot($plot->levelName, $plot->X, $plot->Z); + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("clone.form")])); + $this->addEntry(new LabelEntry($plugin->getLanguage()->get('clone.formcoordslabel'))); + $this->addEntry( + new InputEntry($plugin->getLanguage()->get('clone.formxcoord'), '2', (string) $plot->X), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $this->clonedPlot->X = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry($plugin->getLanguage()->get('clone.formzcoord'), '-4', (string) $plot->Z), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $this->clonedPlot->Z = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry($plugin->getLanguage()->get('clone.formworld'), 'world', $plot->levelName), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $this->clonedPlot->levelName = $entry->getValue()) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/DenyPlayerForm.php b/src/MyPlot/forms/subforms/DenyPlayerForm.php index b629da60..37ac6cfb 100644 --- a/src/MyPlot/forms/subforms/DenyPlayerForm.php +++ b/src/MyPlot/forms/subforms/DenyPlayerForm.php @@ -1,44 +1,46 @@ denied, true)) { + if(!in_array("*", $plot->denied, true)){ $players = ["*"]; - $this->players = ["*"]; + $this->players['*'] = ["*"]; } - foreach($plugin->getServer()->getOnlinePlayers() as $player) { - $players[] = $player->getDisplayName(); - $this->players[] = $player->getName(); + foreach($plugin->getServer()->getOnlinePlayers() as $onlinePlayer){ + $players[] = $onlinePlayer->getDisplayName(); + $this->players[$onlinePlayer->getDisplayName()] = $onlinePlayer->getName(); } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("denyplayer.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("denyplayer.dropdown"), - array_map(function(string $text) : string { - return TextFormat::DARK_BLUE.$text; - }, $players) + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("denyplayer.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("denyplayer.dropdown"), + ...array_map( + function(string $text) : string{ + return TextFormat::DARK_BLUE . $text; + }, + $players ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("denyplayer.name").' "'.$this->players[$response->getInt("0")].'"', true); - } + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("denyplayer.name") . ' "' . $this->players[$entry->getValue()] . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/FillForm.php b/src/MyPlot/forms/subforms/FillForm.php index 14fc264f..0bce87b8 100644 --- a/src/MyPlot/forms/subforms/FillForm.php +++ b/src/MyPlot/forms/subforms/FillForm.php @@ -1,31 +1,26 @@ getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("fill.form")]), - [ - new Input( - "0", - $plugin->getLanguage()->get("fill.formtitle"), - "1:0", - "1:0" - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("fill.name").' "'.$response->getString("0").'"', true); - } +class FillForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("fill.form")])); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("fill.formtitle"), + "1:0", + "1:0" + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("fill.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/GenerateForm.php b/src/MyPlot/forms/subforms/GenerateForm.php index b72ae7ae..e121e226 100644 --- a/src/MyPlot/forms/subforms/GenerateForm.php +++ b/src/MyPlot/forms/subforms/GenerateForm.php @@ -1,99 +1,81 @@ getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("generate.form")])); + + static $outputs = []; + $this->addEntry( + new InputEntry($plugin->getLanguage()->get("generate.formworld"), 'plots'), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $outputs[] = $entry->getValue()) + ); + $this->addEntry( + new InputEntry($plugin->getLanguage()->get("generate.formgenerator"), '', 'myplot'), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $outputs[] = $entry->getValue()) + ); - public function __construct() { - $plugin = MyPlot::getInstance(); - $elements = [ - new Input( - "0", - $plugin->getLanguage()->get("generate.formworld"), - "plots" - ), - new Input( - "1", - $plugin->getLanguage()->get("generate.formgenerator"), - "", - "myplot" - ) - ]; - $i = 2; - foreach($plugin->getConfig()->get("DefaultWorld", []) as $key => $value) { - if(is_numeric($value)) { + foreach($plugin->getConfig()->get("DefaultWorld", []) as $key => $value){ + if(is_numeric($value)){ if($value > 0) - $elements[] = new Slider("$i", $key, 1, 4 * (float)$value, 1, (float)$value); + $this->addEntry( + new SliderEntry($key, 1, 4 * $value, 1, $value), + \Closure::fromCallable(fn(Player $player, SliderEntry $entry) => $outputs[] = $entry->getValue()) + ); else - $elements[] = new Slider("$i", $key, 1, 1000, 1, 1.0); - }elseif(is_bool($value)) { - $elements[] = new Toggle("$i", $key, $value); - }elseif(is_string($value)) { - $elements[] = new Input("$i", $key, "", $value); + $this->addEntry( + new SliderEntry($key, 1, 1000, 1, 1), + \Closure::fromCallable(fn(Player $player, SliderEntry $entry) => $outputs[] = $entry->getValue()) + ); + }elseif(is_bool($value)){ + $this->addEntry( + new ToggleEntry($key, $value), + \Closure::fromCallable(fn(Player $player, ToggleEntry $entry) => $outputs[] = $entry->getValue()) + ); + }elseif(is_string($value)){ + $this->addEntry( + new InputEntry($key, '', $value), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $outputs[] = $entry->getValue()) + ); } - $this->keys[] = $key; - $i++; } - $this->keys[] = "teleport"; - $elements[] = new Toggle("$i", $plugin->getLanguage()->get("generate.formteleport"), true); - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("generate.form")]), - $elements, - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $copy = []; - foreach($response->getAll() as $key => $value) { - if(isset($this->keys[((int)$key)-2])) - $copy[$this->keys[((int)$key)-2]] = $value; - else - $copy[] = $value; - } - $data = $copy; - - $world = array_shift($data); - if($player->getServer()->getWorldManager()->isWorldGenerated($world)) { - $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("generate.exists", [$world])); + $this->addEntry( + new ToggleEntry($plugin->getLanguage()->get("generate.formteleport"), true), + \Closure::fromCallable(function(Player $player, ToggleEntry $entry) use ($plugin, $outputs){ + $worldName = array_shift($outputs); + if($player->getServer()->getWorldManager()->isWorldGenerated($worldName)){ + $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("generate.exists", [$worldName])); return; } - $teleport = array_pop($data); - $blockIds = array_slice($data, -5, 5, true); - $blockIds = array_map(function($val) { - if(str_contains($val, ':')) { - $peices = explode(':', $val); - if(defined(BlockLegacyIds::class."::".strtoupper(str_replace(' ', '_', $peices[0])))) - return constant(BlockLegacyIds::class."::".strtoupper(str_replace(' ', '_', $val))).':'.($peices[1] ?? 0); - return $val; - }elseif(is_numeric($val)) - return $val.':0'; - elseif(defined(BlockLegacyIds::class."::".strtoupper(str_replace(' ', '_', $val)))) - return constant(BlockLegacyIds::class."::".strtoupper(str_replace(' ', '_', $val))).':0'; - return $val; - }, $blockIds); - foreach($blockIds as $key => $val) - $data[$key] = $val; + $blockNames = array_slice($outputs, -6, 5, true); // TODO: UPDATE WHEN CONFIG IS UPDATED + $blockNames = array_map(fn(string $blockName) => str_replace(' ', '_', $blockName), $blockNames); + $blockNames = array_filter($blockNames, fn(string $blockName) => StringToItemParser::getInstance()->parse($blockName) instanceof ItemBlock); + $outputs = array_merge($outputs, $blockNames); - if($plugin->generateLevel($world, array_shift($data), $data)) { - if($teleport) - $plugin->teleportPlayerToPlot($player, new Plot($world, 0, 0)); - $player->sendMessage($plugin->getLanguage()->translateString("generate.success", [$world])); + if($plugin->generateLevel($worldName, array_shift($outputs), $outputs)){ + if($entry->getValue() === true) + $plugin->teleportPlayerToPlot($player, new BasePlot($worldName, 0, 0)); + $player->sendMessage($plugin->getLanguage()->translateString("generate.success", [$worldName])); }else{ $player->sendMessage(TextFormat::RED . $plugin->getLanguage()->translateString("generate.error")); } - } + }) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/GiveForm.php b/src/MyPlot/forms/subforms/GiveForm.php index cc8eb7d0..e358d28a 100644 --- a/src/MyPlot/forms/subforms/GiveForm.php +++ b/src/MyPlot/forms/subforms/GiveForm.php @@ -1,37 +1,25 @@ getServer()->getOnlinePlayers() as $player) { - $players[] = $player->getDisplayName(); - $this->players[] = $player->getName(); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("give.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("give.dropdown"), - $players - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("give.name").' "'.$this->players[$response->getInt("0")].'"', true); - } +class GiveForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("give.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("give.dropdown"), + ...array_map(fn(Player $player) => $player->getDisplayName(), $plugin->getServer()->getOnlinePlayers()) + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("give.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/HomeForm.php b/src/MyPlot/forms/subforms/HomeForm.php index 1af20a01..a8f4d2e1 100644 --- a/src/MyPlot/forms/subforms/HomeForm.php +++ b/src/MyPlot/forms/subforms/HomeForm.php @@ -1,31 +1,22 @@ getPlotsOfPlayer($player->getName(), $player->getWorld()->getFolderName()); - $i = 1; - $elements = []; - foreach($plots as $plot) { - $elements[] = new MenuOption(TextFormat::DARK_RED.$i++.") ".$plot->name." ". $plot); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("home.form")]), - "", - $elements, - function(Player $player, int $selectedOption) use ($plugin) : void { - // TODO: merge list and home into one form - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("home.name").' "'.($selectedOption+1).'"', true); - } - ); +class HomeForm extends SimpleForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("home.form")])); + // TODO: merge list and home into one form + $i = 0; + foreach($plugin->getPlotsOfPlayer($player->getName(), $player->getWorld()->getFolderName()) as $plot) + $this->addButton(new Button(TextFormat::DARK_RED . ++$i . ") " . $plot->name . " " . $plot), \Closure::fromCallable(fn(Player $player, int $data) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("home.name") . ' "' . ($data + 1) . '"', true))); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/InfoForm.php b/src/MyPlot/forms/subforms/InfoForm.php index 4f3c0b24..4ce915c4 100644 --- a/src/MyPlot/forms/subforms/InfoForm.php +++ b/src/MyPlot/forms/subforms/InfoForm.php @@ -1,65 +1,59 @@ setPlot($plot); +class InfoForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + if(!$plot instanceof SinglePlot) + throw new \InvalidArgumentException("Plot must be a SinglePlot"); + + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("info.form")])); - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("info.form")]), - [ - new Label( - "0", - $plugin->getLanguage()->translateString("info.formcoords", [(string)$this->plot]) - ), - new Label( - "1", - $plugin->getLanguage()->translateString("info.formowner", [TextFormat::BOLD.$this->plot->owner]) - ), - new Label( - "2", - $plugin->getLanguage()->translateString("info.formpname", [TextFormat::BOLD.$this->plot->name]) - ), - new Dropdown( - "3", - $plugin->getLanguage()->get("info.formhelpers"), - count($this->plot->helpers) === 0 ? [TextFormat::DARK_BLUE.$plugin->getLanguage()->get("info.formnohelpers")] : array_map(function(string $text) : string { - return TextFormat::DARK_BLUE.$text; - }, $this->plot->helpers) - ), - new Dropdown( - "4", - $plugin->getLanguage()->get("info.formdenied"), - count($this->plot->denied) === 0 ? [TextFormat::DARK_BLUE.$plugin->getLanguage()->get("info.formnodenied")] : array_map(function(string $text) : string { - return TextFormat::DARK_BLUE.$text; - }, $this->plot->denied) - ), - new Dropdown( - "5", - $plugin->getLanguage()->get("info.formbiome"), - array_map(function(string $text) : string { - return TextFormat::DARK_BLUE.ucfirst(strtolower(str_replace("_", " ", $text))); - }, array_keys(BiomeSubCommand::BIOMES)), - (int)array_search($this->plot->biome, array_keys(BiomeSubCommand::BIOMES), true) - ), - new Label( - "6", - $plugin->getLanguage()->translateString("info.formpvp", [$this->plot->pvp ? "Enabled" : "Disabled"]) // TODO: translations - ) - ], - function(Player $player, CustomFormResponse $response) : void{} - ); + $this->addEntry(new LabelEntry($plugin->getLanguage()->translateString("info.formcoords", [(string) $plot]))); + $this->addEntry(new LabelEntry($plugin->getLanguage()->translateString("info.formowner", [TextFormat::BOLD . $plot->owner]))); + $this->addEntry(new LabelEntry($plugin->getLanguage()->translateString("info.formpname", [TextFormat::BOLD . $plot->name]))); + $this->addEntry(new DropdownEntry( + $plugin->getLanguage()->get("info.formhelpers"), + ...(count($plot->helpers) === 0 ? + [TextFormat::DARK_BLUE . $plugin->getLanguage()->get("info.formnohelpers")] : + array_map( + function(string $text) : string{ + return TextFormat::DARK_BLUE . $text; + }, + $plot->helpers + )) + )); + $this->addEntry(new DropdownEntry( + $plugin->getLanguage()->get("info.formdenied"), + ...(count($plot->denied) === 0 ? + [TextFormat::DARK_BLUE . $plugin->getLanguage()->get("info.formnodenied")] : + array_map( + function(string $text) : string{ + return TextFormat::DARK_BLUE . $text; + }, + $plot->denied + )) + )); + $this->addEntry(new DropdownEntry( + $plugin->getLanguage()->get("info.formbiome"), + ...array_map( + function(string $text) : string{ + return TextFormat::DARK_BLUE . ucfirst(strtolower(str_replace("_", " ", $text))); + }, + array_keys(BiomeSubCommand::BIOMES) + ))); + $this->addEntry(new LabelEntry($plugin->getLanguage()->translateString("info.formpvp", [$plot->pvp ? "Enabled" : "Disabled"]))); // TODO: translations } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/KickForm.php b/src/MyPlot/forms/subforms/KickForm.php index 2f669984..32290411 100644 --- a/src/MyPlot/forms/subforms/KickForm.php +++ b/src/MyPlot/forms/subforms/KickForm.php @@ -1,44 +1,35 @@ setPlot($plot); - $players = []; - foreach($plugin->getServer()->getOnlinePlayers() as $player) { - $plot = $plugin->getPlotByPosition($player->getPosition()); - if($plot === null) - continue; - if($this->plot !== null and !$plot->isSame($this->plot)) - continue; - $players[] = $player->getDisplayName(); - $this->players[] = $player->getName(); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("kick.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("kick.dropdown"), - $players + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("kick.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("kick.dropdown"), + ...array_map( + fn(Player $player2) => $player2->getDisplayName(), + array_filter( + array_filter( + $plugin->getServer()->getOnlinePlayers(), + fn(Player $player2) => $player2->getWorld()->getFolderName() === $plot->levelName + ), + fn(Player $player2) => $plugin->getPlotFast($player2->getPosition()->x, $player2->getPosition()->z, $plugin->getLevelSettings($player2->getWorld()->getFolderName()))?->isSame($plot) + ) ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("kick.name").' "'.$this->players[$response->getInt("0")].'"', true); - } + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("kick.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/NameForm.php b/src/MyPlot/forms/subforms/NameForm.php index 0dad5994..f9f64666 100644 --- a/src/MyPlot/forms/subforms/NameForm.php +++ b/src/MyPlot/forms/subforms/NameForm.php @@ -1,33 +1,30 @@ setPlot($plot); +class NameForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + if(!$plot instanceof SinglePlot) + throw new \InvalidArgumentException("Plot must be a SinglePlot"); - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("name.form")]), - [ - new Input( - "0", - $plugin->getLanguage()->get("name.formtitle"), - $player->getDisplayName()."'s Plot", - $this->plot->name - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("name.name").' "'.$response->getString("0").'"', true); - } + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("name.form")])); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("name.formtitle"), + $player->getDisplayName() . "'s Plot", + $plot->name + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("name.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/OwnerForm.php b/src/MyPlot/forms/subforms/OwnerForm.php index edc9ed9d..bc98e232 100644 --- a/src/MyPlot/forms/subforms/OwnerForm.php +++ b/src/MyPlot/forms/subforms/OwnerForm.php @@ -1,38 +1,29 @@ getServer()->getOnlinePlayers() as $player) { - $players[] = $player->getDisplayName(); - $this->players[] = $player->getName(); - } - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("setowner.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("setowner.dropdown"), - $players + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("setowner.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("setowner.dropdown"), + ...array_map( + fn(Player $player) => $player->getDisplayName(), + $plugin->getServer()->getOnlinePlayers() ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("setowner.name").' "'.$this->players[$response->getInt("0")].'"', true); - } + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("setowner.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/RemoveHelperForm.php b/src/MyPlot/forms/subforms/RemoveHelperForm.php index 96bf89f8..00af7758 100644 --- a/src/MyPlot/forms/subforms/RemoveHelperForm.php +++ b/src/MyPlot/forms/subforms/RemoveHelperForm.php @@ -1,35 +1,31 @@ setPlot($plot); - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("removehelper.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("removehelper.dropdown"), - count($this->plot->helpers) < 1 ? [TextFormat::DARK_BLUE.$plugin->getLanguage()->get("removehelper.formnohelpers")] : array_map(function(string $text) { - return TextFormat::DARK_BLUE.$text; - }, $this->plot->helpers) - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - if(count($this->plot->helpers) < 1) - return; - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("removehelper.name").' "'.$this->plot->helpers[$response->getInt("0")].'"', true); - } +class RemoveHelperForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + if(!$plot instanceof SinglePlot) + throw new \InvalidArgumentException("Plot must be a SinglePlot"); + + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("removehelper.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("removehelper.dropdown"), + ...(count($plot->helpers) < 1 ? [TextFormat::DARK_BLUE . $plugin->getLanguage()->get("removehelper.formnohelpers")] : array_map(function(string $text){ + return TextFormat::DARK_BLUE . $text; + }, $plot->helpers)) + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("removehelper.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/UndenyPlayerForm.php b/src/MyPlot/forms/subforms/UndenyPlayerForm.php index 389224cb..5f980dd4 100644 --- a/src/MyPlot/forms/subforms/UndenyPlayerForm.php +++ b/src/MyPlot/forms/subforms/UndenyPlayerForm.php @@ -1,35 +1,31 @@ setPlot($plot); - parent::__construct( - TextFormat::BLACK.$plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("undenyplayer.form")]), - [ - new Dropdown( - "0", - $plugin->getLanguage()->get("undenyplayer.dropdown"), - count($this->plot->denied) < 1 ? [TextFormat::DARK_BLUE.$plugin->getLanguage()->get("undenyplayer.formnodenied")] : array_map(function(string $text) { - return TextFormat::DARK_BLUE.$text; - }, $this->plot->denied) - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - if(count($this->plot->denied) < 1) - return; - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("undenyplayer.name").' "'.$this->plot->denied[$response->getInt("0")].'"', true); - } +class UndenyPlayerForm extends CustomForm implements MyPlotForm{ + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + if(!$plot instanceof SinglePlot) + throw new \InvalidArgumentException("Plot must be a SinglePlot"); + + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("undenyplayer.form")])); + $this->addEntry( + new DropdownEntry( + $plugin->getLanguage()->get("undenyplayer.dropdown"), + ...(count($plot->denied) < 1 ? [TextFormat::DARK_BLUE . $plugin->getLanguage()->get("undenyplayer.formnodenied")] : array_map(function(string $text){ + return TextFormat::DARK_BLUE . $text; + }, $plot->denied)) + ), + \Closure::fromCallable(fn(Player $player, DropdownEntry $entry) => $plugin->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("undenyplayer.name") . ' "' . $entry->getValue() . '"', true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/forms/subforms/WarpForm.php b/src/MyPlot/forms/subforms/WarpForm.php index d8bfcfdd..6160c060 100644 --- a/src/MyPlot/forms/subforms/WarpForm.php +++ b/src/MyPlot/forms/subforms/WarpForm.php @@ -1,55 +1,41 @@ getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("warp.form")]), - [ - new Input( - "0", - $plugin->getLanguage()->get("warp.formxcoord"), - "2" - ), - new Input( - "1", - $plugin->getLanguage()->get("warp.formzcoord"), - "-4" - ), - new Input( - "2", - $plugin->getLanguage()->get("warp.formworld"), - "world", - $player->getWorld()->getFolderName() - ) - ], - function(Player $player, CustomFormResponse $response) use ($plugin) : void { - if(is_numeric($response->getString("0")) and is_numeric($response->getString("1")) and $plugin->isLevelLoaded($response->getString("2"))) - $data =[ - (int)$response->getString("0"), - (int)$response->getString("1"), - $response->getString("2") === '' ? $player->getWorld()->getFolderName() : $response->getString("2") - ]; - elseif($response->getString("0") === '' and $response->getString("1") === '') { - $player->sendForm(new self($player)); - throw new FormValidationException("Invalid form data returned"); - }else - throw new FormValidationException("Unexpected form data returned"); +class WarpForm extends CustomForm implements MyPlotForm{ - $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name")." ".$plugin->getLanguage()->get("warp.name")." $data[0];$data[1] $data[2]", true); - } + public function __construct(MyPlot $plugin, Player $player, ?BasePlot $plot){ + parent::__construct(TextFormat::BLACK . $plugin->getLanguage()->translateString("form.header", [$plugin->getLanguage()->get("warp.form")])); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("warp.formxcoord"), + "2" + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plot->X = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("warp.formzcoord"), + "-4" + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $plot->Z = (int) $entry->getValue()) + ); + $this->addEntry( + new InputEntry( + $plugin->getLanguage()->get("warp.formworld"), + $player->getWorld()->getFolderName() + ), + \Closure::fromCallable(fn(Player $player, InputEntry $entry) => $player->getServer()->dispatchCommand($player, $plugin->getLanguage()->get("command.name") . " " . $plugin->getLanguage()->get("warp.name") . " $plot->X;$plot->Z {$entry->getValue()}", true)) ); } } \ No newline at end of file diff --git a/src/MyPlot/plot/BasePlot.php b/src/MyPlot/plot/BasePlot.php new file mode 100644 index 00000000..4c8f0b71 --- /dev/null +++ b/src/MyPlot/plot/BasePlot.php @@ -0,0 +1,27 @@ +levelName === $plot->levelName and $this->X === $plot->X and $this->Z === $plot->Z; + } + + public function getSide(int $side, int $step = 1) : BasePlot{ + return match ($side) { + Facing::NORTH => new BasePlot($this->levelName, $this->X, $this->Z - $step), + Facing::SOUTH => new BasePlot($this->levelName, $this->X, $this->Z + $step), + Facing::EAST => new BasePlot($this->levelName, $this->X + $step, $this->Z), + Facing::WEST => new BasePlot($this->levelName, $this->X - $step, $this->Z), + default => throw new \InvalidArgumentException("Invalid side: " . Facing::toString($side)) + }; + } + + public function __toString() : string{ + return "($this->X;$this->Z)"; + } +} \ No newline at end of file diff --git a/src/MyPlot/plot/MergedPlot.php b/src/MyPlot/plot/MergedPlot.php new file mode 100644 index 00000000..39c0116c --- /dev/null +++ b/src/MyPlot/plot/MergedPlot.php @@ -0,0 +1,90 @@ +levelName, + $plot->X, + $plot->Z, + $xWidth, + $zWidth, + $plot->name, + $plot->owner, + $plot->helpers, + $plot->denied, + $plot->biome, + $plot->pvp, + $plot->price + ); + } + + /** + * TODO: description + * + * @api + * + * @param SinglePlot $plot + * + * @return bool + */ + public function isSame(BasePlot $plot) : bool{ + if(parent::isSame($plot)) + return true; + + return ( + new AxisAlignedBB( + $this->X, + 0, + $this->Z, + $this->X + $this->xWidth, + 1, + $this->Z + $this->zWidth + ) + )->isVectorInXZ(new Vector3($plot->X, 0, $plot->Z)); + } + + public function getSide(int $side, int $step = 1) : BasePlot{ + $axis = Facing::axis($side); + $isPositive = Facing::isPositive($side); + if($axis === Axis::X){ + if($isPositive){ + return parent::getSide($side, $step + $this->xWidth); + } + return parent::getSide($side, $step); + }elseif($axis === Axis::Z){ + if($isPositive){ + return parent::getSide($side, $step + $this->zWidth); + } + return parent::getSide($side, $step); + } + throw new \InvalidArgumentException("Invalid Axis " . $axis); + } +} \ No newline at end of file diff --git a/src/MyPlot/plot/SinglePlot.php b/src/MyPlot/plot/SinglePlot.php new file mode 100644 index 00000000..39f13666 --- /dev/null +++ b/src/MyPlot/plot/SinglePlot.php @@ -0,0 +1,131 @@ +biome = strtoupper($biome); + $settings = MyPlot::getInstance()->getLevelSettings($levelName); + if(!isset($pvp)){ + $this->pvp = !$settings->restrictPVP; + }else{ + $this->pvp = $pvp; + } + if(MyPlot::getInstance()->getEconomyProvider() !== null) + $this->price = $price < 0 ? $settings->claimPrice : $price; + else + $this->price = 0; + } + + public static function fromBase(BasePlot $plot, string $name = '', string $owner = '', array $helpers = [], array $denied = [], string $biome = "PLAINS", ?bool $pvp = null, int $price = -1) : SinglePlot{ + return new SinglePlot( + $plot->levelName, + $plot->X, + $plot->Z, + $name, + $owner, + $helpers, + $denied, + $biome, + $pvp, + $price + ); + } + + /** + * @param string $username + * + * @return bool + * @api + * + */ + public function isHelper(string $username) : bool{ + return in_array($username, $this->helpers, true); + } + + /** + * @api + * + * @param string $username + * + * @return bool + */ + public function addHelper(string $username) : bool{ + if(!$this->isHelper($username)){ + $this->unDenyPlayer($username); + $this->helpers[] = $username; + return true; + } + return false; + } + + /** + * @api + * + * @param string $username + * + * @return bool + */ + public function removeHelper(string $username) : bool{ + if(!$this->isHelper($username)){ + return false; + } + $key = array_search($username, $this->helpers, true); + if($key === false){ + return false; + } + unset($this->helpers[$key]); + return true; + } + + /** + * @api + * + * @param string $username + * + * @return bool + */ + public function isDenied(string $username) : bool{ + return in_array($username, $this->denied, true); + } + + /** + * @api + * + * @param string $username + * + * @return bool + */ + public function denyPlayer(string $username) : bool{ + if(!$this->isDenied($username)){ + $this->removeHelper($username); + $this->denied[] = $username; + return true; + } + return false; + } + + /** + * @api + * + * @param string $username + * + * @return bool + */ + public function unDenyPlayer(string $username) : bool{ + if(!$this->isDenied($username)){ + return false; + } + $key = array_search($username, $this->denied, true); + if($key === false){ + return false; + } + unset($this->denied[$key]); + return true; + } +} \ No newline at end of file diff --git a/src/MyPlot/provider/ConfigDataProvider.php b/src/MyPlot/provider/ConfigDataProvider.php deleted file mode 100644 index 1ffaba1a..00000000 --- a/src/MyPlot/provider/ConfigDataProvider.php +++ /dev/null @@ -1,209 +0,0 @@ -plugin->getDataFolder() . "Data"); - $this->config = new Config($this->plugin->getDataFolder() . "Data" . DIRECTORY_SEPARATOR . "plots".($yaml ? '.yml' : '.json'), $yaml ? Config::YAML : Config::JSON, ["plots" => [], "merges" => []]); - } - - public function savePlot(Plot $plot) : bool { - $plotId = $plot->levelName.';'.$plot->X.';'.$plot->Z; - $plots = $this->config->get("plots", []); - $plots[$plotId] = ["level" => $plot->levelName, "x" => $plot->X, "z" => $plot->Z, "name" => $plot->name, "owner" => $plot->owner, "helpers" => $plot->helpers, "denied" => $plot->denied, "biome" => $plot->biome, "pvp" => $plot->pvp, "price" => $plot->price]; - $this->config->set("plots", $plots); - $this->cachePlot($plot); - $this->config->save(); - return true; - } - - public function deletePlot(Plot $plot) : bool { - $plotId = $plot->levelName.';'.$plot->X.';'.$plot->Z; - $plots = $this->config->get("plots", []); - unset($plots[$plotId]); - $this->config->set("plots", $plots); - $plot = new Plot($plot->levelName, $plot->X, $plot->Z); - $this->cachePlot($plot); - $this->config->save(); - return true; - } - - public function getPlot(string $levelName, int $X, int $Z) : Plot { - if(($plot = $this->getPlotFromCache($levelName, $X, $Z)) !== null) { - return $plot; - } - $plots = (array)$this->config->get("plots", []); - $key = $levelName.';'.$X.';'.$Z; - if(isset($plots[$key])) { - $plotName = (string)$plots[$key]["name"]; - $owner = (string)$plots[$key]["owner"]; - $helpers = (array)$plots[$key]["helpers"]; - $denied = (array)$plots[$key]["denied"]; - $biome = strtoupper($plots[$key]["biome"]); - $pvp = (bool)$plots[$key]["pvp"]; - $price = (float)$plots[$key]["price"]; - return new Plot($levelName, $X, $Z, $plotName, $owner, $helpers, $denied, $biome, $pvp, $price); - } - return new Plot($levelName, $X, $Z); - } - - /** - * @param string $owner - * @param string $levelName - * - * @return Plot[] - */ - public function getPlotsByOwner(string $owner, string $levelName = "") : array { - $plots = $this->config->get("plots", []); - $ownerPlots = []; - /** @var string[] $ownerKeys */ - $ownerKeys = array_keys($plots, ["owner" => $owner], true); - foreach($ownerKeys as $ownerKey) { - if($levelName === "" or str_contains($ownerKey, $levelName)) { - $X = $plots[$ownerKey]["x"]; - $Z = $plots[$ownerKey]["z"]; - $plotName = $plots[$ownerKey]["name"] == "" ? "" : $plots[$ownerKey]["name"]; - $owner = $plots[$ownerKey]["owner"] == "" ? "" : $plots[$ownerKey]["owner"]; - $helpers = $plots[$ownerKey]["helpers"] == [] ? [] : $plots[$ownerKey]["helpers"]; - $denied = $plots[$ownerKey]["denied"] == [] ? [] : $plots[$ownerKey]["denied"]; - $biome = strtoupper($plots[$ownerKey]["biome"]) == "PLAINS" ? "PLAINS" : strtoupper($plots[$ownerKey]["biome"]); - $pvp = $plots[$ownerKey]["pvp"] == null ? false : $plots[$ownerKey]["pvp"]; - $price = $plots[$ownerKey]["price"] == null ? 0 : $plots[$ownerKey]["price"]; - $ownerPlots[] = new Plot($levelName, $X, $Z, $plotName, $owner, $helpers, $denied, $biome, $pvp, $price); - } - } - return $ownerPlots; - } - - public function getNextFreePlot(string $levelName, int $limitXZ = 0) : ?Plot { - $plotsArr = $this->config->get("plots", []); - for($i = 0; $limitXZ <= 0 or $i < $limitXZ; $i++) { - $existing = []; - foreach($plotsArr as $data) { - if($data["level"] === $levelName) { - if(abs($data["x"]) === $i and abs($data["z"]) <= $i) { - $existing[] = [$data["x"], $data["z"]]; - }elseif(abs($data["z"]) === $i and abs($data["x"]) <= $i) { - $existing[] = [$data["x"], $data["z"]]; - } - } - } - $plots = []; - foreach($existing as $XZ) { - $plots[$XZ[0]][$XZ[1]] = true; - } - if(count($plots) === max(1, 8 * $i)) { - continue; - } - if(($ret = self::findEmptyPlotSquared(0, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - for($a = 1; $a < $i; $a++) { - if(($ret = self::findEmptyPlotSquared($a, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - if(($ret = self::findEmptyPlotSquared($i, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - return null; - } - - public function mergePlots(Plot $base, Plot ...$plots) : bool { - $originId = $base->levelName.';'.$base->X.';'.$base->Z; - $mergedIds = $this->config->getNested("merges.$originId", []); - $mergedIds = array_merge($mergedIds, array_map(function(Plot $val) : string { - return $val->levelName.';'.$val->X.';'.$val->Z; - }, $plots)); - $mergedIds = array_unique($mergedIds, SORT_NUMERIC); - $this->config->setNested("merges.$originId", $mergedIds); - $this->config->save(); - return true; - } - - public function getMergedPlots(Plot $plot, bool $adjacent = false) : array { - $originId = $plot->levelName.';'.$plot->X.';'.$plot->Z; - $mergedIds = $this->config->getNested("merges.$originId", []); - $plotDatums = $this->config->get("plots", []); - $plots = [$plot]; - foreach($mergedIds as $mergedId) { - if(!isset($plotDatums[$mergedId])) - continue; - $levelName = $plotDatums[$mergedId]["level"]; - $X = $plotDatums[$mergedId]["x"]; - $Z = $plotDatums[$mergedId]["z"]; - $plotName = $plotDatums[$mergedId]["name"] == "" ? "" : $plotDatums[$mergedId]["name"]; - $owner = $plotDatums[$mergedId]["owner"] == "" ? "" : $plotDatums[$mergedId]["owner"]; - $helpers = $plotDatums[$mergedId]["helpers"] == [] ? [] : $plotDatums[$mergedId]["helpers"]; - $denied = $plotDatums[$mergedId]["denied"] == [] ? [] : $plotDatums[$mergedId]["denied"]; - $biome = strtoupper($plotDatums[$mergedId]["biome"]) == "PLAINS" ? "PLAINS" : strtoupper($plotDatums[$mergedId]["biome"]); - $pvp = $plotDatums[$mergedId]["pvp"] == null ? false : $plotDatums[$mergedId]["pvp"]; - $price = $plotDatums[$mergedId]["price"] == null ? 0 : $plotDatums[$mergedId]["price"]; - $plots[] = new Plot($levelName, $X, $Z, $plotName, $owner, $helpers, $denied, $biome, $pvp, $price); - } - if($adjacent) - $plots = array_filter($plots, function(Plot $val) use ($plot) { - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - if($plot->getSide($i)->isSame($val)) - return true; - } - return false; - }); - return $plots; - } - - public function getMergeOrigin(Plot $plot) : Plot { - $mergedIdString = $plot->levelName.';'.$plot->X.';'.$plot->Z; - $allMerges = $this->config->get("merges", []); - if(isset($allMerges[$mergedIdString])) - return $plot; - $originId = array_search($mergedIdString, $allMerges, true); - $plotDatums = $this->config->get("plots", []); - if(isset($plotDatums[$originId])) { - $levelName = $plotDatums[$originId]["level"]; - $X = $plotDatums[$originId]["x"]; - $Z = $plotDatums[$originId]["z"]; - $plotName = $plotDatums[$originId]["name"] == "" ? "" : $plotDatums[$originId]["name"]; - $owner = $plotDatums[$originId]["owner"] == "" ? "" : $plotDatums[$originId]["owner"]; - $helpers = $plotDatums[$originId]["helpers"] == [] ? [] : $plotDatums[$originId]["helpers"]; - $denied = $plotDatums[$originId]["denied"] == [] ? [] : $plotDatums[$originId]["denied"]; - $biome = strtoupper($plotDatums[$originId]["biome"]) == "PLAINS" ? "PLAINS" : strtoupper($plotDatums[$originId]["biome"]); - $pvp = $plotDatums[$originId]["pvp"] == null ? false : $plotDatums[$originId]["pvp"]; - $price = $plotDatums[$originId]["price"] == null ? 0 : $plotDatums[$originId]["price"]; - return new Plot($levelName, $X, $Z, $plotName, $owner, $helpers, $denied, $biome, $pvp, $price); - } - return $plot; - } - - public function close() : void { - $this->config->save(); - unset($this->config); - } -} \ No newline at end of file diff --git a/src/MyPlot/provider/DataProvider.php b/src/MyPlot/provider/DataProvider.php index 7cea29c2..dd780d7c 100644 --- a/src/MyPlot/provider/DataProvider.php +++ b/src/MyPlot/provider/DataProvider.php @@ -2,34 +2,70 @@ declare(strict_types=1); namespace MyPlot\provider; +use MyPlot\InternalAPI; use MyPlot\MyPlot; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; +use MyPlot\plot\MergedPlot; +use MyPlot\plot\SinglePlot; +use poggit\libasynql\DataConnector; +use poggit\libasynql\libasynql; +use poggit\libasynql\SqlThread; +use SOFe\AwaitGenerator\Await; -abstract class DataProvider -{ - /** @var Plot[] $cache */ +final class DataProvider{ + + /** @var BasePlot[] $cache */ private array $cache = []; private int $cacheSize; - protected MyPlot $plugin; + private DataConnector $database; - /** - * DataProvider constructor. - * - * @param MyPlot $plugin - * @param int $cacheSize - */ - public function __construct(MyPlot $plugin, int $cacheSize = 0) { - $this->plugin = $plugin; - $this->cacheSize = $cacheSize; + /** @noinspection PhpVoidFunctionResultUsedInspection */ + public function __construct(private MyPlot $plugin, InternalAPI $internalAPI){ + $this->database = libasynql::create($plugin, $plugin->getConfig()->get("Database"), [ + 'sqlite' => 'sqlite.sql', + 'mysql' => 'mysql.sql', + ], true); + $this->database->executeGeneric('myplot.init.plots'); + $this->database->executeGeneric('myplot.init.mergedPlots'); + $this->database->executeSelect( + 'myplot.test.table', + ['tableName' => 'plotsV2'], + fn(array $rows) => $rows[0]['tables'] === 0 ?: $this->database->executeMulti('myplot.convert.tables', [], SqlThread::MODE_CHANGE) + ); + $this->cacheSize = $plugin->getConfig()->get("PlotCacheSize", 2500); + $maxPlotCoord = floor(sqrt($this->cacheSize) / 2); + foreach($internalAPI->getAllLevelSettings() as $levelName => $settings){ + for($x = -$maxPlotCoord; $x < $maxPlotCoord; ++$x){ + for($z = -$maxPlotCoord; $z < $maxPlotCoord; ++$z){ + Await::g2c( + $this->getMergedPlot(new BasePlot($levelName, $x, $z)) + ); + } + } + } } - protected final function cachePlot(Plot $plot) : void { - if($this->cacheSize > 0) { + private function cachePlot(BasePlot $plot) : void{ + if($this->cacheSize > 0){ + if($plot instanceof MergedPlot){ + for($x = $plot->X; $x <= $plot->xWidth + $plot->X; ++$x){ + for($z = $plot->Z; $z <= $plot->zWidth + $plot->Z; ++$z){ + $key = $plot->levelName . ';' . $x . ';' . $z; + if(isset($this->cache[$key])){ + unset($this->cache[$key]); + }elseif($this->cacheSize <= count($this->cache)){ + array_shift($this->cache); + } + $this->cache = array_merge([$key => clone $plot], $this->cache); + $this->plugin->getLogger()->debug("Plot $x;$z has been cached"); + } + } + return; + } $key = $plot->levelName . ';' . $plot->X . ';' . $plot->Z; - if(isset($this->cache[$key])) { + if(isset($this->cache[$key])){ unset($this->cache[$key]); - } - elseif($this->cacheSize <= count($this->cache)) { + }elseif($this->cacheSize <= count($this->cache)){ array_shift($this->cache); } $this->cache = array_merge([$key => clone $plot], $this->cache); @@ -37,71 +73,275 @@ protected final function cachePlot(Plot $plot) : void { } } - protected final function getPlotFromCache(string $levelName, int $X, int $Z) : ?Plot { - if($this->cacheSize > 0) { + public function getPlotFromCache(string $levelName, int $X, int $Z) : BasePlot{ + if($this->cacheSize > 0){ $key = $levelName . ';' . $X . ';' . $Z; - if(isset($this->cache[$key])) { - #$this->plugin->getLogger()->debug("Plot {$X};{$Z} was loaded from the cache"); - return $this->cache[$key]; + if(isset($this->cache[$key])){ + $this->plugin->getLogger()->debug("Plot {$X};{$Z} was loaded from the cache"); + return $this->cache[$key] ?? new BasePlot($levelName, $X, $Z); } } - return null; + return new BasePlot($levelName, $X, $Z); } - public abstract function savePlot(Plot $plot) : bool; + /** + * @param SinglePlot $plot + * + * @return \Generator + */ + public function savePlot(SinglePlot $plot) : \Generator{ + [$insertId, $affectedRows] = yield from $this->database->asyncInsert('myplot.add.plot', [ + 'level' => $plot->levelName, + 'X' => $plot->X, + 'Z' => $plot->Z, + 'name' => $plot->name, + 'owner' => $plot->owner, + 'helpers' => implode(",", $plot->helpers), + 'denied' => implode(",", $plot->denied), + 'biome' => $plot->biome, + 'pvp' => $plot->pvp, + 'price' => $plot->price, + ]); + if($affectedRows < 1){ + return false; + } + $this->cachePlot($plot); + return true; + } - public abstract function deletePlot(Plot $plot) : bool; + /** + * @param BasePlot $plot + * + * @return \Generator + */ + public function deletePlot(BasePlot $plot) : \Generator{ + if($plot instanceof MergedPlot){ + $plotLevel = $this->plugin->getLevelSettings($plot->levelName); + + $changedRows = yield from $this->database->asyncChange('myplot.remove.merge.by-xz', [ + 'level' => $plot->levelName, + 'X' => $plot->X, + 'Z' => $plot->Z, + 'pvp' => !$plotLevel->restrictPVP, + 'price' => $plotLevel->claimPrice, + ]); + $this->cachePlot(new MergedPlot($plot->levelName, $plot->X, $plot->Z, $plot->xWidth, $plot->zWidth, pvp: !$plotLevel->restrictPVP, price: $plotLevel->claimPrice)); + }else{ + $changedRows = yield from $this->database->asyncChange('myplot.remove.plot.by-xz', [ + 'level' => $plot->levelName, + 'X' => $plot->X, + 'Z' => $plot->Z, + ]); + $this->cachePlot(new BasePlot($plot->levelName, $plot->X, $plot->Z)); + } + if($changedRows < 1){ + return false; + } + return true; + } + + /** + * @param string $levelName + * @param int $X + * @param int $Z + * + * @return \Generator + */ + public function getPlot(string $levelName, int $X, int $Z) : \Generator{ + $plot = $this->getPlotFromCache($levelName, $X, $Z); + if($plot instanceof SinglePlot){ + return $plot; + } + $row = (yield from $this->database->asyncSelect('myplot.get.plot.by-xz', [ + 'level' => $levelName, + 'X' => $X, + 'Z' => $Z + ]))[0]; + if(count($row) < 1) + return $plot; - public abstract function getPlot(string $levelName, int $X, int $Z) : Plot; + return new SinglePlot($levelName, $X, $Z, $row['name'], $row['owner'], explode(",", $row['helpers']), explode(",", $row['denied']), $row['biome'], (bool) $row['pvp'], $row['price']); + } /** * @param string $owner * @param string $levelName * - * @return Plot[] + * @return \Generator> */ - public abstract function getPlotsByOwner(string $owner, string $levelName = "") : array; + public function getPlotsByOwner(string $owner, string $levelName = "") : \Generator{ + if($levelName !== ''){ + $rows = yield from $this->database->asyncSelect('myplot.get.all-plots.by-owner-and-level', [ + 'owner' => $owner, + 'level' => $levelName, + ]); + }else{ + $rows = yield from $this->database->asyncSelect('myplot.get.all-plots.by-owner', [ + 'owner' => $owner, + ]); + } + $plots = []; + foreach($rows as $row){ + $plots[] = yield from $this->getMergedPlot(new BasePlot($row['level'], $row['X'], $row['Z'])); + } + return $plots; + } + + /** + * @param string $levelName + * @param int $limitXZ + * + * @return \Generator + */ + public function getNextFreePlot(string $levelName, int $limitXZ = 0) : \Generator{ + for($i = 0; $limitXZ <= 0 or $i < $limitXZ; $i++){ + $rows = yield from $this->database->asyncSelect('myplot.get.highest-existing.by-interval', [ + 'level' => $levelName, + 'number' => $i, + ]); + $plots = []; + foreach($rows as $row){ + $plots[$row['X']][$row['Z']] = true; + } + if(count($plots) === max(1, 8 * $i)){ + continue; + } + for($a = 0; $a <= $i; $a++){ + if(($ret = self::findEmptyPlotSquared($a, $i, $plots)) !== null){ + [$X, $Z] = $ret; + return new BasePlot($levelName, $X, $Z); + } + } + } + return null; + } - public abstract function getNextFreePlot(string $levelName, int $limitXZ = 0) : ?Plot; + /** + * @param MergedPlot $base + * @param BasePlot ...$plots + * + * @return \Generator + */ + public function mergePlots(MergedPlot $base, BasePlot ...$plots) : \Generator{ + $minX = 0; + $minZ = 0; + foreach($plots as $plot){ + if(min($minX, $plot->X)) + $minX = $plot->X; + if(min($minZ, $plot->Z)) + $minZ = $plot->Z; + } - public abstract function mergePlots(Plot $base, Plot ...$plots) : bool; + $ret = true; + foreach($plots as $plot){ + if($minX !== $base->X and $minZ !== $base->Z){ + $affectedRows = yield from $this->database->asyncChange('myplot.remove.merge-entry', [ + 'level' => $plot->levelName, + 'originX' => $base->X, + 'originZ' => $base->Z, + 'mergedX' => $plot->X, + 'mergedZ' => $plot->Z + ]); + if($affectedRows < 1){ + MyPlot::getInstance()->getLogger()->debug("Failed to delete merge entry for $plot with base $base"); + $ret = false; + } + } + [$insertId, $affectedRows] = yield from $this->database->asyncInsert('myplot.add.merge', [ + 'level' => $plot->levelName, + 'originX' => $minX, + 'originZ' => $minZ, + 'mergedX' => $plot->X, + 'mergedZ' => $plot->Z + ]); + if($affectedRows < 1){ + MyPlot::getInstance()->getLogger()->debug("Failed to merge plot $plot into $base"); + $ret = false; + } + } + return $ret; + } /** - * @param Plot $plot - * @param bool $adjacent - * @return Plot[] + * @param BasePlot $plot + * + * @return \Generator */ - public abstract function getMergedPlots(Plot $plot, bool $adjacent = false) : array; + public function getMergedPlot(BasePlot $plot) : \Generator{ + $plot = $this->getPlotFromCache($plot->levelName, $plot->X, $plot->Z); + if($plot instanceof MergedPlot) + return $plot; - public abstract function getMergeOrigin(Plot $plot) : Plot; + $rows = yield from $this->database->asyncSelect('myplot.get.merge-plots.by-origin', [ + 'level' => $plot->levelName, + 'originX' => $plot->X, + 'originZ' => $plot->Z + ]); + if(count($rows) < 1){ + $rows = yield from $this->database->asyncSelect('myplot.get.merge-plots.by-merged', [ + 'level' => $plot->levelName, + 'mergedX' => $plot->X, + 'mergedZ' => $plot->Z + ]); + if(count($rows) < 1){ + return yield from $this->getPlot($plot->levelName, $plot->X, $plot->Z); + } + } + $highestX = $highestZ = $lowestX = $lowestZ = 0; + foreach($rows as $row){ + $highestX = max($highestX, $row['X']); + $highestZ = max($highestZ, $row['Z']); + $lowestX = min($lowestX, $row['X']); + $lowestZ = min($lowestZ, $row['Z']); + } - public abstract function close() : void; + $plot = new MergedPlot( + $rows[0]["level"], + $rows[0]["X"], + $rows[0]["Z"], + $highestX - $lowestX, + $highestZ - $lowestZ, + $rows[0]["name"], + $rows[0]["owner"], + explode(",", $rows[0]["helpers"]), + explode(",", $rows[0]["denied"]), + $rows[0]["biome"], + is_numeric($rows[0]["pvp"]) ? (bool) $rows[0]["pvp"] : null, + $rows[0]["price"] * ($highestX - $lowestX) * ($highestZ - $lowestZ) + ); + $this->cachePlot($plot); + return $plot; + } + + public function close() : void{ + $this->database->close(); + } /** - * @param int $a - * @param int $b + * @param int $a + * @param int $b * @param bool[][] $plots * * @return int[]|null */ - protected static function findEmptyPlotSquared(int $a, int $b, array $plots) : ?array { + private static function findEmptyPlotSquared(int $a, int $b, array $plots) : ?array{ if(!isset($plots[$a][$b])) return [$a, $b]; if(!isset($plots[$b][$a])) return [$b, $a]; - if($a !== 0) { + if($a !== 0){ if(!isset($plots[-$a][$b])) return [-$a, $b]; if(!isset($plots[$b][-$a])) return [$b, -$a]; } - if($b !== 0) { + if($b !== 0){ if(!isset($plots[-$b][$a])) return [-$b, $a]; if(!isset($plots[$a][-$b])) return [$a, -$b]; } - if(($a | $b) === 0) { + if(($a | $b) === 0){ if(!isset($plots[-$a][-$b])) return [-$a, -$b]; if(!isset($plots[-$b][-$a])) diff --git a/src/MyPlot/provider/EconomyProvider.php b/src/MyPlot/provider/EconomyProvider.php deleted file mode 100644 index d986ae4c..00000000 --- a/src/MyPlot/provider/EconomyProvider.php +++ /dev/null @@ -1,12 +0,0 @@ -plugin = $plugin; - } - - public function reduceMoney(Player $player, float $amount) : bool { - if($amount == 0) { - return true; - }elseif($amount < 0) { - $amount = -$amount; - } - $ret = $this->plugin->reduceMoney($player, $amount, true, "MyPlot"); - if($ret === EconomyAPI::RET_SUCCESS) { - $this->plugin->getLogger()->debug("MyPlot Reduced money of " . $player->getName()); - return true; - } - $this->plugin->getLogger()->debug("MyPlot failed to reduce money of ".$player->getName()); - return false; - } - - public function addMoney(IPlayer $player, float $amount) : bool { - if($amount < 1) - return true; - $ret = $this->plugin->addMoney($player->getName(), $amount, true, "MyPlot"); - if($ret === EconomyAPI::RET_SUCCESS) { - $this->plugin->getLogger()->debug("MyPlot Add money of " . $player->getName()); - return true; - } - $this->plugin->getLogger()->debug("MyPlot failed to add money of ".$player->getName()); - return false; - } -} \ No newline at end of file diff --git a/src/MyPlot/provider/EconomyWrapper.php b/src/MyPlot/provider/EconomyWrapper.php new file mode 100644 index 00000000..c9e15dbf --- /dev/null +++ b/src/MyPlot/provider/EconomyWrapper.php @@ -0,0 +1,53 @@ +provider->reduceMoney($player, $amount, $reason), + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); + } + + /** + * @inheritDoc + */ + public function addMoney(Player $player, int $amount, string $reason = "Unknown") : Promise{ + $resolver = new PromiseResolver(); + Await::g2c( + $this->provider->addMoney($player, $amount, $reason), + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); + } + + /** + * @inheritDoc + */ + public function transactMoney(Player $player1, Player $player2, int $amount, string $reason = "Unknown") : Promise{ + $resolver = new PromiseResolver(); + Await::g2c( + $this->provider->transactMoney($player1, $player2, $amount, $reason), + fn(bool $success) => $resolver->resolve($success), + fn(\Throwable $e) => $resolver->reject() + ); + return $resolver->getPromise(); + } +} \ No newline at end of file diff --git a/src/MyPlot/provider/InternalBedrockEconomyProvider.php b/src/MyPlot/provider/InternalBedrockEconomyProvider.php new file mode 100644 index 00000000..53a58956 --- /dev/null +++ b/src/MyPlot/provider/InternalBedrockEconomyProvider.php @@ -0,0 +1,75 @@ +api->subtractFromPlayerBalance( + $player->getName(), + $amount, + ClosureContext::create( + static function(bool $response, callable $stopRunning, ?string $error) use ($onSuccess, $onError) : void{ + $error === null ?: $onError($error); + $onSuccess($response); + } + ), + 'MyPlot' + ); + return yield Await::ONCE; + } + + /** + * @inheritDoc + */ + public function addMoney(Player $player, int $amount, string $reason = "Unknown") : \Generator{ + $onSuccess = yield Await::RESOLVE; + $onError = yield Await::REJECT; + $this->api->addToPlayerBalance( + $player->getName(), + $amount, + ClosureContext::create( + static function(bool $response, callable $stopRunning, ?string $error) use ($onSuccess, $onError) : void{ + $error === null ?: $onError($error); + $onSuccess($response); + } + ), + 'MyPlot' + ); + return yield Await::ONCE; + } + + /** + * @inheritDoc + */ + public function transactMoney(Player $player1, Player $player2, int $amount, string $reason = "Unknown") : \Generator{ + $onSuccess = yield Await::RESOLVE; + $onError = yield Await::REJECT; + $this->api->transferFromPlayerBalance( + $player1->getName(), + $player2->getName(), + $amount, + ClosureContext::create( + static function(bool $response, callable $stopRunning, ?string $error) use ($onSuccess, $onError) : void{ + $error === null ?: $onError($error); + $onSuccess($response); + } + ) + // no issuer for some reason + ); + return yield Await::ONCE; + } +} \ No newline at end of file diff --git a/src/MyPlot/provider/InternalCapitalProvider.php b/src/MyPlot/provider/InternalCapitalProvider.php new file mode 100644 index 00000000..1da921b5 --- /dev/null +++ b/src/MyPlot/provider/InternalCapitalProvider.php @@ -0,0 +1,65 @@ +selector = $api->completeConfig(null); // use null to get the default schema from Capital + }); + } + + /** + * @inheritDoc + */ + public function reduceMoney(Player $player, int $amount, string $reason = 'Unknown') : \Generator{ + /** @var Capital $api */ + $api = yield from Capital::get(MainClass::$context); + yield from $api->takeMoney( + oracleName: "MyPlot", + player: $player, + schema: $this->selector, + amount: $amount, + transactionLabels: new LabelSet(["reason" => $reason]), + ); + } + + /** + * @inheritDoc + */ + public function addMoney(Player $player, int $amount, string $reason = 'Unknown') : \Generator{ + /** @var Capital $api */ + $api = yield from Capital::get(MainClass::$context); + yield from $api->addMoney( + oracleName: "MyPlot", + player: $player, + schema: $this->selector, + amount: $amount, + transactionLabels: new LabelSet(["reason" => $reason]), + ); + } + + /** + * @inheritDoc + */ + public function transactMoney(Player $player1, Player $player2, int $amount, string $reason = 'Unknown') : \Generator{ + /** @var Capital $api */ + $api = yield from Capital::get(MainClass::$context); + yield from $api->pay( + src: $player1, + dest: $player2, + schema: $this->selector, + amount: $amount, + transactionLabels: new LabelSet(["reason" => $reason]), + ); + } +} \ No newline at end of file diff --git a/src/MyPlot/provider/InternalEconomyProvider.php b/src/MyPlot/provider/InternalEconomyProvider.php new file mode 100644 index 00000000..e511217d --- /dev/null +++ b/src/MyPlot/provider/InternalEconomyProvider.php @@ -0,0 +1,35 @@ + + */ + public function reduceMoney(Player $player, int $amount, string $reason = "Unknown") : \Generator; + + /** + * @param Player $player + * @param int $amount + * @param string $reason + * + * @return \Generator + */ + public function addMoney(Player $player, int $amount, string $reason = "Unknown") : \Generator; + + /** + * @param Player $player1 + * @param Player $player2 + * @param int $amount + * @param string $reason + * + * @return \Generator + */ + public function transactMoney(Player $player1, Player $player2, int $amount, string $reason = "Unknown") : \Generator; +} \ No newline at end of file diff --git a/src/MyPlot/provider/InternalEconomySProvider.php b/src/MyPlot/provider/InternalEconomySProvider.php new file mode 100644 index 00000000..02396bd4 --- /dev/null +++ b/src/MyPlot/provider/InternalEconomySProvider.php @@ -0,0 +1,62 @@ +plugin->reduceMoney($player, $amount, false, "MyPlot"); + if($ret === EconomyAPI::RET_SUCCESS){ + $this->plugin->getLogger()->debug("MyPlot Reduced money of " . $player->getName()); + return true; + } + return false; + } + + /** + * @inheritDoc + */ + public function addMoney(Player $player, int $amount, string $reason = "Unknown") : \Generator{ + 0 && yield; + if($amount === 0){ + return true; + } + $ret = $this->plugin->addMoney($player, $amount, false, "MyPlot"); + if($ret === EconomyAPI::RET_SUCCESS){ + return true; + } + return false; + } + + /** + * @inheritDoc + */ + public function transactMoney(Player $player1, Player $player2, int $amount, string $reason = "Unknown") : \Generator{ + 0 && yield; + if($amount < 1){ + return true; + } + $ret = $this->plugin->reduceMoney($player1, $amount, true, "MyPlot"); + if($ret !== EconomyAPI::RET_SUCCESS){ + return false; + } + $ret = $this->plugin->addMoney($player2, $amount, true, "MyPlot"); + if($ret !== EconomyAPI::RET_SUCCESS){ + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/MyPlot/provider/MySQLProvider.php b/src/MyPlot/provider/MySQLProvider.php deleted file mode 100644 index 63a35909..00000000 --- a/src/MyPlot/provider/MySQLProvider.php +++ /dev/null @@ -1,370 +0,0 @@ -plugin = $plugin; - parent::__construct($plugin, $cacheSize); - $this->settings = $settings; - $this->db = new \mysqli($settings['Host'], $settings['Username'], $settings['Password'], $settings['DatabaseName'], $settings['Port']); - if($this->db->connect_error !== null and $this->db->connect_error !== '') - throw new \RuntimeException("Failed to connect to the MySQL database: " . $this->db->connect_error); - $this->db->query("CREATE TABLE IF NOT EXISTS plotsV2 (level TEXT, X INT, Z INT, name TEXT, owner TEXT, helpers TEXT, denied TEXT, biome TEXT, pvp INT, price FLOAT, PRIMARY KEY (level, X, Z));"); - $res = $this->db->query("SELECT count(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='{$settings['DatabaseName']}' AND TABLE_NAME='plots'"); - if($res instanceof \mysqli_result and $res->fetch_array()[0] > 0) - $this->db->query("INSERT IGNORE INTO plotsV2 (level, X, Z, name, owner, helpers, denied, biome, pvp, price) SELECT level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plots;"); - $this->db->query("CREATE TABLE IF NOT EXISTS mergedPlotsV2 (level TEXT, originX INT, originZ INT, mergedX INT, mergedZ INT, PRIMARY KEY(level, originX, originZ, mergedX, mergedZ));"); - $res = $this->db->query("SELECT count(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='{$settings['DatabaseName']}' AND TABLE_NAME='mergedPlots';"); - if($res instanceof \mysqli_result and $res->fetch_array()[0] > 0) - $this->db->query("INSERT IGNORE INTO mergedPlotsV2 (level, originX, originZ, mergedX, mergedZ) SELECT r1.level, r1.X, r1.Z, r2.X, r2.Z FROM plots r1, mergedPlots JOIN plots r2 ON r1.id = mergedPlots.originId AND r2.id = mergedPlots.mergedId;"); - $this->prepare(); - $this->plugin->getLogger()->debug("MySQL data provider registered"); - } - - /** - * @throws \Exception - */ - public function savePlot(Plot $plot) : bool { - $this->reconnect(); - $helpers = implode(',', $plot->helpers); - $denied = implode(',', $plot->denied); - $stmt = $this->sqlSavePlot; - $stmt->bind_param('siisssssid', $plot->levelName, $plot->X, $plot->Z, $plot->name, $plot->owner, $helpers, $denied, $plot->biome, $plot->pvp, $plot->price); - $result = $stmt->execute(); - if($result === false) { - $this->plugin->getLogger()->error($stmt->error); - return false; - } - $this->cachePlot($plot); - return true; - } - - /** - * @throws \Exception - */ - public function deletePlot(Plot $plot) : bool { - $this->reconnect(); - $settings = MyPlot::getInstance()->getLevelSettings($plot->levelName); - if($plot->isMerged()) { - $stmt = $this->sqlDisposeMergedPlot; - $restrictPVP = !$settings->restrictPVP; - $stmt->bind_param('idsii', $restrictPVP, $settings->claimPrice, $plot->levelName, $plot->X, $plot->Z); - $result = $stmt->execute(); - if ($result === false) { - $this->plugin->getLogger()->error($stmt->error); - return false; - } - $plot = new Plot($plot->levelName, $plot->X, $plot->Z); - $this->cachePlot($this->getMergeOrigin($plot)); - }else{ - $stmt = $this->sqlRemovePlot; - $stmt->bind_param('sii', $plot->levelName, $plot->X, $plot->Z); - $result = $stmt->execute(); - if($result === false){ - $this->plugin->getLogger()->error($stmt->error); - return false; - } - $plot = new Plot($plot->levelName, $plot->X, $plot->Z); - $this->cachePlot($plot); - } - return true; - } - - /** - * @throws \Exception - */ - public function getPlot(string $levelName, int $X, int $Z) : Plot { - $this->reconnect(); - if(($plot = $this->getPlotFromCache($levelName, $X, $Z)) != null) { - return $plot; - } - $stmt = $this->sqlGetPlot; - $stmt->bind_param('sii', $levelName, $X, $Z); - $result = $stmt->execute(); - if($result === false) { - $this->plugin->getLogger()->error($stmt->error); - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - $result = $stmt->get_result(); - if($result !== false and ($val = $result->fetch_array(MYSQLI_ASSOC)) !== null) { - if($val["helpers"] === '') { - $helpers = []; - }else{ - $helpers = explode(",", (string) $val["helpers"]); - } - if($val["denied"] === '') { - $denied = []; - }else{ - $denied = explode(",", (string) $val["denied"]); - } - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plot = new Plot($levelName, $X, $Z, (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - }else{ - $plot = new Plot($levelName, $X, $Z); - } - $this->cachePlot($plot); - return $plot; - } - - /** - * @param string $owner - * @param string $levelName - * - * @return Plot[] - * @throws \Exception - */ - public function getPlotsByOwner(string $owner, string $levelName = "") : array { - $this->reconnect(); - if($levelName === '') { - $stmt = $this->sqlGetPlotsByOwner; - $stmt->bind_param('s', $owner); - }else{ - $stmt = $this->sqlGetPlotsByOwnerAndLevel; - $stmt->bind_param('ss', $owner, $levelName); - } - $plots = []; - $result = $stmt->execute(); - if($result === false) { - $this->plugin->getLogger()->error($stmt->error); - return $plots; - } - $result = $stmt->get_result(); - while($result !== false and ($val = $result->fetch_array()) !== null) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plots[] = new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - // Remove unloaded plots - $plots = array_filter($plots, function(Plot $plot) : bool { - return $this->plugin->isLevelLoaded($plot->levelName); - }); - // Sort plots by level - usort($plots, function(Plot $plot1, Plot $plot2) : int { - return strcmp($plot1->levelName, $plot2->levelName); - }); - return $plots; - } - - /** - * @throws \Exception - */ - public function getNextFreePlot(string $levelName, int $limitXZ = 0) : ?Plot { - $this->reconnect(); - $i = 0; - for(; $limitXZ <= 0 or $i < $limitXZ; $i++) { - $stmt = $this->sqlGetExistingXZ; - $stmt->bind_param('siiii', $levelName, $i, $i, $i, $i); - $result = $stmt->execute(); - if($result === false) { - $this->plugin->getLogger()->error($stmt->error); - continue; - } - $result = $stmt->get_result(); - $plots = []; - while($result !== false and ($val = $result->fetch_array(MYSQLI_NUM)) !== null) { - $plots[$val[0]][$val[1]] = true; - } - if(count($plots) === max(1, 8 * $i)) { - continue; - } - if(($ret = self::findEmptyPlotSquared(0, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - for($a = 1; $a < $i; $a++) { - if(($ret = self::findEmptyPlotSquared($a, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - if(($ret = self::findEmptyPlotSquared($i, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - return null; - } - - public function mergePlots(Plot $base, Plot ...$plots) : bool { - $stmt = $this->sqlMergePlot; - $ret = true; - foreach($plots as $plot) { - $stmt->bind_param('siiii', $base->levelName, $base->X, $base->Z, $plot->X, $plot->Z); - $result = $stmt->execute(); - if($result === false) { - $this->plugin->getLogger()->error($stmt->error); - $ret = false; - } - } - return $ret; - } - - public function getMergedPlots(Plot $plot, bool $adjacent = false) : array { - $origin = $this->getMergeOrigin($plot); - $stmt = $this->sqlGetMergedPlots; - $stmt->bind_param('sii', $origin->levelName, $origin->X, $origin->Z); - $result = $stmt->execute(); - $plots = []; - $plots[] = $origin; - if(!$result) { - $this->plugin->getLogger()->error($stmt->error); - return $plots; - } - $result = $stmt->get_result(); - while($result !== false and ($val = $result->fetch_array()) !== null) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plots[] = new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - if($adjacent) - $plots = array_filter($plots, function(Plot $val) use ($plot) : bool { - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - if($plot->getSide($i)->isSame($val)) - return true; - } - return false; - }); - return $plots; - } - - public function getMergeOrigin(Plot $plot) : Plot { - $stmt = $this->sqlGetMergeOrigin; - $stmt->bind_param('sii', $plot->levelName, $plot->X, $plot->Z); - $result = $stmt->execute(); - if(!$result) { - $this->plugin->getLogger()->error($stmt->error); - return $plot; - } - $result = $stmt->get_result(); - if($result !== false and ($val = $result->fetch_array()) !== null) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - return new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - return $plot; - } - - public function close() : void { - if($this->db->close()) - $this->plugin->getLogger()->debug("MySQL database closed!"); - } - - /** - * @throws \Exception - */ - private function reconnect() : void{ - if(!$this->db->ping()) { - $this->plugin->getLogger()->error("The MySQL server can not be reached! Trying to reconnect!"); - $this->close(); - $this->db->connect($this->settings['Host'], $this->settings['Username'], $this->settings['Password'], $this->settings['DatabaseName'], $this->settings['Port']); - $this->prepare(); - if($this->db->ping()) { - $this->plugin->getLogger()->notice("The MySQL connection has been re-established!"); - }else{ - $this->plugin->getLogger()->critical("The MySQL connection could not be re-established!"); - $this->plugin->getLogger()->critical("Closing level to prevent griefing!"); - foreach($this->plugin->getPlotLevels() as $levelName => $settings) { - $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($levelName); - if($level !== null) { - $level->save(); // don't force in case owner doesn't want it saved - Server::getInstance()->getWorldManager()->unloadWorld($level, true); // force unload to prevent possible griefing - } - } - if($this->db->connect_error !== null and $this->db->connect_error !== '') - $this->plugin->getLogger()->critical("Failed to connect to the MySQL database: " . $this->db->connect_error); - if($this->plugin->getConfig()->getNested("MySQLSettings.ShutdownOnFailure", false) === true) { - $this->plugin->getServer()->shutdown(); - } - } - } - } - - private function prepare() : void { - $stmt = $this->db->prepare("SELECT name, owner, helpers, denied, biome, pvp, price FROM plotsV2 WHERE level = ? AND X = ? AND Z = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlot = $stmt; - $stmt = $this->db->prepare("INSERT INTO plotsV2 (`level`, `X`, `Z`, `name`, `owner`, `helpers`, `denied`, `biome`, `pvp`, `price`) VALUES(?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE name = VALUES(name), owner = VALUES(owner), helpers = VALUES(helpers), denied = VALUES(denied), biome = VALUES(biome), pvp = VALUES(pvp), price = VALUES(price);"); - if($stmt === false) - throw new \Exception(); - $this->sqlSavePlot = $stmt; - $stmt = $this->db->prepare("DELETE FROM plotsV2 WHERE level = ? AND X = ? AND Z = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlRemovePlot = $stmt; - $stmt = $this->db->prepare("SELECT * FROM plotsV2 WHERE owner = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlotsByOwner = $stmt; - $stmt = $this->db->prepare("SELECT * FROM plotsV2 WHERE owner = ? AND level = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlotsByOwnerAndLevel = $stmt; - $stmt = $this->db->prepare("SELECT X, Z FROM plotsV2 WHERE (level = ? AND ((abs(X) = ? AND abs(Z) <= ?) OR (abs(Z) = ? AND abs(X) <= ?)));"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetExistingXZ = $stmt; - - $stmt = $this->db->prepare("INSERT IGNORE INTO mergedPlotsV2 (`level`, `originX`, `originZ`, `mergedX`, `mergedZ`) VALUES (?,?,?,?,?);"); - if($stmt === false) - throw new \Exception(); - $this->sqlMergePlot = $stmt; - $stmt = $this->db->prepare("SELECT plotsV2.level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plotsV2 LEFT JOIN mergedPlotsV2 ON mergedPlotsV2.level = plotsV2.level WHERE mergedPlotsV2.level = ? AND mergedX = ? AND mergedZ = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetMergeOrigin = $stmt; - $stmt = $this->db->prepare("SELECT plotsV2.level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plotsV2 LEFT JOIN mergedPlotsV2 ON mergedPlotsV2.level = plotsV2.level AND mergedPlotsV2.mergedX = plotsV2.X AND mergedPlotsV2.mergedZ = plotsV2.Z WHERE mergedPlotsV2.level = ? AND originX = ? AND originZ = ?;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetMergedPlots = $stmt; - $stmt = $this->db->prepare("UPDATE plotsV2 SET name = '', owner = '', helpers = '', denied = '', biome = :biome, pvp = :pvp, price = :price WHERE level = :level AND X = :X AND Z = :Z;"); - if($stmt === false) - throw new \Exception(); - $this->sqlDisposeMergedPlot = $stmt; - } -} diff --git a/src/MyPlot/provider/SQLiteDataProvider.php b/src/MyPlot/provider/SQLiteDataProvider.php deleted file mode 100644 index 9abdf20f..00000000 --- a/src/MyPlot/provider/SQLiteDataProvider.php +++ /dev/null @@ -1,315 +0,0 @@ -db = new \SQLite3($this->plugin->getDataFolder() . "plots.db"); - $this->db->exec("CREATE TABLE IF NOT EXISTS plotsV2 - (level TEXT, X INTEGER, Z INTEGER, name TEXT, - owner TEXT, helpers TEXT, denied TEXT, biome TEXT, pvp INTEGER, price FLOAT, PRIMARY KEY (level, X, Z));"); - if($this->db->querySingle("SELECT count(name) FROM sqlite_Master WHERE type='table' AND name='plots';") > 0) - $this->db->exec("INSERT OR IGNORE INTO plotsV2 (level, X, Z, name, owner, helpers, denied, biome, pvp, price) SELECT level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plots;"); - $this->db->exec("CREATE TABLE IF NOT EXISTS mergedPlotsV2 (level TEXT, originX INTEGER, originZ INTEGER, mergedX INTEGER, mergedZ INTEGER, PRIMARY KEY(level, originX, originZ, mergedX, mergedZ));"); - if($this->db->querySingle("SELECT count(name) FROM sqlite_Master WHERE type='table' AND name='mergedPlots';") > 0) - $this->db->exec("INSERT OR IGNORE INTO mergedPlotsV2 (level, originX, originZ, mergedX, mergedZ) SELECT r1.level, r1.X, r1.Z, r2.X, r2.Z FROM plots r1, mergedPlots JOIN plots r2 ON r1.id = mergedPlots.originId AND r2.id = mergedPlots.mergedId;"); - $this->prepare(); - $this->plugin->getLogger()->debug("SQLite data provider registered"); - } - - public function savePlot(Plot $plot) : bool { - $helpers = implode(",", $plot->helpers); - $denied = implode(",", $plot->denied); - $stmt = $this->sqlSavePlot; - $stmt->bindValue(":level", $plot->levelName, SQLITE3_TEXT); - $stmt->bindValue(":X", $plot->X, SQLITE3_INTEGER); - $stmt->bindValue(":Z", $plot->Z, SQLITE3_INTEGER); - $stmt->bindValue(":name", $plot->name, SQLITE3_TEXT); - $stmt->bindValue(":owner", $plot->owner, SQLITE3_TEXT); - $stmt->bindValue(":helpers", $helpers, SQLITE3_TEXT); - $stmt->bindValue(":denied", $denied, SQLITE3_TEXT); - $stmt->bindValue(":biome", $plot->biome, SQLITE3_TEXT); - $stmt->bindValue(":pvp", $plot->pvp, SQLITE3_INTEGER); - $stmt->bindValue(":price", $plot->price, SQLITE3_FLOAT); - $stmt->reset(); - $result = $stmt->execute(); - if(!$result instanceof \SQLite3Result) { - return false; - } - $this->cachePlot($plot); - return true; - } - - public function deletePlot(Plot $plot) : bool { - if($plot->isMerged()){ - $plot = $this->getMergeOrigin($plot); - $settings = MyPlot::getInstance()->getLevelSettings($plot->levelName); - $stmt = $this->sqlDisposeMergedPlot; - $stmt->bindValue(":pvp", !$settings->restrictPVP, SQLITE3_INTEGER); - $stmt->bindValue(":price", $settings->claimPrice, SQLITE3_FLOAT); - }else { - $stmt = $this->sqlRemovePlot; - } - $stmt->bindValue(":level", $plot->levelName, SQLITE3_TEXT); - $stmt->bindValue(":X", $plot->X, SQLITE3_INTEGER); - $stmt->bindValue(":Z", $plot->Z, SQLITE3_INTEGER); - $stmt->reset(); - $result = $stmt->execute(); - if(!$result instanceof \SQLite3Result) { - return false; - } - $this->cachePlot(new Plot($plot->levelName, $plot->X, $plot->Z)); - return true; - } - - public function getPlot(string $levelName, int $X, int $Z) : Plot { - if(($plot = $this->getPlotFromCache($levelName, $X, $Z)) !== null) { - return $plot; - } - $this->sqlGetPlot->bindValue(":level", $levelName, SQLITE3_TEXT); - $this->sqlGetPlot->bindValue(":X", $X, SQLITE3_INTEGER); - $this->sqlGetPlot->bindValue(":Z", $Z, SQLITE3_INTEGER); - $this->sqlGetPlot->reset(); - $result = $this->sqlGetPlot->execute(); - if($result !== false and ($val = $result->fetchArray(SQLITE3_ASSOC)) !== false) { - if($val["helpers"] === null or $val["helpers"] === "") { - $helpers = []; - }else{ - $helpers = explode(",", (string) $val["helpers"]); - } - if($val["denied"] === null or $val["denied"] === "") { - $denied = []; - }else{ - $denied = explode(",", (string) $val["denied"]); - } - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plot = new Plot($levelName, $X, $Z, (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - }else{ - $plot = new Plot($levelName, $X, $Z); - } - $this->cachePlot($plot); - return $plot; - } - - /** - * @param string $owner - * @param string $levelName - * - * @return Plot[] - */ - public function getPlotsByOwner(string $owner, string $levelName = "") : array { - if($levelName === "") { - $stmt = $this->sqlGetPlotsByOwner; - }else{ - $stmt = $this->sqlGetPlotsByOwnerAndLevel; - $stmt->bindValue(":level", $levelName, SQLITE3_TEXT); - } - $stmt->bindValue(":owner", $owner, SQLITE3_TEXT); - $plots = []; - $stmt->reset(); - $result = $stmt->execute(); - while($result !== false and ($val = $result->fetchArray(SQLITE3_ASSOC)) !== false) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plots[] = new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - // Remove unloaded plots - $plots = array_filter($plots, function(Plot $plot) : bool { - return $this->plugin->isLevelLoaded($plot->levelName); - }); - // Sort plots by level - usort($plots, function(Plot $plot1, Plot $plot2) : int { - return strcmp($plot1->levelName, $plot2->levelName); - }); - return $plots; - } - - public function getNextFreePlot(string $levelName, int $limitXZ = 0) : ?Plot { - $this->sqlGetExistingXZ->bindValue(":level", $levelName, SQLITE3_TEXT); - $i = 0; - $this->sqlGetExistingXZ->bindParam(":number", $i, SQLITE3_INTEGER); - for(; $limitXZ <= 0 or $i < $limitXZ; $i++) { - $this->sqlGetExistingXZ->reset(); - $result = $this->sqlGetExistingXZ->execute(); - $plots = []; - while($result !== false and ($val = $result->fetchArray(SQLITE3_NUM)) !== false) { - $plots[$val[0]][$val[1]] = true; - } - if(count($plots) === max(1, 8 * $i)) { - continue; - } - if(($ret = self::findEmptyPlotSquared(0, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - for($a = 1; $a < $i; $a++) { - if(($ret = self::findEmptyPlotSquared($a, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - if(($ret = self::findEmptyPlotSquared($i, $i, $plots)) !== null) { - [$X, $Z] = $ret; - $plot = new Plot($levelName, $X, $Z); - $this->cachePlot($plot); - return $plot; - } - } - return null; - } - - public function close() : void { - $this->db->close(); - $this->plugin->getLogger()->debug("SQLite database closed!"); - } - - public function mergePlots(Plot $base, Plot ...$plots) : bool { - $stmt = $this->sqlMergePlot; - $ret = true; - foreach($plots as $plot) { - $stmt->bindValue(":level", $base->levelName); - $stmt->bindValue(":originX", $base->X); - $stmt->bindValue(":originZ", $base->Z); - $stmt->bindValue(":mergedX", $plot->X); - $stmt->bindValue(":mergedZ", $plot->Z); - $stmt->reset(); - $result = $stmt->execute(); - if(!$result instanceof \SQLite3Result) { - MyPlot::getInstance()->getLogger()->debug("Failed to merge plot $plot into $base"); - $ret = false; - } - } - return $ret; - } - - /** - * @param Plot $plot - * @param bool $adjacent - * - * @return Plot[] - */ - public function getMergedPlots(Plot $plot, bool $adjacent = false) : array { - $origin = $this->getMergeOrigin($plot); - $stmt = $this->sqlGetMergedPlots; - $stmt->bindValue(":level", $origin->levelName); - $stmt->bindValue(":originX", $origin->X); - $stmt->bindValue(":originZ", $origin->Z); - $stmt->reset(); - $result = $stmt->execute(); - $plots = [$origin]; - while($result !== false and ($val = $result->fetchArray(SQLITE3_ASSOC)) !== false) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - $plots[] = new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - if($adjacent) - $plots = array_filter($plots, function(Plot $val) use ($plot) : bool { - for($i = Facing::NORTH; $i <= Facing::EAST; ++$i) { - if($plot->getSide($i)->isSame($val)) - return true; - } - return false; - }); - return $plots; - } - - public function getMergeOrigin(Plot $plot) : Plot { - $stmt = $this->sqlGetMergeOrigin; - $stmt->bindValue(":level", $plot->levelName); - $stmt->bindValue(":mergedX", $plot->X); - $stmt->bindValue(":mergedZ", $plot->Z); - $stmt->reset(); - $result = $stmt->execute(); - if(!$result instanceof \SQLite3Result) { - return $plot; - } - if(($val = $result->fetchArray(SQLITE3_ASSOC)) !== false) { - $helpers = explode(",", (string) $val["helpers"]); - $denied = explode(",", (string) $val["denied"]); - $pvp = is_numeric($val["pvp"]) ? (bool)$val["pvp"] : null; - return new Plot((string) $val["level"], (int) $val["X"], (int) $val["Z"], (string) $val["name"], (string) $val["owner"], $helpers, $denied, (string) $val["biome"], $pvp, (float) $val["price"]); - } - return $plot; - } - - private function prepare() : void { - $stmt = $this->db->prepare("SELECT name, owner, helpers, denied, biome, pvp, price FROM plotsV2 WHERE level = :level AND X = :X AND Z = :Z;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlot = $stmt; - $stmt = $this->db->prepare("INSERT OR REPLACE INTO plotsV2 (level, X, Z, name, owner, helpers, denied, biome, pvp, price) VALUES (:level, :X, :Z, :name, :owner, :helpers, :denied, :biome, :pvp, :price);"); - if($stmt === false) - throw new \Exception(); - $this->sqlSavePlot = $stmt; - $stmt = $this->db->prepare("DELETE FROM plotsV2 WHERE level = :level AND X = :X AND Z = :Z;"); - if($stmt === false) - throw new \Exception(); - $this->sqlRemovePlot = $stmt; - $stmt = $this->db->prepare("UPDATE plotsV2 SET name = '', owner = '', helpers = '', denied = '', biome = :biome, pvp = :pvp, price = :price WHERE level = :level AND X = :X AND Z = :Z;"); - if($stmt === false) - throw new \Exception(); - $this->sqlDisposeMergedPlot = $stmt; - $stmt = $this->db->prepare("SELECT * FROM plotsV2 WHERE owner = :owner;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlotsByOwner = $stmt; - $stmt = $this->db->prepare("SELECT * FROM plotsV2 WHERE owner = :owner AND level = :level;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetPlotsByOwnerAndLevel = $stmt; - $stmt = $this->db->prepare("SELECT X, Z FROM plotsV2 WHERE ( - level = :level - AND ( - (abs(X) = :number AND abs(Z) <= :number) OR - (abs(Z) = :number AND abs(X) <= :number) - ) - );"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetExistingXZ = $stmt; - $stmt = $this->db->prepare("INSERT OR REPLACE INTO mergedPlotsV2 (level, originX, originZ, mergedX, mergedZ) VALUES (:level, :originX, :originZ, :mergedX, :mergedZ);"); - if($stmt === false) - throw new \Exception(); - $this->sqlMergePlot = $stmt; - $stmt = $this->db->prepare("SELECT plotsV2.level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plotsV2 LEFT JOIN mergedPlotsV2 ON mergedPlotsV2.level = plotsV2.level WHERE mergedPlotsV2.level = :level AND mergedX = :mergedX AND mergedZ = :mergedZ;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetMergeOrigin = $stmt; - $stmt = $this->db->prepare("SELECT plotsV2.level, X, Z, name, owner, helpers, denied, biome, pvp, price FROM plotsV2 LEFT JOIN mergedPlotsV2 ON mergedPlotsV2.level = plotsV2.level AND mergedPlotsV2.mergedX = plotsV2.X AND mergedPlotsV2.mergedZ = plotsV2.Z WHERE mergedPlotsV2.level = :level AND originX = :originX AND originZ = :originZ;"); - if($stmt === false) - throw new \Exception(); - $this->sqlGetMergedPlots = $stmt; - } -} \ No newline at end of file diff --git a/src/MyPlot/subcommand/AddHelperSubCommand.php b/src/MyPlot/subcommand/AddHelperSubCommand.php index 34d08f36..1f10edd0 100644 --- a/src/MyPlot/subcommand/AddHelperSubCommand.php +++ b/src/MyPlot/subcommand/AddHelperSubCommand.php @@ -1,54 +1,66 @@ hasPermission("myplot.command.addhelper"); +class AddHelperSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.addhelper")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $helperName = $args[0]; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.addhelper")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $helper = $this->plugin->getServer()->getPlayerByPrefix($helperName); - if($helper === null) - $helper = $this->plugin->getServer()->getOfflinePlayer($helperName); - if($this->plugin->addPlotHelper($plot, $helper->getName())) { - $sender->sendMessage($this->translateString("addhelper.success", [$helper->getName()])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $helperName = $args[0]; + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.addhelper")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $helper = $this->plugin->getServer()->getPlayerByPrefix($helperName); + if($helper === null) + $helper = $this->plugin->getServer()->getOfflinePlayer($helperName); + if(yield from $this->internalAPI->generateAddPlotHelper($plot, $helper->getName())){ + $sender->sendMessage($this->translateString("addhelper.success", [$helper->getName()])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new AddHelperForm($plot); - return null; + public function getFormClass() : ?string{ + return AddHelperForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/AutoSubCommand.php b/src/MyPlot/subcommand/AutoSubCommand.php index 1819a725..ee62c50e 100644 --- a/src/MyPlot/subcommand/AutoSubCommand.php +++ b/src/MyPlot/subcommand/AutoSubCommand.php @@ -1,48 +1,47 @@ hasPermission("myplot.command.auto"); +class AutoSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + return $sender->hasPermission("myplot.command.auto") and $sender instanceof Player; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $levelName = $sender->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("auto.notplotworld")); - return true; - } - if(($plot = $this->plugin->getNextFreePlot($levelName)) !== null) { - if($this->plugin->teleportPlayerToPlot($sender, $plot, true)) { - $sender->sendMessage($this->translateString("auto.success", [$plot->X, $plot->Z])); - /** @noinspection PhpParamsInspection */ - $cmd = new ClaimSubCommand($this->plugin, "claim"); - if(isset($args[0]) and strtolower($args[0]) == "true" and $cmd->canUse($sender)) { - $cmd->execute($sender, isset($args[1]) ? [$args[1]] : []); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $levelName = $sender->getWorld()->getFolderName(); + if($this->internalAPI->getLevelSettings($levelName) === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("auto.notplotworld")); + return; + } + $plot = yield from $this->internalAPI->generateNextFreePlot($levelName, 0); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("auto.noplots")); + return; + } + if($this->internalAPI->teleportPlayerToPlot($sender, $plot, true)){ + $sender->sendMessage($this->translateString("auto.success", [$plot->X, $plot->Z])); + $cmd = new ClaimSubCommand($this->plugin, $this->internalAPI, "claim"); + if(isset($args[0]) and strtolower($args[0]) === "true" and $cmd->canUse($sender)) + $cmd->execute($sender, isset($args[1]) ? [$args[1]] : []); + return; } - }else { $sender->sendMessage(TextFormat::RED . $this->translateString("error")); } - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("auto.noplots")); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/BiomeSubCommand.php b/src/MyPlot/subcommand/BiomeSubCommand.php index 847386d9..93a7679a 100644 --- a/src/MyPlot/subcommand/BiomeSubCommand.php +++ b/src/MyPlot/subcommand/BiomeSubCommand.php @@ -1,80 +1,92 @@ BiomeIds::PLAINS, "DESERT" => BiomeIds::DESERT, "MOUNTAINS" => BiomeIds::ICE_MOUNTAINS, "FOREST" => BiomeIds::FOREST, "TAIGA" => BiomeIds::TAIGA, "SWAMP" => BiomeIds::SWAMPLAND, "NETHER" => BiomeIds::HELL, "HELL" => BiomeIds::HELL, "ICE_PLAINS" => BiomeIds::ICE_PLAINS]; -class BiomeSubCommand extends SubCommand -{ - public CONST BIOMES = ["PLAINS" => BiomeIds::PLAINS, "DESERT" => BiomeIds::DESERT, "MOUNTAINS" => BiomeIds::ICE_MOUNTAINS, "FOREST" => BiomeIds::FOREST, "TAIGA" => BiomeIds::TAIGA, "SWAMP" => BiomeIds::SWAMPLAND, "NETHER" => BiomeIds::HELL, "HELL" => BiomeIds::HELL, "ICE_PLAINS" => BiomeIds::ICE_PLAINS]; + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.biome")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($pos->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.biome"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - $biomes = TextFormat::WHITE . implode(", ", array_keys(self::BIOMES)); - $sender->sendMessage($this->translateString("biome.possible", [$biomes])); - return true; - } - $player = $sender->getServer()->getPlayerExact($sender->getName()); - if($player === null) - return true; - $biome = strtoupper($args[0]); - $plot = $this->plugin->getPlotByPosition($player->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.biome")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(is_numeric($biome)) { - $biome = (int) $biome; - if($biome > 27 or $biome < 0) { - $sender->sendMessage(TextFormat::RED . $this->translateString("biome.invalid")); - $biomes = implode(", ", array_keys(self::BIOMES)); - $sender->sendMessage(TextFormat::RED . $this->translateString("biome.possible", [$biomes])); - return true; + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $biomes = TextFormat::WHITE . implode(", ", array_keys(self::BIOMES)); + $sender->sendMessage($this->translateString("biome.possible", [$biomes])); + return; + } + $player = $sender->getServer()->getPlayerExact($sender->getName()); + if($player === null) + return; + $biome = strtoupper($args[0]); + $plot = yield from $this->internalAPI->generatePlotByPosition($player->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.biome")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(is_numeric($biome)){ + $biome = (int) $biome; + if($biome > 27 or $biome < 0){ + $sender->sendMessage(TextFormat::RED . $this->translateString("biome.invalid")); + $biomes = implode(", ", array_keys(self::BIOMES)); + $sender->sendMessage(TextFormat::RED . $this->translateString("biome.possible", [$biomes])); + return; + } + $biome = BiomeRegistry::getInstance()->getBiome($biome); + }else{ + $biome = ($biome === "NETHER" ? "HELL" : $biome); + $biome = ($biome === "ICE PLAINS" ? "ICE_PLAINS" : $biome); + if(!defined(BiomeIds::class . "::" . $biome) or !is_int(constant(BiomeIds::class . "::" . $biome))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("biome.invalid")); + $biomes = implode(", ", array_keys(self::BIOMES)); + $sender->sendMessage(TextFormat::RED . $this->translateString("biome.possible", [$biomes])); + return; + } + $biome = BiomeRegistry::getInstance()->getBiome(constant(BiomeIds::class . "::" . $biome)); + } + if(yield from $this->internalAPI->generatePlotBiome($plot, $biome)){ + $sender->sendMessage($this->translateString("biome.success", [$biome->getName()])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - $biome = BiomeRegistry::getInstance()->getBiome($biome); - }else{ - $biome = ($biome === "NETHER" ? "HELL" : $biome); - $biome = ($biome === "ICE PLAINS" ? "ICE_PLAINS" : $biome); - if(!defined(BiomeIds::class."::".$biome) or !is_int(constant(BiomeIds::class."::".$biome))) { - $sender->sendMessage(TextFormat::RED . $this->translateString("biome.invalid")); - $biomes = implode(", ", array_keys(self::BIOMES)); - $sender->sendMessage(TextFormat::RED . $this->translateString("biome.possible", [$biomes])); - return true; - } - $biome = BiomeRegistry::getInstance()->getBiome(constant(BiomeIds::class."::".$biome)); - } - if($this->plugin->setPlotBiome($plot, $biome)) { - $sender->sendMessage($this->translateString("biome.success", [$biome->getName()])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and $this->plugin->getPlotByPosition($player->getPosition()) instanceof Plot) - return new BiomeForm(array_keys(self::BIOMES)); - return null; + public function getFormClass() : ?string{ + return BiomeForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/BuySubCommand.php b/src/MyPlot/subcommand/BuySubCommand.php index 84de1816..9974052b 100644 --- a/src/MyPlot/subcommand/BuySubCommand.php +++ b/src/MyPlot/subcommand/BuySubCommand.php @@ -1,72 +1,76 @@ hasPermission("myplot.command.buy")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class BuySubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.buy"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if($this->plugin->getEconomyProvider() === null){ - /** @noinspection PhpParamsInspection */ - $command = new ClaimSubCommand($this->plugin, "claim"); - return $command->execute($sender, []); - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null){ - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner === $sender->getName() and !$sender->hasPermission("myplot.admin.buy")){ - $sender->sendMessage(TextFormat::RED . $this->translateString("buy.noself")); - return true; - } - if($plot->price <= 0){ - $sender->sendMessage(TextFormat::RED . $this->translateString("buy.notforsale")); - return true; - } - $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); - $plotsOfPlayer = 0; - foreach($this->plugin->getPlotLevels() as $level => $settings) { - $level = $this->plugin->getServer()->getWorldManager()->getWorldByName((string)$level); - if($level !== null and $level->isLoaded()) { - $plotsOfPlayer += count($this->plugin->getPlotsOfPlayer($sender->getName(), $level->getFolderName())); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if($this->internalAPI->getEconomyProvider() === null){ + /** @noinspection PhpParamsInspection */ + $command = new ClaimSubCommand($this->plugin, "claim"); + $command->execute($sender, []); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner === $sender->getName() and !$sender->hasPermission("myplot.admin.buy")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("buy.noself")); + return; + } + if($plot->price <= 0){ + $sender->sendMessage(TextFormat::RED . $this->translateString("buy.notforsale")); + return; + } + $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); + if(count(yield from $this->internalAPI->generatePlotsOfPlayer($sender->getName(), null)) >= $maxPlots){ + $sender->sendMessage(TextFormat::RED . $this->translateString("claim.maxplots", [$maxPlots])); + return; + } + $price = $plot->price; + if(strtolower($args[0] ?? "") !== $this->translateString("confirm")){ + $sender->sendMessage($this->translateString("buy.confirm", ["$plot->X;$plot->Z", $price])); + return; + } + $oldOwner = $this->plugin->getServer()->getPlayerExact($plot->owner); + if(yield from $this->internalAPI->generateBuyPlot($plot, $sender)){ + $sender->sendMessage($this->translateString("buy.success", ["$plot->X;$plot->Z", $price])); + $oldOwner?->sendMessage($this->translateString("buy.sold", [$sender->getName(), "$plot->X;$plot->Z", $price])); // TODO: queue messages for sending when player rejoins + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - } - if($plotsOfPlayer >= $maxPlots) { - $sender->sendMessage(TextFormat::RED . $this->translateString("claim.maxplots", [$maxPlots])); - return true; - } - $price = $plot->price; - if(strtolower($args[0] ?? "") !== $this->translateString("confirm")){ - $sender->sendMessage($this->translateString("buy.confirm", ["$plot->X;$plot->Z", $price])); - return true; - } - $oldOwner = $this->plugin->getServer()->getPlayerExact($plot->owner); - if($this->plugin->buyPlot($plot, $sender)) { - $sender->sendMessage($this->translateString("buy.success", ["$plot->X;$plot->Z", $price])); - $oldOwner?->sendMessage($this->translateString("buy.sold", [$sender->getName(), "$plot->X;$plot->Z", $price])); // TODO: queue messages for sending when player rejoins - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - // TODO: Implement getForm() method. - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/ClaimSubCommand.php b/src/MyPlot/subcommand/ClaimSubCommand.php index b72d64bc..b7129e1e 100644 --- a/src/MyPlot/subcommand/ClaimSubCommand.php +++ b/src/MyPlot/subcommand/ClaimSubCommand.php @@ -1,72 +1,100 @@ hasPermission("myplot.command.claim"); +class ClaimSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + return $sender->hasPermission("myplot.command.claim") and $sender instanceof Player; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $name = ""; - if(isset($args[0])) { - $name = $args[0]; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner != "") { - if($plot->owner === $sender->getName()) { - $sender->sendMessage(TextFormat::RED . $this->translateString("claim.yourplot")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("claim.alreadyclaimed", [$plot->owner])); - } - return true; - } - $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); - $plotsOfPlayer = 0; - foreach($this->plugin->getPlotLevels() as $level => $settings) { - $level = $this->plugin->getServer()->getWorldManager()->getWorldByName((string)$level); - if($level !== null and $level->isLoaded()) { - $plotsOfPlayer += count($this->plugin->getPlotsOfPlayer($sender->getName(), $level->getFolderName())); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $pos = $sender->getPosition(); + $x = $pos->x; + $z = $pos->z; + $levelName = $sender->getWorld()->getFolderName(); + $plot = $this->internalAPI->getPlotFast($x, $z, $this->internalAPI->getLevelSettings($levelName)); + + $name = ""; + switch(count($args)){ + case 1: + if(str_contains($args[0], ';')){ + $coords = explode(';', $args[0]); + if(count($coords) !== 2 or !is_numeric($coords[0]) or !is_numeric($coords[1])){ + $sender->sendMessage(TextFormat::RED . 'Usage: ' . $this->translateString('claim.usage')); + return; + } + $plot = new BasePlot($levelName, (int) $coords[0], (int) $coords[1]); + }else{ + $name = $args[0]; + } + break; + case 2: + if(!str_contains($args[0], ';')){ + $sender->sendMessage(TextFormat::RED . 'Usage: /plot claim '); + return; + } + $coords = explode(';', $args[0]); + if(count($coords) !== 2 or !is_numeric($coords[0]) or !is_numeric($coords[1])){ + $sender->sendMessage(TextFormat::RED . 'Usage: /plot claim '); + return; + } + $plot = new BasePlot($levelName, (int) $coords[0], (int) $coords[1]); + $name = $args[1]; + } + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + $plot = yield from $this->internalAPI->generatePlot($plot); + if(!$plot instanceof SinglePlot) + $plot = SinglePlot::fromBase($plot); + + if($plot->owner !== ""){ + if($plot->owner === $sender->getName()){ + $sender->sendMessage(TextFormat::RED . $this->translateString("claim.yourplot")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("claim.alreadyclaimed", [$plot->owner])); + } + return; + } + $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); + if(count(yield from $this->internalAPI->generatePlotsOfPlayer($sender->getName(), null)) >= $maxPlots){ + $sender->sendMessage(TextFormat::RED . $this->translateString("claim.maxplots", [$maxPlots])); + return; + } + $economy = $this->internalAPI->getEconomyProvider(); + if($economy !== null and !(yield from $economy->reduceMoney($sender, $plot->price, 'used plot claim command'))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("claim.nomoney")); + return; + } + if(yield from $this->internalAPI->generateClaimPlot($plot, $sender->getName(), $name)){ + $sender->sendMessage($this->translateString("claim.success")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - } - if($plotsOfPlayer >= $maxPlots) { - $sender->sendMessage(TextFormat::RED . $this->translateString("claim.maxplots", [$maxPlots])); - return true; - } - $economy = $this->plugin->getEconomyProvider(); - if($economy !== null and !$economy->reduceMoney($sender, $plot->price)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("claim.nomoney")); - return true; - } - if($this->plugin->claimPlot($plot, $sender->getName(), $name)) { - $sender->sendMessage($this->translateString("claim.success")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) !== null) - return new ClaimForm($player, $plot); - return null; + public function getFormClass() : ?string{ + return ClaimForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/ClearSubCommand.php b/src/MyPlot/subcommand/ClearSubCommand.php index d59ed16a..e9ded398 100644 --- a/src/MyPlot/subcommand/ClearSubCommand.php +++ b/src/MyPlot/subcommand/ClearSubCommand.php @@ -1,57 +1,67 @@ hasPermission("myplot.command.clear"); +class ClearSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.clear")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clear")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(isset($args[0]) and $args[0] == $this->translateString("confirm")) { - $economy = $this->plugin->getEconomyProvider(); - $price = $this->plugin->getLevelSettings($plot->levelName)->clearPrice; - if($economy !== null and !$economy->reduceMoney($sender, $price)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("clear.nomoney")); - return true; - } - $maxBlocksPerTick = $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); - if(!is_int($maxBlocksPerTick)) - $maxBlocksPerTick = 256; - if($this->plugin->clearPlot($plot, $maxBlocksPerTick)) { - $sender->sendMessage($this->translateString("clear.success")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clear")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!isset($args[0]) or $args[0] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("clear.confirm", [$plotId])); + return; + } + $economy = $this->internalAPI->getEconomyProvider(); + $price = $this->internalAPI->getLevelSettings($plot->levelName)->clearPrice; + if($economy !== null and !(yield from $economy->reduceMoney($sender, $price, 'used plot clear command'))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("clear.nomoney")); + return; + } + $maxBlocksPerTick = $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); + if(!is_int($maxBlocksPerTick)) + $maxBlocksPerTick = 256; + if(yield from $this->internalAPI->generateClearPlot($plot, $maxBlocksPerTick)){ + $sender->sendMessage($this->translateString("clear.success")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - }else{ - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("clear.confirm", [$plotId])); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/CloneSubCommand.php b/src/MyPlot/subcommand/CloneSubCommand.php index db0e3747..c935e288 100644 --- a/src/MyPlot/subcommand/CloneSubCommand.php +++ b/src/MyPlot/subcommand/CloneSubCommand.php @@ -1,65 +1,81 @@ hasPermission("myplot.command.clone"); +class CloneSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.clone")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - /** @var string[] $plotIdArray */ - $plotIdArray = explode(";", $args[0]); - if(count($plotIdArray) != 2 or !is_numeric($plotIdArray[0]) or !is_numeric($plotIdArray[1])) { - $sender->sendMessage(TextFormat::RED . $this->translateString("clone.wrongid")); - return true; - } - $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); - $selectedPlot = $this->plugin->getProvider()->getPlot($levelName, (int) $plotIdArray[0], (int) $plotIdArray[1]); - $standingPlot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($standingPlot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($standingPlot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clone")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if($selectedPlot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clone")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $plotLevel = $this->plugin->getLevelSettings($standingPlot->levelName); - $economy = $this->plugin->getEconomyProvider(); - if($economy !== null and !$economy->reduceMoney($sender, $plotLevel->clonePrice)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("clone.nomoney")); - return true; - } - if($this->plugin->clonePlot($selectedPlot, $standingPlot)) { - $sender->sendMessage($this->translateString("clone.success", [$selectedPlot->__toString(), $standingPlot->__toString()])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plotIdArray = explode(";", $args[0]); + if(count($plotIdArray) < 2 or !is_numeric($plotIdArray[0]) or !is_numeric($plotIdArray[1])){ + $sender->sendMessage(TextFormat::RED . $this->translateString("clone.wrongid")); + return; + } + $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); + $selectedPlot = yield from $this->internalAPI->generatePlot(new BasePlot($levelName, (int) $plotIdArray[0], (int) $plotIdArray[1])); + $standingPlot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($standingPlot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($standingPlot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clone")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if($selectedPlot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.clone")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $plotLevel = $this->plugin->getLevelSettings($standingPlot->levelName); + $economy = $this->internalAPI->getEconomyProvider(); + if($economy !== null and !(yield from $economy->reduceMoney($sender, $plotLevel->clonePrice))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("clone.nomoney")); + return; + } + if($this->internalAPI->clonePlot($selectedPlot, $standingPlot)){ + $sender->sendMessage($this->translateString("clone.success", [$selectedPlot->__toString(), $standingPlot->__toString()])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - return $player !== null ? new CloneForm($player) : null; + public function getFormClass() : ?string{ + return CloneForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/DenyPlayerSubCommand.php b/src/MyPlot/subcommand/DenyPlayerSubCommand.php index 9554edd5..32fcb2d6 100644 --- a/src/MyPlot/subcommand/DenyPlayerSubCommand.php +++ b/src/MyPlot/subcommand/DenyPlayerSubCommand.php @@ -1,80 +1,94 @@ hasPermission("myplot.command.denyplayer")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class DenyPlayerSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.denyplayer"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $dplayer = $args[0]; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.denyplayer")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if($dplayer === "*") { - if($this->plugin->addPlotDenied($plot, $dplayer)) { - $sender->sendMessage($this->translateString("denyplayer.success1", [$dplayer])); - foreach($this->plugin->getServer()->getOnlinePlayers() as $player) { - if($this->plugin->getPlotBB($plot)->isVectorInside($player) and !($player->getName() === $plot->owner) and !$player->hasPermission("myplot.admin.denyplayer.bypass") and !$plot->isHelper($player->getName())) - $this->plugin->teleportPlayerToPlot($player, $plot); - else { - $sender->sendMessage($this->translateString("denyplayer.cannotdeny", [$player->getName()])); - $player->sendMessage($this->translateString("denyplayer.attempteddeny", [$sender->getName()])); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $dplayer = $args[0]; + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.denyplayer")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if($dplayer === "*"){ + if(yield from $this->internalAPI->generateAddPlotDenied($plot, $dplayer)){ + $sender->sendMessage($this->translateString("denyplayer.success1", [$dplayer])); + foreach($this->plugin->getServer()->getOnlinePlayers() as $player){ + if($this->internalAPI->getPlotBB($plot)->isVectorInside($player->getPosition()) and !($player->getName() === $plot->owner) and !$player->hasPermission("myplot.admin.denyplayer.bypass") and !$plot->isHelper($player->getName())) + $this->internalAPI->teleportPlayerToPlot($player, $plot, false); + else{ + $sender->sendMessage($this->translateString("denyplayer.cannotdeny", [$player->getName()])); + $player->sendMessage($this->translateString("denyplayer.attempteddeny", [$sender->getName()])); + } + } + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); } + return; + } + + $dplayer = $this->plugin->getServer()->getPlayerByPrefix($dplayer); + if(!$dplayer instanceof Player){ + $sender->sendMessage($this->translateString("denyplayer.notaplayer")); + return; + } + if($dplayer->hasPermission("myplot.admin.denyplayer.bypass") or $dplayer->getName() === $plot->owner){ + $sender->sendMessage($this->translateString("denyplayer.cannotdeny", [$dplayer->getName()])); + $dplayer->sendMessage($this->translateString("denyplayer.attempteddeny", [$sender->getName()])); + return; + } + if(yield from $this->internalAPI->generateAddPlotDenied($plot, $dplayer->getName())){ + $sender->sendMessage($this->translateString("denyplayer.success1", [$dplayer->getName()])); + $dplayer->sendMessage($this->translateString("denyplayer.success2", [$plot->X, $plot->Z, $sender->getName()])); + if($this->internalAPI->getPlotBB($plot)->isVectorInside($dplayer->getPosition())) + $this->internalAPI->teleportPlayerToPlot($dplayer, $plot, false); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); } - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); } - return true; - } - $dplayer = $this->plugin->getServer()->getPlayerByPrefix($dplayer); - if(!$dplayer instanceof Player) { - $sender->sendMessage($this->translateString("denyplayer.notaplayer")); - return true; - } - if($dplayer->hasPermission("myplot.admin.denyplayer.bypass") or $dplayer->getName() === $plot->owner) { - $sender->sendMessage($this->translateString("denyplayer.cannotdeny", [$dplayer->getName()])); - $dplayer->sendMessage($this->translateString("denyplayer.attempteddeny", [$sender->getName()])); - return true; - } - if($this->plugin->addPlotDenied($plot, $dplayer->getName())) { - $sender->sendMessage($this->translateString("denyplayer.success1", [$dplayer->getName()])); - $dplayer->sendMessage($this->translateString("denyplayer.success2", [$plot->X, $plot->Z, $sender->getName()])); - if($this->plugin->getPlotBB($plot)->isVectorInside($dplayer)) - $this->plugin->teleportPlayerToPlot($dplayer, $plot); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new DenyPlayerForm($plot); - return null; + public function getFormClass() : ?string{ + return DenyPlayerForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/DisposeSubCommand.php b/src/MyPlot/subcommand/DisposeSubCommand.php index 737cc494..d15e51b0 100644 --- a/src/MyPlot/subcommand/DisposeSubCommand.php +++ b/src/MyPlot/subcommand/DisposeSubCommand.php @@ -1,54 +1,65 @@ hasPermission("myplot.command.dispose")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class DisposeSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.dispose"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.dispose")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(isset($args[0]) and $args[0] == $this->translateString("confirm")) { - $economy = $this->plugin->getEconomyProvider(); - $price = $this->plugin->getLevelSettings($plot->levelName)->disposePrice; - if($economy !== null and !$economy->reduceMoney($sender, $price)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("dispose.nomoney")); - return true; - } - if($this->plugin->disposePlot($plot)) { - $sender->sendMessage($this->translateString("dispose.success")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.dispose")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!isset($args[0]) or $args[0] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("dispose.confirm", [$plotId])); + return; + } + $economy = $this->internalAPI->getEconomyProvider(); + $price = $this->plugin->getLevelSettings($plot->levelName)->disposePrice; + if($economy !== null and !(yield from $economy->reduceMoney($sender, $price))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("dispose.nomoney")); + return; + } + if(yield from $this->internalAPI->generateDisposePlot($plot)){ + $sender->sendMessage(TextFormat::GREEN . $this->translateString("dispose.success")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - }else{ - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("dispose.confirm", [$plotId])); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/FillSubCommand.php b/src/MyPlot/subcommand/FillSubCommand.php index ecd4251d..ce0ff20e 100644 --- a/src/MyPlot/subcommand/FillSubCommand.php +++ b/src/MyPlot/subcommand/FillSubCommand.php @@ -1,64 +1,85 @@ hasPermission("myplot.command.fill"); + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.fill")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) < 1) { - return false; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED.$this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.fill")) { - $sender->sendMessage(TextFormat::RED.$this->translateString("notowner")); - return true; - } - - if(($item = StringToItemParser::getInstance()->parse($args[0])) instanceof Item and $item->getBlock() instanceof Air) { - $maxBlocksPerTick = (int)$this->plugin->getConfig()->get("FillBlocksPerTick", 256); - if($this->plugin->fillPlot($plot, $item->getBlock(), $maxBlocksPerTick)) { - $sender->sendMessage($this->translateString("fill.success", [$item->getBlock()->getName()])); - }else { - $sender->sendMessage(TextFormat::RED.$this->translateString("error")); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) < 1 or !($item = StringToItemParser::getInstance()->parse($args[0])) instanceof Item or !$item->getBlock() instanceof Air){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.fill")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!isset($args[1]) or $args[1] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("fill.confirm", [$plotId])); + return; + } + $economy = $this->internalAPI->getEconomyProvider(); + $price = $this->internalAPI->getLevelSettings($plot->levelName)->fillPrice; + if($economy !== null and !(yield from $economy->reduceMoney($sender, $price, 'used plot fill command'))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("fill.nomoney")); + return; + } + $maxBlocksPerTick = $this->plugin->getConfig()->get("FillBlocksPerTick", 256); + if(!is_int($maxBlocksPerTick)) + $maxBlocksPerTick = 256; + if($this->internalAPI->fillPlot($plot, $item->getBlock(), $maxBlocksPerTick)){ + $sender->sendMessage($this->translateString("fill.success", [$item->getBlock()->getName()])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - }else { - return false; - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($this->plugin->getPlotByPosition($player->getPosition()) instanceof Plot) { - return new FillForm(); - } - return null; + public function getFormClass() : ?string{ + return FillForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/GenerateSubCommand.php b/src/MyPlot/subcommand/GenerateSubCommand.php index 0ac34f9a..1207ab58 100644 --- a/src/MyPlot/subcommand/GenerateSubCommand.php +++ b/src/MyPlot/subcommand/GenerateSubCommand.php @@ -1,39 +1,38 @@ hasPermission("myplot.command.generate"); } /** * @param CommandSender $sender - * @param string[] $args + * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { + public function execute(CommandSender $sender, array $args) : bool{ + if(count($args) === 0){ return false; } $levelName = $args[0]; - if($sender->getServer()->getWorldManager()->isWorldGenerated($levelName)) { + if($sender->getServer()->getWorldManager()->isWorldGenerated($levelName)){ $sender->sendMessage(TextFormat::RED . $this->translateString("generate.exists", [$levelName])); return true; } - if($this->plugin->generateLevel($levelName, $args[2] ?? MyPlotGenerator::NAME)) { - if(isset($args[1]) and $args[1] == true and $sender instanceof Player) { - $this->plugin->teleportPlayerToPlot($sender, new Plot($levelName, 0, 0)); + if($this->plugin->generateLevel($levelName, $args[2] ?? MyPlotGenerator::NAME)){ + if(isset($args[1]) and $args[1] == true and $sender instanceof Player){ + $this->internalAPI->teleportPlayerToPlot($sender, new BasePlot($levelName, 0, 0), false); } $sender->sendMessage($this->translateString("generate.success", [$levelName])); }else{ @@ -42,7 +41,7 @@ public function execute(CommandSender $sender, array $args) : bool { return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - return new GenerateForm(); + public function getFormClass() : ?string{ + return GenerateForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/GiveSubCommand.php b/src/MyPlot/subcommand/GiveSubCommand.php index c4e03e30..e809c696 100644 --- a/src/MyPlot/subcommand/GiveSubCommand.php +++ b/src/MyPlot/subcommand/GiveSubCommand.php @@ -1,81 +1,87 @@ hasPermission("myplot.command.give")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class GiveSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.give"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $newOwner = $args[0]; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName()) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $newOwner = $this->plugin->getServer()->getPlayerByPrefix($newOwner); - if(!$newOwner instanceof Player) { - $sender->sendMessage(TextFormat::RED . $this->translateString("give.notonline")); - return true; - }elseif($newOwner->getName() === $sender->getName()) { - $sender->sendMessage(TextFormat::RED . $this->translateString("give.toself")); - return true; - } - $maxPlots = $this->plugin->getMaxPlotsOfPlayer($newOwner); - $plotsOfPlayer = 0; - foreach($this->plugin->getPlotLevels() as $level => $settings) { - $level = $this->plugin->getServer()->getWorldManager()->getWorldByName((string)$level); - if($level !== null and $level->isLoaded()) { - $plotsOfPlayer += count($this->plugin->getPlotsOfPlayer($newOwner->getName(), $level->getFolderName())); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) < 1){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $newOwner = $args[0]; + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName()){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $newOwner = $this->plugin->getServer()->getPlayerByPrefix($newOwner); + if(!$newOwner instanceof Player){ + $sender->sendMessage(TextFormat::RED . $this->translateString("give.notonline")); + return; + }elseif($newOwner->getName() === $sender->getName()){ + $sender->sendMessage(TextFormat::RED . $this->translateString("give.toself")); + return; + } + $maxPlots = $this->plugin->getMaxPlotsOfPlayer($newOwner); + if(count(yield from $this->internalAPI->generatePlotsOfPlayer($newOwner->getName(), null)) >= $maxPlots){ + $sender->sendMessage(TextFormat::RED . $this->translateString("give.maxedout", [$maxPlots])); + return; + } + if(count($args) < 2 or $args[1] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $newOwnerName = TextFormat::GREEN . $newOwner->getName() . TextFormat::WHITE; + $sender->sendMessage($this->translateString("give.confirm", [$plotId, $newOwnerName])); + return; + } + if(yield from $this->internalAPI->generateClaimPlot($plot, $newOwner->getName(), '')){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $oldOwnerName = TextFormat::GREEN . $sender->getName() . TextFormat::WHITE; + $newOwnerName = TextFormat::GREEN . $newOwner->getName() . TextFormat::WHITE; + $sender->sendMessage($this->translateString("give.success", [$newOwnerName])); + $newOwner->sendMessage($this->translateString("give.received", [$oldOwnerName, $plotId])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - } - if($plotsOfPlayer >= $maxPlots) { - $sender->sendMessage(TextFormat::RED . $this->translateString("give.maxedout", [$maxPlots])); - return true; - } - if(count($args) == 2 and $args[1] == $this->translateString("confirm")) { - if($this->plugin->claimPlot($plot, $newOwner->getName())) { - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $oldOwnerName = TextFormat::GREEN . $sender->getName() . TextFormat::WHITE; - $newOwnerName = TextFormat::GREEN . $newOwner->getName() . TextFormat::WHITE; - $sender->sendMessage($this->translateString("give.success", [$newOwnerName])); - $newOwner->sendMessage($this->translateString("give.received", [$oldOwnerName, $plotId])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } - }else{ - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $newOwnerName = TextFormat::GREEN . $newOwner->getName() . TextFormat::WHITE; - $sender->sendMessage($this->translateString("give.confirm", [$plotId, $newOwnerName])); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and $this->plugin->getPlotByPosition($player->getPosition()) instanceof Plot) - return new GiveForm(); - return null; + public function getFormClass() : ?string{ + return GiveForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/HelpSubCommand.php b/src/MyPlot/subcommand/HelpSubCommand.php index 5109aeda..f9b7fdd7 100644 --- a/src/MyPlot/subcommand/HelpSubCommand.php +++ b/src/MyPlot/subcommand/HelpSubCommand.php @@ -1,45 +1,35 @@ cmds = $cmds; +class HelpSubCommand extends SubCommand{ + public function __construct(MyPlot $plugin, InternalAPI $api, string $name, private Commands $cmds){ + parent::__construct($plugin, $api, $name); } - public function canUse(CommandSender $sender) : bool { + public function canUse(CommandSender $sender) : bool{ return $sender->hasPermission("myplot.command.help"); } /** * @param CommandSender $sender - * @param string[] $args + * @param string[] $args + * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { + public function execute(CommandSender $sender, array $args) : bool{ + if(count($args) === 0){ $pageNumber = 1; - }elseif(is_numeric($args[0])) { + }elseif(is_numeric($args[0])){ $pageNumber = (int) array_shift($args); - if ($pageNumber <= 0) { + if($pageNumber <= 0){ $pageNumber = 1; } }else{ @@ -47,25 +37,21 @@ public function execute(CommandSender $sender, array $args) : bool { } $commands = []; - foreach($this->cmds->getCommands() as $command) { - if ($command->canUse($sender)) { + foreach($this->cmds->getCommands() as $command){ + if($command->canUse($sender)){ $commands[$command->getName()] = $command; } } ksort($commands, SORT_NATURAL | SORT_FLAG_CASE); - $commands = array_chunk($commands, (int) ($sender->getScreenLineHeight()/2)); + $commands = array_chunk($commands, (int) ($sender->getScreenLineHeight() / 2)); /** @var SubCommand[][] $commands */ $pageNumber = min(count($commands), $pageNumber); - $sender->sendMessage(TextFormat::GREEN.$this->translateString("help.header", [$pageNumber, count($commands)])); - foreach($commands[$pageNumber - 1] as $command) { - $sender->sendMessage(TextFormat::BLUE . $command->getUsage().TextFormat::WHITE.":"); + $sender->sendMessage(TextFormat::GREEN . $this->translateString("help.header", [$pageNumber, count($commands)])); + foreach($commands[$pageNumber - 1] as $command){ + $sender->sendMessage(TextFormat::BLUE . $command->getUsage() . TextFormat::WHITE . ":"); $sender->sendMessage(TextFormat::AQUA . $command->getDescription()); } return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/HomeSubCommand.php b/src/MyPlot/subcommand/HomeSubCommand.php index a1df8e07..0019c4c1 100644 --- a/src/MyPlot/subcommand/HomeSubCommand.php +++ b/src/MyPlot/subcommand/HomeSubCommand.php @@ -1,66 +1,80 @@ hasPermission("myplot.command.home"); +class HomeSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.home")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - $plotNumber = 1; - }elseif(is_numeric($args[0])) { - $plotNumber = (int) $args[0]; - }else{ - return false; - } - $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("error", [$levelName])); - return true; - } - $plots = $this->plugin->getPlotsOfPlayer($sender->getName(), $levelName); - if(count($plots) === 0) { - $sender->sendMessage(TextFormat::RED . $this->translateString("home.noplots")); - return true; - } - if(!isset($plots[$plotNumber - 1])) { - $sender->sendMessage(TextFormat::RED . $this->translateString("home.notexist", [$plotNumber])); - return true; - } - usort($plots, function(Plot $plot1, Plot $plot2) { - if($plot1->levelName == $plot2->levelName) { - return 0; + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $plotNumber = 1; + }elseif(is_numeric($args[0])){ + $plotNumber = (int) $args[0]; + }else{ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); + if($this->internalAPI->getLevelSettings($levelName) === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("error", [$levelName])); + return; + } + $plots = yield from $this->internalAPI->generatePlotsOfPlayer($sender->getName(), $levelName); + if(count($plots) === 0){ + $sender->sendMessage(TextFormat::RED . $this->translateString("home.noplots")); + return; + } + if(!isset($plots[$plotNumber - 1])){ + $sender->sendMessage(TextFormat::RED . $this->translateString("home.notexist", [$plotNumber])); + return; + } + usort($plots, function(BasePlot $plot1, BasePlot $plot2){ + if($plot1->levelName == $plot2->levelName){ + return 0; + } + return ($plot1->levelName < $plot2->levelName) ? -1 : 1; + }); + $plot = $plots[$plotNumber - 1]; + if($this->internalAPI->teleportPlayerToPlot($sender, $plot, false)){ + $sender->sendMessage($this->translateString("home.success", [$plot->__toString(), $plot->levelName])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("home.error")); + } } - return ($plot1->levelName < $plot2->levelName) ? -1 : 1; - }); - $plot = $plots[$plotNumber - 1]; - if($this->plugin->teleportPlayerToPlot($sender, $plot)) { - $sender->sendMessage($this->translateString("home.success", [$plot->__toString(), $plot->levelName])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("home.error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and count($this->plugin->getPlotsOfPlayer($player->getName(), $player->getWorld()->getFolderName())) > 0) - return new HomeForm($player); - return null; + public function getFormClass() : ?string{ + return HomeForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/HomesSubCommand.php b/src/MyPlot/subcommand/HomesSubCommand.php index e8102c5e..b618158c 100644 --- a/src/MyPlot/subcommand/HomesSubCommand.php +++ b/src/MyPlot/subcommand/HomesSubCommand.php @@ -1,49 +1,60 @@ hasPermission("myplot.command.homes")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class HomesSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.homes"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $levelName = $args[0] ?? $sender->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("error", [$levelName])); - return true; - } - $plots = $this->plugin->getPlotsOfPlayer($sender->getName(), $levelName); - if(count($plots) === 0) { - $sender->sendMessage(TextFormat::RED . $this->translateString("homes.noplots")); - return true; - } - $sender->sendMessage(TextFormat::DARK_GREEN . $this->translateString("homes.header")); - for($i = 0; $i < count($plots); $i++) { - $plot = $plots[$i]; - $message = TextFormat::DARK_GREEN . ($i + 1) . ") "; - $message .= TextFormat::WHITE . $plot->levelName . " " . $plot; - if($plot->name !== "") { - $message .= " = " . $plot->name; + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $levelName = $args[0] ?? $sender->getWorld()->getFolderName(); + if($this->internalAPI->getLevelSettings($levelName) === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("error", [$levelName])); + return; + } + $plots = yield from $this->internalAPI->generatePlotsOfPlayer($sender->getName(), $levelName); + if(count($plots) === 0){ + $sender->sendMessage(TextFormat::RED . $this->translateString("homes.noplots")); + return; + } + $sender->sendMessage(TextFormat::DARK_GREEN . $this->translateString("homes.header")); + for($i = 0; $i < count($plots); $i++){ + $plot = $plots[$i]; + $message = TextFormat::DARK_GREEN . ($i + 1) . ") "; + $message .= TextFormat::WHITE . $plot->levelName . " " . $plot; + if($plot->name !== ""){ + $message .= " = " . $plot->name; + } + $sender->sendMessage($message); + } } - $sender->sendMessage($message); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; // we can just list homes in the home form - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/InfoSubCommand.php b/src/MyPlot/subcommand/InfoSubCommand.php index c101eb9b..76e34c00 100644 --- a/src/MyPlot/subcommand/InfoSubCommand.php +++ b/src/MyPlot/subcommand/InfoSubCommand.php @@ -1,72 +1,80 @@ hasPermission("myplot.command.info")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class InfoSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.info"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(isset($args[0])) { - if(isset($args[1]) and is_numeric($args[1])) { - $key = max(((int) $args[1] - 1), 1); - /** @var Plot[] $plots */ - $plots = []; - foreach($this->plugin->getPlotLevels() as $levelName => $settings) { - $plots = array_merge($plots, $this->plugin->getPlotsOfPlayer($args[0], $levelName)); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(isset($args[0])){ + if(isset($args[1]) and is_numeric($args[1])){ + $key = max(((int) $args[1] - 1), 1); + $plots = yield from $this->internalAPI->generatePlotsOfPlayer($args[0], null); + if(isset($plots[$key])){ + $plot = $plots[$key]; + $sender->sendMessage($this->translateString("info.about", [TextFormat::GREEN . $plot])); + $sender->sendMessage($this->translateString("info.owner", [TextFormat::GREEN . $plot->owner])); + $sender->sendMessage($this->translateString("info.plotname", [TextFormat::GREEN . $plot->name])); + $helpers = implode(", ", $plot->helpers); + $sender->sendMessage($this->translateString("info.helpers", [TextFormat::GREEN . $helpers])); + $denied = implode(", ", $plot->denied); + $sender->sendMessage($this->translateString("info.denied", [TextFormat::GREEN . $denied])); + $sender->sendMessage($this->translateString("info.biome", [TextFormat::GREEN . $plot->biome])); + return; + } + $sender->sendMessage(TextFormat::RED . $this->translateString("info.notfound")); + return; + } + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; } - if(isset($plots[$key])) { - $plot = $plots[$key]; - $sender->sendMessage($this->translateString("info.about", [TextFormat::GREEN . $plot])); - $sender->sendMessage($this->translateString("info.owner", [TextFormat::GREEN . $plot->owner])); - $sender->sendMessage($this->translateString("info.plotname", [TextFormat::GREEN . $plot->name])); - $helpers = implode(", ", $plot->helpers); - $sender->sendMessage($this->translateString("info.helpers", [TextFormat::GREEN . $helpers])); - $denied = implode(", ", $plot->denied); - $sender->sendMessage($this->translateString("info.denied", [TextFormat::GREEN . $denied])); - $sender->sendMessage($this->translateString("info.biome", [TextFormat::GREEN . $plot->biome])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("info.notfound")); + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; } - }else{ - return false; + $sender->sendMessage($this->translateString("info.about", [TextFormat::GREEN . $plot])); + $sender->sendMessage($this->translateString("info.owner", [TextFormat::GREEN . $plot->owner])); + $sender->sendMessage($this->translateString("info.plotname", [TextFormat::GREEN . $plot->name])); + $helpers = implode(", ", $plot->helpers); + $sender->sendMessage($this->translateString("info.helpers", [TextFormat::GREEN . $helpers])); + $denied = implode(", ", $plot->denied); + $sender->sendMessage($this->translateString("info.denied", [TextFormat::GREEN . $denied])); + $sender->sendMessage($this->translateString("info.biome", [TextFormat::GREEN . $plot->biome])); } - }else{ - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - $sender->sendMessage($this->translateString("info.about", [TextFormat::GREEN . $plot])); - $sender->sendMessage($this->translateString("info.owner", [TextFormat::GREEN . $plot->owner])); - $sender->sendMessage($this->translateString("info.plotname", [TextFormat::GREEN . $plot->name])); - $helpers = implode(", ", $plot->helpers); - $sender->sendMessage($this->translateString("info.helpers", [TextFormat::GREEN . $helpers])); - $denied = implode(", ", $plot->denied); - $sender->sendMessage($this->translateString("info.denied", [TextFormat::GREEN . $denied])); - $sender->sendMessage($this->translateString("info.biome", [TextFormat::GREEN . $plot->biome])); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new InfoForm($plot); - return null; + public function getFormClass() : ?string{ + return InfoForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/KickSubCommand.php b/src/MyPlot/subcommand/KickSubCommand.php index d90c5d7c..376d670f 100644 --- a/src/MyPlot/subcommand/KickSubCommand.php +++ b/src/MyPlot/subcommand/KickSubCommand.php @@ -1,63 +1,78 @@ hasPermission("myplot.command.kick")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class KickSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.kick"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if (!isset($args[0])) return false; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if ($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.kick")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $target = $this->plugin->getServer()->getPlayerByPrefix($args[0]); - if ($target === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("kick.noPlayer")); - return true; - } - if (($targetPlot = $this->plugin->getPlotByPosition($target->getPosition())) === null or !$plot->isSame($targetPlot)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("kick.notInPlot")); - return true; - } - if ($target->hasPermission("myplot.admin.kick.bypass")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("kick.cannotkick")); - $target->sendMessage($this->translateString("kick.attemptkick", [$target->getName()])); - return true; - } - if ($this->plugin->teleportPlayerToPlot($target, $plot)) { - $sender->sendMessage($this->translateString("kick.success1", [$target->getName(), $plot->__toString()])); - $target->sendMessage($this->translateString("kick.success2", [$sender->getName(), $plot->__toString()])); - return true; - } - $sender->sendMessage($this->translateString("error")); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(!isset($args[0])){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.kick")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $target = $this->plugin->getServer()->getPlayerByPrefix($args[0]); + if($target === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("kick.noPlayer")); + return; + } + if(($targetPlot = yield from $this->internalAPI->generatePlotByPosition($target->getPosition())) === null or !$plot->isSame($targetPlot)){ + $sender->sendMessage(TextFormat::RED . $this->translateString("kick.notInPlot")); + return; + } + if($target->hasPermission("myplot.admin.kick.bypass")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("kick.cannotkick")); + $target->sendMessage($this->translateString("kick.attemptkick", [$target->getName()])); + return; + } + if($this->internalAPI->teleportPlayerToPlot($target, $plot, false)){ + $sender->sendMessage($this->translateString("kick.success1", [$target->getName(), $plot->__toString()])); + $target->sendMessage($this->translateString("kick.success2", [$sender->getName(), $plot->__toString()])); + }else{ + $sender->sendMessage($this->translateString("error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new KickForm($plot); - return null; + public function getFormClass() : ?string{ + return KickForm::class; } } diff --git a/src/MyPlot/subcommand/ListSubCommand.php b/src/MyPlot/subcommand/ListSubCommand.php index 6977cf49..f6c81e4b 100644 --- a/src/MyPlot/subcommand/ListSubCommand.php +++ b/src/MyPlot/subcommand/ListSubCommand.php @@ -1,61 +1,40 @@ hasPermission("myplot.command.list"); } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if($sender->hasPermission("myplot.admin.list")) { - if(count($args) > 0) { - foreach($this->plugin->getPlotLevels() as $levelName => $settings) { - $plots = $this->plugin->getPlotsOfPlayer($args[0], $levelName); - foreach($plots as $plot) { - $name = $plot->name; - $x = $plot->X; - $z = $plot->Z; - $sender->sendMessage(TF::YELLOW . $this->translateString("list.found", [$name, $x, $z])); - } - } - }else{ - foreach($this->plugin->getPlotLevels() as $levelName => $settings) { - $plots = $this->plugin->getPlotsOfPlayer($sender->getName(), $levelName); - foreach($plots as $plot) { - $name = $plot->name; - $x = $plot->X; - $z = $plot->Z; - $sender->sendMessage(TF::YELLOW . $this->translateString("list.found", [$name, $x, $z])); - } - } - } - }elseif($sender->hasPermission("myplot.command.list")) { - foreach($this->plugin->getPlotLevels() as $levelName => $settings) { - $plots = $this->plugin->getPlotsOfPlayer($sender->getName(), $levelName); - foreach($plots as $plot) { + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) > 0 and $sender->hasPermission("myplot.admin.list")) + $plots = yield from $this->internalAPI->generatePlotsOfPlayer($args[0], null); + else + $plots = yield from $this->internalAPI->generatePlotsOfPlayer($sender->getName(), null); + + foreach($plots as $plot){ $name = $plot->name; $x = $plot->X; $z = $plot->Z; $sender->sendMessage(TF::YELLOW . $this->translateString("list.found", [$name, $x, $z])); } } - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; // this will probably be merged into the homes command - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/MergeSubCommand.php b/src/MyPlot/subcommand/MergeSubCommand.php index 2c364588..35a1f037 100644 --- a/src/MyPlot/subcommand/MergeSubCommand.php +++ b/src/MyPlot/subcommand/MergeSubCommand.php @@ -1,111 +1,124 @@ hasPermission("myplot.command.merge")); +class MergeSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.merge")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.merge")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(!isset($args[0])) { - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("merge.confirmface", [$plotId])); - return true; - }elseif($args[0] === $this->translateString("confirm")) { - $rotation = ($sender->getLocation()->getYaw() - 180) % 360; - if($rotation < 0) { - $rotation += 360.0; - } - if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)) { - $direction = Facing::NORTH; //North - $args[0] = $this->translateString("merge.north"); - }elseif(45 <= $rotation and $rotation < 135) { - $direction = Facing::EAST; //East - $args[0] = $this->translateString("merge.east"); - }elseif(135 <= $rotation and $rotation < 225) { - $direction = Facing::SOUTH; //South - $args[0] = $this->translateString("merge.south"); - }elseif(225 <= $rotation and $rotation < 315) { - $direction = Facing::WEST; //West - $args[0] = $this->translateString("merge.west"); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - return true; - } - }else{ - switch(strtolower($args[0])) { - case "north": - case "-z": - case "z-": - case $this->translateString("merge.north"): - $direction = Facing::NORTH; - $args[0] = $this->translateString("merge.north"); - break; - case "east": - case "+x": - case "x+": - case $this->translateString("merge.east"): - $direction = Facing::EAST; - $args[0] = $this->translateString("merge.east"); - break; - case "south": - case "+z": - case "z+": - case $this->translateString("merge.south"): - $direction = Facing::SOUTH; - $args[0] = $this->translateString("merge.south"); - break; - case "west": - case "-x": - case "x-": - case $this->translateString("merge.west"): - $direction = Facing::WEST; - $args[0] = $this->translateString("merge.west"); - break; - default: - $sender->sendMessage(TextFormat::RED . $this->translateString("merge.direction")); - return true; - } - if(!isset($args[1]) or $args[1] !== $this->translateString("confirm")) { - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("merge.confirmarg", [$plotId, $args[0], implode(' ', $args)." ".$this->translateString("confirm")])); - return true; + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender) : \Generator{ + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.merge")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!isset($args[0])){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("merge.confirmface", [$plotId])); + return; + }elseif($args[0] === $this->translateString("confirm")){ + $rotation = ($sender->getLocation()->getYaw() - 180) % 360; + if($rotation < 0){ + $rotation += 360.0; + } + if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)){ + $direction = Facing::NORTH; //North + $args[0] = $this->translateString("merge.north"); + }elseif(45 <= $rotation and $rotation < 135){ + $direction = Facing::EAST; //East + $args[0] = $this->translateString("merge.east"); + }elseif(135 <= $rotation and $rotation < 225){ + $direction = Facing::SOUTH; //South + $args[0] = $this->translateString("merge.south"); + }elseif(225 <= $rotation and $rotation < 315){ + $direction = Facing::WEST; //West + $args[0] = $this->translateString("merge.west"); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + return; + } + }else{ + switch(strtolower($args[0])){ + case "north": + case "-z": + case "z-": + case $this->translateString("merge.north"): + $direction = Facing::NORTH; + $args[0] = $this->translateString("merge.north"); + break; + case "east": + case "+x": + case "x+": + case $this->translateString("merge.east"): + $direction = Facing::EAST; + $args[0] = $this->translateString("merge.east"); + break; + case "south": + case "+z": + case "z+": + case $this->translateString("merge.south"): + $direction = Facing::SOUTH; + $args[0] = $this->translateString("merge.south"); + break; + case "west": + case "-x": + case "x-": + case $this->translateString("merge.west"): + $direction = Facing::WEST; + $args[0] = $this->translateString("merge.west"); + break; + default: + $sender->sendMessage(TextFormat::RED . $this->translateString("merge.direction")); + return; + } + if(!isset($args[1]) or $args[1] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("merge.confirmarg", [$plotId, $args[0], implode(' ', $args) . " " . $this->translateString("confirm")])); + return; + } + } + $maxBlocksPerTick = $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); + if(!is_int($maxBlocksPerTick)) + $maxBlocksPerTick = 256; + if(yield from $this->internalAPI->generateMergePlots($plot, $direction, $maxBlocksPerTick)){ + $plot = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("merge.success", [$plot, $args[0]])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - } - $maxBlocksPerTick = (int) $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); - if($this->plugin->mergePlots($plot, $direction, $maxBlocksPerTick)) { - $plot = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("merge.success", [$plot, $args[0]])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/MiddleSubCommand.php b/src/MyPlot/subcommand/MiddleSubCommand.php index cfd9d7a3..efa4863c 100644 --- a/src/MyPlot/subcommand/MiddleSubCommand.php +++ b/src/MyPlot/subcommand/MiddleSubCommand.php @@ -1,44 +1,56 @@ hasPermission("myplot.command.middle")); +class MiddleSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.middle")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) != 0) { - return false; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.middle")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if($this->plugin->teleportPlayerToPlot($sender, $plot, true)) { - $sender->sendMessage(TextFormat::GREEN . $this->translateString("middle.success")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) != 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.middle")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if($this->internalAPI->teleportPlayerToPlot($sender, $plot, true)){ + $sender->sendMessage(TextFormat::GREEN . $this->translateString("middle.success")); + } + } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/MyPlotSubCommand.php b/src/MyPlot/subcommand/MyPlotSubCommand.php new file mode 100644 index 00000000..4e4aab39 --- /dev/null +++ b/src/MyPlot/subcommand/MyPlotSubCommand.php @@ -0,0 +1,27 @@ +hasPermission("myplot.command.name")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class NameSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.name"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.name")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if($this->plugin->renamePlot($plot, $args[0])) { - $sender->sendMessage($this->translateString("name.success")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.name")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(yield from $this->internalAPI->generateRenamePlot($plot, $args[0])){ + $sender->sendMessage($this->translateString("name.success")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new NameForm($player, $plot); - return null; + public function getFormClass() : ?string{ + return NameForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/PvpSubCommand.php b/src/MyPlot/subcommand/PvpSubCommand.php index 2e2459e7..604d8812 100644 --- a/src/MyPlot/subcommand/PvpSubCommand.php +++ b/src/MyPlot/subcommand/PvpSubCommand.php @@ -1,48 +1,49 @@ hasPermission("myplot.command.pvp"); } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED.$this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.pvp")) { - $sender->sendMessage(TextFormat::RED.$this->translateString("notowner")); - return true; - } - $levelSettings = $this->plugin->getLevelSettings($sender->getWorld()->getFolderName()); - if($levelSettings->restrictPVP) { - $sender->sendMessage(TextFormat::RED.$this->translateString("pvp.world")); - return true; - } - if($this->plugin->setPlotPvp($plot, !$plot->pvp)) { - $sender->sendMessage($this->translateString("pvp.success", [!$plot->pvp ? "enabled" : "disabled"])); - }else { - $sender->sendMessage(TextFormat::RED.$this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.pvp")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $levelSettings = $this->plugin->getLevelSettings($sender->getWorld()->getFolderName()); + if($levelSettings->restrictPVP){ + $sender->sendMessage(TextFormat::RED . $this->translateString("pvp.world")); + return; + } + if(yield from $this->internalAPI->generatePlotPvp($plot, !$plot->pvp)){ + $sender->sendMessage($this->translateString("pvp.success", [!$plot->pvp ? "enabled" : "disabled"])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/RemoveHelperSubCommand.php b/src/MyPlot/subcommand/RemoveHelperSubCommand.php index 7ef7d1d2..a0be5b52 100644 --- a/src/MyPlot/subcommand/RemoveHelperSubCommand.php +++ b/src/MyPlot/subcommand/RemoveHelperSubCommand.php @@ -1,54 +1,68 @@ hasPermission("myplot.command.removehelper")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class RemoveHelperSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.removehelper"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $helperName = $args[0]; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.removehelper")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $helper = $this->plugin->getServer()->getPlayerByPrefix($helperName); - if($helper === null) - $helper = $this->plugin->getServer()->getOfflinePlayer($helperName); - if($this->plugin->removePlotHelper($plot, $helper->getName())) { - $sender->sendMessage($this->translateString("removehelper.success", [$helper->getName()])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $helperName = $args[0]; + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.removehelper")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $helper = $this->plugin->getServer()->getPlayerByPrefix($helperName); + if($helper === null) + $helper = $this->plugin->getServer()->getOfflinePlayer($helperName); + + if(yield from $this->internalAPI->generateRemovePlotHelper($plot, $helper->getName())){ + $sender->sendMessage($this->translateString("removehelper.success", [$helper->getName()])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new RemoveHelperForm($plot); - return null; + public function getFormClass() : ?string{ + return RemoveHelperForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/ResetSubCommand.php b/src/MyPlot/subcommand/ResetSubCommand.php index 6a2705e0..3fa31470 100644 --- a/src/MyPlot/subcommand/ResetSubCommand.php +++ b/src/MyPlot/subcommand/ResetSubCommand.php @@ -1,56 +1,68 @@ hasPermission("myplot.command.reset")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } -class ResetSubCommand extends SubCommand -{ - public function canUse(CommandSender $sender) : bool { - return ($sender instanceof Player) and $sender->hasPermission("myplot.command.reset"); + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.reset")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(isset($args[0]) and $args[0] == $this->translateString("confirm")) { - $economy = $this->plugin->getEconomyProvider(); - $price = $this->plugin->getLevelSettings($plot->levelName)->resetPrice; - if($economy !== null and !$economy->reduceMoney($sender, $price)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("reset.nomoney")); - return true; - } - /** @var int $maxBlocksPerTick */ - $maxBlocksPerTick = $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); - if($this->plugin->resetPlot($plot, $maxBlocksPerTick)) { - $sender->sendMessage($this->translateString("reset.success")); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.reset")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!isset($args[0]) and $args[0] !== $this->translateString("confirm")){ + $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("reset.confirm", [$plotId])); + return; + } + $economy = $this->internalAPI->getEconomyProvider(); + $price = $this->plugin->getLevelSettings($plot->levelName)->resetPrice; + if($economy !== null and !(yield from $economy->reduceMoney($sender, $price))){ + $sender->sendMessage(TextFormat::RED . $this->translateString("reset.nomoney")); + return; + } + $maxBlocksPerTick = $this->plugin->getConfig()->get("ClearBlocksPerTick", 256); + if(!is_int($maxBlocksPerTick)) + $maxBlocksPerTick = 256; + if(yield from $this->internalAPI->generateResetPlot($plot, $maxBlocksPerTick)){ + $sender->sendMessage($this->translateString("reset.success")); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - }else{ - $plotId = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("reset.confirm", [$plotId])); - } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - return null; - } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/SellSubCommand.php b/src/MyPlot/subcommand/SellSubCommand.php index 7a515371..9f93809c 100644 --- a/src/MyPlot/subcommand/SellSubCommand.php +++ b/src/MyPlot/subcommand/SellSubCommand.php @@ -1,52 +1,67 @@ hasPermission("myplot.command.sell"); +class SellSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.sell")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null){ - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.sell")){ - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - if(!is_numeric($args[0])) - return false; - $price = (float)$args[0]; - if($this->plugin->sellPlot($plot, $price) and $price > 0) { - $sender->sendMessage($this->translateString("sell.success", ["$plot->X;$plot->Z", $price])); - }elseif($price <= 0){ - $sender->sendMessage(TextFormat::RED . $this->translateString("sell.unlisted", ["$plot->X;$plot->Z"])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.sell")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + if(!is_numeric($args[0])){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $price = (int) $args[0]; + if($price <= 0){ + $sender->sendMessage(TextFormat::RED . $this->translateString("sell.unlisted", ["$plot->X;$plot->Z"])); + return; + } + if(yield from $this->internalAPI->generateSellPlot($plot, $price)){ + $sender->sendMessage($this->translateString("sell.success", ["$plot->X;$plot->Z", $price])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } + } + ); return true; } - - public function getForm(?Player $player = null) : ?MyPlotForm { - // TODO: Implement getForm() method. - return null; - } } diff --git a/src/MyPlot/subcommand/SetOwnerSubCommand.php b/src/MyPlot/subcommand/SetOwnerSubCommand.php index 34f09c1e..e34d1d59 100644 --- a/src/MyPlot/subcommand/SetOwnerSubCommand.php +++ b/src/MyPlot/subcommand/SetOwnerSubCommand.php @@ -1,57 +1,64 @@ hasPermission("myplot.admin.setowner"); +class SetOwnerSubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.admin.setowner")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); - $plotsOfPlayer = 0; - foreach($this->plugin->getPlotLevels() as $level => $settings) { - $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($level); - if($level !== null and $level->isLoaded()) { - $plotsOfPlayer += count($this->plugin->getPlotsOfPlayer($sender->getName(), $level->getFolderName())); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + $maxPlots = $this->plugin->getMaxPlotsOfPlayer($sender); + if(count($this->internalAPI->generatePlotsOfPlayer($sender->getName(), null)) >= $maxPlots){ + $sender->sendMessage(TextFormat::RED . $this->translateString("setowner.maxplots", [$maxPlots])); + return; + } + if(yield from $this->internalAPI->generateClaimPlot($plot, $args[0], '')){ + $sender->sendMessage($this->translateString("setowner.success", [$args[0]])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - } - if($plotsOfPlayer >= $maxPlots) { - $sender->sendMessage(TextFormat::RED . $this->translateString("setowner.maxplots", [$maxPlots])); - return true; - } - if($this->plugin->claimPlot($plot, $args[0])) { - $sender->sendMessage($this->translateString("setowner.success", [$args[0]])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and $this->plugin->getPlotByPosition($player->getPosition()) instanceof Plot) - return new OwnerForm(); - return null; + public function getFormClass() : ?string{ + return OwnerForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/SubCommand.php b/src/MyPlot/subcommand/SubCommand.php index dc4b9b22..3b512968 100644 --- a/src/MyPlot/subcommand/SubCommand.php +++ b/src/MyPlot/subcommand/SubCommand.php @@ -1,69 +1,44 @@ plugin = $plugin; - $this->name = $name; - } - /** - * @return MyPlot - */ - public final function getPlugin() : MyPlot { - return $this->plugin; - } +abstract class SubCommand implements MyPlotSubCommand{ + public function __construct(protected MyPlot $plugin, protected InternalAPI $internalAPI, private string $name){ } - /** - * @param string $str - * @param (float|int|string)[] $params - * @param string $onlyPrefix - * - * @return string - */ - protected function translateString(string $str, array $params = [], string $onlyPrefix = null) : string { - return $this->plugin->getLanguage()->translateString($str, $params, $onlyPrefix); - } + protected function translateString(string $str, array $params = [], ?string $onlyPrefix = null) : string{ + return $this->plugin->getLanguage()->translateString($str, $params, $onlyPrefix); + } public abstract function canUse(CommandSender $sender) : bool; - public function getUsage() : string { - $usage = $this->plugin->getFallBackLang()->get($this->name . ".usage"); // TODO: use normal language when command autofill gains support - return ($usage == $this->name . ".usage") ? "" : $usage; - } + public function getUsage() : string{ + $usage = $this->plugin->getFallBackLang()->get($this->name . ".usage"); // TODO: use normal language when command autofill gains support + return ($usage == $this->name . ".usage") ? "" : $usage; + } - public function getName() : string { - $name = $this->plugin->getLanguage()->get($this->name . ".name"); - return ($name == $this->name . ".name") ? "" : $name; - } + public function getName() : string{ + $name = $this->plugin->getLanguage()->get($this->name . ".name"); + return ($name == $this->name . ".name") ? "" : $name; + } - public function getDescription() : string { - $desc = $this->plugin->getLanguage()->get($this->name . ".desc"); - return ($desc == $this->name . ".desc") ? "" : $desc; - } + public function getDescription() : string{ + $desc = $this->plugin->getLanguage()->get($this->name . ".desc"); + return ($desc == $this->name . ".desc") ? "" : $desc; + } - public function getAlias() : string { - $alias = $this->plugin->getLanguage()->get($this->name . ".alias"); - return ($alias == $this->name . ".alias") ? "" : $alias; - } + public function getAlias() : string{ + $alias = $this->plugin->getLanguage()->get($this->name . ".alias"); + return ($alias == $this->name . ".alias") ? "" : $alias; + } - public abstract function getForm(?Player $player = null) : ?MyPlotForm; + public function getFormClass() : ?string{ + return null; + } - /** - * @param CommandSender $sender - * @param string[] $args - * - * @return bool - */ public abstract function execute(CommandSender $sender, array $args) : bool; } \ No newline at end of file diff --git a/src/MyPlot/subcommand/UnDenySubCommand.php b/src/MyPlot/subcommand/UnDenySubCommand.php index 2f480525..4148f406 100644 --- a/src/MyPlot/subcommand/UnDenySubCommand.php +++ b/src/MyPlot/subcommand/UnDenySubCommand.php @@ -1,57 +1,71 @@ hasPermission("myplot.command.undenyplayer"); +class UnDenySubCommand extends SubCommand{ + public function canUse(CommandSender $sender) : bool{ + if(!$sender->hasPermission("myplot.command.undenyplayer")){ + return false; + } + if($sender instanceof Player){ + $pos = $sender->getPosition(); + $plotLevel = $this->internalAPI->getLevelSettings($sender->getWorld()->getFolderName()); + if($this->internalAPI->getPlotFast($pos->x, $pos->z, $plotLevel) === null){ + return false; + } + } + + return true; } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $dplayerName = $args[0]; - $plot = $this->plugin->getPlotByPosition($sender->getPosition()); - if($plot === null) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); - return true; - } - if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.undenyplayer")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); - return true; - } - $dplayer = $this->plugin->getServer()->getPlayerByPrefix($dplayerName); - if($dplayer === null) - $dplayer = $this->plugin->getServer()->getOfflinePlayer($dplayerName); - if($this->plugin->removePlotDenied($plot, $dplayer->getName())) { - $sender->sendMessage($this->translateString("undenyplayer.success1", [$dplayer->getName()])); - if($dplayer instanceof Player) { - $dplayer->sendMessage($this->translateString("undenyplayer.success2", [$plot->X, $plot->Z, $sender->getName()])); + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $dplayerName = $args[0]; + $plot = yield from $this->internalAPI->generatePlotByPosition($sender->getPosition()); + if($plot === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notinplot")); + return; + } + if($plot->owner !== $sender->getName() and !$sender->hasPermission("myplot.admin.undenyplayer")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("notowner")); + return; + } + $dplayer = $this->plugin->getServer()->getPlayerByPrefix($dplayerName); + if($dplayer === null) + $dplayer = $this->plugin->getServer()->getOfflinePlayer($dplayerName); + + if(yield from $this->internalAPI->generateRemovePlotDenied($plot, $dplayer->getName())){ + $sender->sendMessage($this->translateString("undenyplayer.success1", [$dplayer->getName()])); + if($dplayer instanceof Player){ + $dplayer->sendMessage($this->translateString("undenyplayer.success2", [$plot->X, $plot->Z, $sender->getName()])); + } + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("error")); + } } - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("error")); - } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - if($player !== null and ($plot = $this->plugin->getPlotByPosition($player->getPosition())) instanceof Plot) - return new UndenyPlayerForm($plot); - return null; + public function getFormClass() : ?string{ + return UndenyPlayerForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/subcommand/WarpSubCommand.php b/src/MyPlot/subcommand/WarpSubCommand.php index 91a59a4d..7bd640ce 100644 --- a/src/MyPlot/subcommand/WarpSubCommand.php +++ b/src/MyPlot/subcommand/WarpSubCommand.php @@ -1,54 +1,60 @@ hasPermission("myplot.command.warp"); } /** - * @param Player $sender + * @param Player $sender * @param string[] $args * * @return bool */ - public function execute(CommandSender $sender, array $args) : bool { - if(count($args) === 0) { - return false; - } - $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); - if(!$this->plugin->isLevelLoaded($levelName)) { - $sender->sendMessage(TextFormat::RED . $this->translateString("warp.notinplotworld")); - return true; - } - $plotIdArray = explode(";", $args[0]); - if(count($plotIdArray) != 2 or !is_numeric($plotIdArray[0]) or !is_numeric($plotIdArray[1])) { - $sender->sendMessage(TextFormat::RED . $this->translateString("warp.wrongid")); - return true; - } - $plot = $this->plugin->getProvider()->getPlot($levelName, (int) $plotIdArray[0], (int) $plotIdArray[1]); - if($plot->owner == "" and !$sender->hasPermission("myplot.admin.warp")) { - $sender->sendMessage(TextFormat::RED . $this->translateString("warp.unclaimed")); - return true; - } - if($this->plugin->teleportPlayerToPlot($sender, $plot)) { - $plot = TextFormat::GREEN . $plot . TextFormat::WHITE; - $sender->sendMessage($this->translateString("warp.success", [$plot])); - }else{ - $sender->sendMessage(TextFormat::RED . $this->translateString("generate.error")); - } + public function execute(CommandSender $sender, array $args) : bool{ + Await::f2c( + function() use ($sender, $args) : \Generator{ + if(count($args) === 0){ + $sender->sendMessage($this->translateString("subcommand.usage", [$this->getUsage()])); + return; + } + $levelName = $args[1] ?? $sender->getWorld()->getFolderName(); + if($this->internalAPI->getLevelSettings($levelName) === null){ + $sender->sendMessage(TextFormat::RED . $this->translateString("warp.notinplotworld")); + return; + } + $plotIdArray = explode(";", $args[0]); + if(count($plotIdArray) != 2 or !is_numeric($plotIdArray[0]) or !is_numeric($plotIdArray[1])){ + $sender->sendMessage(TextFormat::RED . $this->translateString("warp.wrongid")); + return; + } + $plot = yield from $this->internalAPI->generatePlot(new BasePlot($levelName, (int) $plotIdArray[0], (int) $plotIdArray[1])); + if($plot->owner == "" and !$sender->hasPermission("myplot.admin.warp")){ + $sender->sendMessage(TextFormat::RED . $this->translateString("warp.unclaimed")); + return; + } + if($this->internalAPI->teleportPlayerToPlot($sender, $plot, false)){ + $plot = TextFormat::GREEN . $plot . TextFormat::WHITE; + $sender->sendMessage($this->translateString("warp.success", [$plot])); + }else{ + $sender->sendMessage(TextFormat::RED . $this->translateString("generate.error")); + } + } + ); return true; } - public function getForm(?Player $player = null) : ?MyPlotForm { - return $player !== null ? new WarpForm($player) : null; + public function getFormClass() : ?string{ + return WarpForm::class; } } \ No newline at end of file diff --git a/src/MyPlot/task/BorderCorrectionTask.php b/src/MyPlot/task/BorderCorrectionTask.php index 8718afc8..6343d5c5 100644 --- a/src/MyPlot/task/BorderCorrectionTask.php +++ b/src/MyPlot/task/BorderCorrectionTask.php @@ -3,9 +3,10 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; -use pocketmine\block\Block; +use MyPlot\plot\BasePlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\VanillaBlocks; +use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\scheduler\CancelTaskException; @@ -13,60 +14,43 @@ use pocketmine\world\World; class BorderCorrectionTask extends Task{ - protected MyPlot $plugin; - protected Plot $start; - protected World $level; - protected int $height; - protected Block $plotWallBlock; + protected AxisAlignedBB $aabb; protected Vector3 $plotBeginPos; - protected int $xMax; - protected int $zMax; - protected int $direction; - protected Block $roadBlock; - protected Block $groundBlock; - protected Block $bottomBlock; - protected Plot $end; - protected bool $fillCorner; - protected int $cornerDirection; + protected PlotLevelSettings $plotLevel; protected Vector3 $pos; - protected int $maxBlocksPerTick; + protected World $world; - public function __construct(MyPlot $plugin, Plot $start, Plot $end, bool $fillCorner = false, int $cornerDirection = -1, int $maxBlocksPerTick = 256) { - $this->plugin = $plugin; - $this->start = $start; - $this->end = $end; - $this->fillCorner = $fillCorner; - $this->cornerDirection = $cornerDirection; - $this->maxBlocksPerTick = $maxBlocksPerTick; + public function __construct(private MyPlot $plugin, private BasePlot $start, private BasePlot $end, private bool $fillCorner = false, private int $cornerDirection = -1, private int $maxBlocksPerTick = 256){ + if($start->isSame($end)) + throw new \Exception("Plot arguments cannot be the same plot or already be merged"); + if(abs($start->X - $end->X) !== 1 and abs($start->Z - $end->Z) !== 1) + throw new \Exception("Plot arguments must be adjacent plots"); - $this->plotBeginPos = $plugin->getPlotPosition($start, false); - $this->level = $this->plotBeginPos->getWorld(); + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($start->levelName); + $this->plotLevel = $plugin->getLevelSettings($start->levelName); + $this->aabb = $aabb = null; + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); - $plotLevel = $plugin->getLevelSettings($start->levelName); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $this->height = $plotLevel->groundHeight; - $this->plotWallBlock = $plotLevel->wallBlock; - $this->roadBlock = $plotLevel->roadBlock; - $this->groundBlock = $plotLevel->plotFillBlock; - $this->bottomBlock = $plotLevel->bottomBlock; - - if(($start->Z - $end->Z) === 1) { // North Z- + if(($start->Z - $end->Z) === 1){ // North Z- $this->plotBeginPos = $this->plotBeginPos->subtract(0, 0, $roadWidth); $this->xMax = (int) ($this->plotBeginPos->x + $plotSize); $this->zMax = (int) ($this->plotBeginPos->z + $roadWidth); $this->direction = Facing::NORTH; - }elseif(($start->X - $end->X) === -1) { // East X+ + }elseif(($start->X - $end->X) === -1){ // East X+ $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, 0); $this->xMax = (int) ($this->plotBeginPos->x + $roadWidth); $this->zMax = (int) ($this->plotBeginPos->z + $plotSize); $this->direction = Facing::EAST; - }elseif(($start->Z - $end->Z) === -1) { // South Z+ + }elseif(($start->Z - $end->Z) === -1){ // South Z+ $this->plotBeginPos = $this->plotBeginPos->add(0, 0, $plotSize); $this->xMax = (int) ($this->plotBeginPos->x + $plotSize); $this->zMax = (int) ($this->plotBeginPos->z + $roadWidth); $this->direction = Facing::SOUTH; - }elseif(($start->X - $end->X) === 1) { // West X- + }elseif(($start->X - $end->X) === 1){ // West X- $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, 0); $this->xMax = (int) ($this->plotBeginPos->x + $roadWidth); $this->zMax = (int) ($this->plotBeginPos->z + $plotSize); @@ -80,11 +64,11 @@ public function __construct(MyPlot $plugin, Plot $start, Plot $end, bool $fillCo $plugin->getLogger()->debug("Border Correction Task started between plots $start->X;$start->Z and $end->X;$end->Z"); } - public function onRun() : void { + public function onRun() : void{ $blocks = 0; - if($this->direction === Facing::NORTH or $this->direction === Facing::SOUTH) { - while($this->pos->z < $this->zMax) { - while($this->pos->y < $this->level->getMaxY()) { + if($this->direction === Facing::NORTH or $this->direction === Facing::SOUTH){ + while($this->pos->z < $this->zMax){ + while($this->pos->y < $this->level->getMaxY()){ if($this->pos->y > $this->height + 1) $block = VanillaBlocks::AIR(); elseif($this->pos->y === $this->height + 1){ @@ -102,7 +86,7 @@ public function onRun() : void { $this->pos->y++; $blocks += 2; - if($blocks >= $this->maxBlocksPerTick) { + if($blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); @@ -112,8 +96,8 @@ public function onRun() : void { $this->pos->z++; } }else{ - while($this->pos->x < $this->xMax) { - while($this->pos->y < $this->level->getMaxY()) { + while($this->pos->x < $this->xMax){ + while($this->pos->y < $this->level->getMaxY()){ if($this->pos->y > $this->height + 1) $block = VanillaBlocks::AIR(); elseif($this->pos->y === $this->height + 1) @@ -128,7 +112,7 @@ public function onRun() : void { $this->level->setBlock(new Vector3($this->pos->x, $this->pos->y, $this->zMax), $block, false); $this->pos->y++; $blocks += 2; - if($blocks >= $this->maxBlocksPerTick) { + if($blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); diff --git a/src/MyPlot/task/ClearBorderTask.php b/src/MyPlot/task/ClearBorderTask.php index 338c3df3..76ad803e 100644 --- a/src/MyPlot/task/ClearBorderTask.php +++ b/src/MyPlot/task/ClearBorderTask.php @@ -3,95 +3,80 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; -use pocketmine\block\Block; +use MyPlot\plot\BasePlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\VanillaBlocks; +use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; +use pocketmine\scheduler\CancelTaskException; use pocketmine\scheduler\Task; use pocketmine\world\World; -class ClearBorderTask extends Task { - protected MyPlot $plugin; - protected Plot $plot; - protected World $level; - protected int $height; - protected Block $plotWallBlock; +class ClearBorderTask extends Task{ + protected AxisAlignedBB $aabb; protected Vector3 $plotBeginPos; - protected int $xMax; - protected int $zMax; - protected Block $roadBlock; - protected Block $groundBlock; - protected Block $bottomBlock; + protected PlotLevelSettings $plotLevel; + protected Vector3 $pos; + protected World $world; - /** - * ClearBorderTask constructor. - * - * @param MyPlot $plugin - * @param Plot $plot - */ - public function __construct(MyPlot $plugin, Plot $plot) { - $this->plugin = $plugin; - $this->plot = $plot; - $plotLevel = $plugin->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize; - $this->plotBeginPos = $plugin->getPlotPosition($plot, false); - $this->xMax = (int)($this->plotBeginPos->x + $plotSize); - $this->zMax = (int)($this->plotBeginPos->z + $plotSize); - foreach ($plugin->getProvider()->getMergedPlots($plot) as $mergedPlot){ - $xplot = $plugin->getPlotPosition($mergedPlot, false)->x; - $zplot = $plugin->getPlotPosition($mergedPlot, false)->z; - $xMaxPlot = (int)($xplot + $plotSize); - $zMaxPlot = (int)($zplot + $plotSize); - if($this->plotBeginPos->x > $xplot) $this->plotBeginPos->x = $xplot; - if($this->plotBeginPos->z > $zplot) $this->plotBeginPos->z = $zplot; - if($this->xMax < $xMaxPlot) $this->xMax = $xMaxPlot; - if($this->zMax < $zMaxPlot) $this->zMax = $zMaxPlot; - } - - --$this->plotBeginPos->x; - --$this->plotBeginPos->z; - $this->level = $this->plotBeginPos->getWorld(); - $this->height = $plotLevel->groundHeight; - $this->plotWallBlock = $plotLevel->wallBlock; - $this->roadBlock = $plotLevel->roadBlock; - $this->groundBlock = $plotLevel->plotFillBlock; - $this->bottomBlock = $plotLevel->bottomBlock; + public function __construct(private MyPlot $plugin, private BasePlot $plot, private int $maxBlocksPerTick = 256){ + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + $this->plotLevel = $plugin->getLevelSettings($plot->levelName); + $this->aabb = $aabb = $this->plugin->getPlotBB($plot)->expand(1, 0, 1); + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); $plugin->getLogger()->debug("Border Clear Task started at plot $plot->X;$plot->Z"); } - public function onRun() : void { - for($x = $this->plotBeginPos->x; $x <= $this->xMax; $x++) { - for($y = 0; $y < $this->level->getMaxY(); ++$y) { - if($y > $this->height + 1) + public function onRun() : void{ + $blocks = 0; + for($x = $this->plotBeginPos->x; $x <= $this->aabb->maxX; $x++){ + for($y = 0; $y < $this->aabb->maxY; ++$y){ + if($y > $this->plotLevel->groundHeight + 1) $block = VanillaBlocks::AIR(); - elseif($y === $this->height + 1) - $block = $this->plotWallBlock; - elseif($y === $this->height) - $block = $this->roadBlock; - elseif($y === 0) - $block = $this->bottomBlock; - else//if($y < $this->height) - $block = $this->groundBlock; - $this->level->setBlock(new Vector3($x, $y, $this->plotBeginPos->z), $block, false); - $this->level->setBlock(new Vector3($x, $y, $this->zMax), $block, false); + elseif($y === $this->plotLevel->groundHeight + 1) + $block = $this->plotLevel->wallBlock; + elseif($y === $this->plotLevel->groundHeight) + $block = $this->plotLevel->roadBlock; + elseif($y === $this->aabb->minY) + $block = $this->plotLevel->bottomBlock; + else//if($y < $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFloorBlock; + $this->world->setBlock(new Vector3($x, $y, $this->plotBeginPos->z), $block, false); + $this->world->setBlock(new Vector3($x, $y, $this->aabb->maxZ), $block, false); + $blocks += 2; } } - for($z = $this->plotBeginPos->z; $z <= $this->zMax; $z++) { - for($y = 0; $y < $this->level->getMaxY(); ++$y) { - if($y > $this->height+1) + if($blocks >= $this->maxBlocksPerTick){ + $this->setHandler(null); + $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); + throw new CancelTaskException(); + } + for($z = $this->plotBeginPos->z; $z <= $this->aabb->maxZ; $z++){ + for($y = 0; $y < $this->aabb->maxY; ++$y){ + if($y > $this->plotLevel->groundHeight + 1) $block = VanillaBlocks::AIR(); - elseif($y === $this->height + 1) - $block = $this->plotWallBlock; - elseif($y === $this->height) - $block = $this->roadBlock; - elseif($y === 0) - $block = $this->bottomBlock; - else//if($y < $this->height) - $block = $this->groundBlock; - $this->level->setBlock(new Vector3($this->plotBeginPos->x, $y, $z), $block, false); - $this->level->setBlock(new Vector3($this->xMax, $y, $z), $block, false); + elseif($y === $this->plotLevel->groundHeight + 1) + $block = $this->plotLevel->wallBlock; + elseif($y === $this->plotLevel->groundHeight) + $block = $this->plotLevel->roadBlock; + elseif($y === $this->aabb->minY) + $block = $this->plotLevel->bottomBlock; + else//if($y < $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFloorBlock; + $this->world->setBlock(new Vector3($this->plotBeginPos->x, $y, $z), $block, false); + $this->world->setBlock(new Vector3($this->aabb->maxX, $y, $z), $block, false); + $blocks += 2; } } - $this->plugin->getLogger()->debug("Border Clear Task completed"); + if($blocks >= $this->maxBlocksPerTick){ + $this->setHandler(null); + $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); + throw new CancelTaskException(); + } + $this->plugin->getLogger()->debug("Border Clear Task completed at {$this->plot->X};{$this->plot->Z}"); } } \ No newline at end of file diff --git a/src/MyPlot/task/ClearPlotTask.php b/src/MyPlot/task/ClearPlotTask.php index dfb298f6..a44cc361 100644 --- a/src/MyPlot/task/ClearPlotTask.php +++ b/src/MyPlot/task/ClearPlotTask.php @@ -3,73 +3,39 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; -use pocketmine\block\Block; +use MyPlot\plot\BasePlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\VanillaBlocks; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\scheduler\CancelTaskException; use pocketmine\scheduler\Task; -use pocketmine\world\Position; use pocketmine\world\World; -class ClearPlotTask extends Task { - protected MyPlot $plugin; - protected Plot $plot; - protected World $level; - protected int $height; - protected Block $bottomBlock; - protected Block $plotFillBlock; - protected Block $plotFloorBlock; - protected Position $plotBeginPos; - protected int $xMax; - protected int $zMax; - protected int $maxBlocksPerTick; +class ClearPlotTask extends Task{ + protected AxisAlignedBB $aabb; + protected Vector3 $plotBeginPos; + protected PlotLevelSettings $plotLevel; protected Vector3 $pos; - protected ?AxisAlignedBB $plotBB; + protected World $world; - /** - * ClearPlotTask constructor. - * - * @param MyPlot $plugin - * @param Plot $plot - * @param int $maxBlocksPerTick - */ - public function __construct(MyPlot $plugin, Plot $plot, int $maxBlocksPerTick = 256) { - $this->plugin = $plugin; - $this->plot = $plot; - $plotLevel = $plugin->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize; - $this->height = $plotLevel->groundHeight; - $this->bottomBlock = $plotLevel->bottomBlock; - $this->plotFillBlock = $plotLevel->plotFillBlock; - $this->plotFloorBlock = $plotLevel->plotFloorBlock; - $this->maxBlocksPerTick = $maxBlocksPerTick; - - $this->plotBeginPos = $plugin->getPlotPosition($plot, false); - $this->xMax = (int)($this->plotBeginPos->x + $plotSize); - $this->zMax = (int)($this->plotBeginPos->z + $plotSize); - foreach ($plugin->getProvider()->getMergedPlots($plot) as $mergedPlot){ - $xplot = $plugin->getPlotPosition($mergedPlot, false)->x; - $zplot = $plugin->getPlotPosition($mergedPlot, false)->z; - $xMaxPlot = (int)($xplot + $plotSize); - $zMaxPlot = (int)($zplot + $plotSize); - if($this->plotBeginPos->x > $xplot) $this->plotBeginPos->x = $xplot; - if($this->plotBeginPos->z > $zplot) $this->plotBeginPos->z = $zplot; - if($this->xMax < $xMaxPlot) $this->xMax = $xMaxPlot; - if($this->zMax < $zMaxPlot) $this->zMax = $zMaxPlot; - } - $this->level = $this->plotBeginPos->getWorld(); - $this->pos = new Vector3($this->plotBeginPos->x, 0, $this->plotBeginPos->z); - $this->plotBB = $this->plugin->getPlotBB($plot); + public function __construct(private MyPlot $plugin, private BasePlot $plot, private int $maxBlocksPerTick = 256){ + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + $this->plotLevel = $plugin->getLevelSettings($plot->levelName); + $this->aabb = $aabb = $this->plugin->getPlotBB($plot); + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); $plugin->getLogger()->debug("Plot Clear Task started at plot $plot->X;$plot->Z"); } - public function onRun() : void { - foreach($this->level->getEntities() as $entity) { - if($this->plotBB->isVectorInXZ($entity->getPosition())) { - if(!$entity instanceof Player) { + public function onRun() : void{ + foreach($this->world->getEntities() as $entity){ + if($this->aabb->isVectorInXZ($entity->getPosition())){ + if(!$entity instanceof Player){ $entity->flagForDespawn(); }else{ $this->plugin->teleportPlayerToPlot($entity, $this->plot); @@ -77,40 +43,35 @@ public function onRun() : void { } } $blocks = 0; - while($this->pos->x < $this->xMax) { - while($this->pos->z < $this->zMax) { - while($this->pos->y < $this->level->getMaxY()) { - if($this->pos->y === 0) { - $block = $this->bottomBlock; - }elseif($this->pos->y < $this->height) { - $block = $this->plotFillBlock; - }elseif($this->pos->y === $this->height) { - $block = $this->plotFloorBlock; - }else{ + for(; $this->pos->x < $this->aabb->maxX; ++$this->pos->x, $this->pos->z = $this->aabb->minZ){ + for(; $this->pos->z < $this->aabb->maxZ; ++$this->pos->z, $this->pos->y = $this->aabb->minY){ + for(; $this->pos->y < $this->aabb->maxY; ++$this->pos->y){ + if($this->pos->y === $this->aabb->minY) + $block = $this->plotLevel->bottomBlock; + elseif($this->pos->y < $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFillBlock; + elseif($this->pos->y === $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFloorBlock; + else $block = VanillaBlocks::AIR(); - } - $this->level->setBlock($this->pos, $block, false); - $blocks++; - if($blocks >= $this->maxBlocksPerTick) { + $this->world->setBlock($this->pos, $block, false); + + if(++$blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); } - $this->pos->y++; } - $this->pos->y = 0; - $this->pos->z++; } - $this->pos->z = $this->plotBeginPos->z; - $this->pos->x++; } - - foreach($this->plugin->getPlotChunks($this->plot) as [$chunkX, $chunkZ, $chunk]) { - foreach($chunk->getTiles() as $tile) { - $tile->close(); - } + foreach($this->plugin->getPlotChunks($this->plot) as [$chunkX, $chunkZ, $chunk]){ + if($chunk === null) + continue; + foreach($chunk->getTiles() as $tile) + if($this->aabb->isVectorInXZ($tile->getPosition())) + $tile->close(); } - $this->plugin->getScheduler()->scheduleDelayedTask(new ClearBorderTask($this->plugin, $this->plot), 1); - $this->plugin->getLogger()->debug("Plot Clear task completed at {$this->plotBeginPos->x};{$this->plotBeginPos->z}"); + $this->plugin->getScheduler()->scheduleDelayedTask(new ClearBorderTask($this->plugin, $this->plot, $this->maxBlocksPerTick), 1); + $this->plugin->getLogger()->debug("Plot Clear Task completed at {$this->plot->X};{$this->plot->Z}"); } } \ No newline at end of file diff --git a/src/MyPlot/task/CornerCorrectionTask.php b/src/MyPlot/task/CornerCorrectionTask.php index a0a5f7bc..dd79af56 100644 --- a/src/MyPlot/task/CornerCorrectionTask.php +++ b/src/MyPlot/task/CornerCorrectionTask.php @@ -3,9 +3,10 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; -use pocketmine\block\Block; +use MyPlot\plot\BasePlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\VanillaBlocks; +use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; @@ -14,64 +15,53 @@ use pocketmine\world\World; class CornerCorrectionTask extends Task{ - - protected MyPlot $plugin; - protected Plot $start; - protected ?World $level; - protected int $height; - protected Block $plotWallBlock; - protected int $maxBlocksPerTick; - protected ?Vector3 $plotBeginPos; - protected int $xMax; - protected int $zMax; - protected int $direction; - protected Block $roadBlock; - protected Block $groundBlock; - protected Block $bottomBlock; + protected AxisAlignedBB $aabb; + protected Vector3 $plotBeginPos; + protected PlotLevelSettings $plotLevel; protected Vector3 $pos; + protected World $world; - public function __construct(MyPlot $plugin, Plot $start, Plot $end, int $cornerDirection, int $maxBlocksPerTick = 256) { - $this->plugin = $plugin; - $this->start = $start; - $this->plotBeginPos = $plugin->getPlotPosition($start, false); - $this->level = $this->plotBeginPos->getWorld(); - $this->maxBlocksPerTick = $maxBlocksPerTick; + public function __construct(private MyPlot $plugin, private BasePlot $start, private BasePlot $end, private int $cornerDirection, private int $maxBlocksPerTick = 256){ + if($start->isSame($end)) + throw new \Exception("Plot arguments cannot be the same plot or already be merged"); + if(abs($start->X - $end->X) !== 1 and abs($start->Z - $end->Z) !== 1) + throw new \Exception("Plot arguments must be adjacent plots"); - $plotLevel = $plugin->getLevelSettings($start->levelName); - $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $this->height = $plotLevel->groundHeight; - $this->plotWallBlock = $plotLevel->wallBlock; - $this->roadBlock = $plotLevel->plotFloorBlock; - $this->groundBlock = $plotLevel->plotFillBlock; - $this->bottomBlock = $plotLevel->bottomBlock; + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($start->levelName); + $this->plotLevel = $plugin->getLevelSettings($start->levelName); + $this->aabb = $aabb = null; + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); - if(($start->Z - $end->Z) === 1) { // North Z- - if($cornerDirection === Facing::EAST) { + if(($start->Z - $end->Z) === 1){ // North Z- + if($cornerDirection === Facing::EAST){ $this->plotBeginPos = $this->plotBeginPos->subtract(0, 0, $roadWidth); $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, 0); - }elseif($cornerDirection === Facing::WEST) { + }elseif($cornerDirection === Facing::WEST){ $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, $roadWidth); } - }elseif(($start->X - $end->X) === -1) { // East X+ - if($cornerDirection === Facing::NORTH) { + }elseif(($start->X - $end->X) === -1){ // East X+ + if($cornerDirection === Facing::NORTH){ $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, 0); $this->plotBeginPos = $this->plotBeginPos->subtract(0, 0, $roadWidth); - }elseif($cornerDirection === Facing::SOUTH) { + }elseif($cornerDirection === Facing::SOUTH){ $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, $plotSize); } - }elseif(($start->Z - $end->Z) === -1) { // South Z+ - if($cornerDirection === Facing::EAST) { + }elseif(($start->Z - $end->Z) === -1){ // South Z+ + if($cornerDirection === Facing::EAST){ $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, $plotSize); $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, 0); - }elseif($cornerDirection === Facing::WEST) { + }elseif($cornerDirection === Facing::WEST){ $this->plotBeginPos = $this->plotBeginPos->add(0, 0, $plotSize); $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, 0); } - }elseif(($start->X - $end->X) === 1) { // West X- - if($cornerDirection === Facing::NORTH) { + }elseif(($start->X - $end->X) === 1){ // West X- + if($cornerDirection === Facing::NORTH){ $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, $roadWidth); - }elseif($cornerDirection === Facing::SOUTH) { + }elseif($cornerDirection === Facing::SOUTH){ $this->plotBeginPos = $this->plotBeginPos->add(0, 0, $plotSize); $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, 0); } @@ -82,11 +72,11 @@ public function __construct(MyPlot $plugin, Plot $start, Plot $end, int $cornerD $plugin->getLogger()->debug("Corner Correction Task started between plots $start->X;$start->Z and $end->X;$end->Z"); } - public function onRun() : void { - foreach($this->level->getEntities() as $entity) { - if($entity->getPosition()->x > $this->pos->x - 1 and $entity->getPosition()->x < $this->xMax + 1) { - if($entity->getPosition()->z > $this->pos->z - 1 and $entity->getPosition()->z < $this->zMax + 1) { - if(!$entity instanceof Player) { + public function onRun() : void{ + foreach($this->level->getEntities() as $entity){ + if($entity->getPosition()->x > $this->pos->x - 1 and $entity->getPosition()->x < $this->xMax + 1){ + if($entity->getPosition()->z > $this->pos->z - 1 and $entity->getPosition()->z < $this->zMax + 1){ + if(!$entity instanceof Player){ $entity->flagForDespawn(); }else{ $this->plugin->teleportPlayerToPlot($entity, $this->start); @@ -95,9 +85,9 @@ public function onRun() : void { } } $blocks = 0; - while($this->pos->x < $this->xMax) { - while($this->pos->z < $this->zMax) { - while($this->pos->y < $this->level->getMaxY()) { + while($this->pos->x < $this->xMax){ + while($this->pos->z < $this->zMax){ + while($this->pos->y < $this->level->getMaxY()){ if($this->pos->y === 0) $block = $this->bottomBlock; elseif($this->pos->y < $this->height) @@ -110,7 +100,7 @@ public function onRun() : void { $this->pos->y++; $blocks++; - if($blocks >= $this->maxBlocksPerTick) { + if($blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); diff --git a/src/MyPlot/task/FillPlotTask.php b/src/MyPlot/task/FillPlotTask.php index 9bcb1e56..19a4236e 100644 --- a/src/MyPlot/task/FillPlotTask.php +++ b/src/MyPlot/task/FillPlotTask.php @@ -3,104 +3,77 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; +use MyPlot\plot\BasePlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\Block; use pocketmine\block\VanillaBlocks; +use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\scheduler\CancelTaskException; use pocketmine\scheduler\Task; -use pocketmine\world\Position; use pocketmine\world\World; -class FillPlotTask extends Task { - /** @var MyPlot $plugin */ - protected $plugin; - /** @var Plot $plot */ - protected $plot; - /** @var World|null $level */ - protected $level; - /** @var int $height */ - protected $height; - /** @var Block $fillBlock */ - protected $fillBlock; - /** @var Block $bottomBlock */ - protected $bottomBlock; - /** @var Position|null $plotBeginPos */ - protected $plotBeginPos; - /** @var int $xMax */ - protected $xMax; - /** @var int $zMax */ - protected $zMax; - /** @var int $maxBlocksPerTick */ - protected $maxBlocksPerTick; - /** @var Vector3 $pos */ - protected $pos; +class FillPlotTask extends Task{ + protected AxisAlignedBB $aabb; + protected Vector3 $plotBeginPos; + protected PlotLevelSettings $plotLevel; + protected Vector3 $pos; + protected World $world; - /** - * FillPlotTask constructor. - * - * @param MyPlot $plugin - * @param Plot $plot - * @param int $maxBlocksPerTick - */ - public function __construct(MyPlot $plugin, Plot $plot, Block $plotFillBlock, int $maxBlocksPerTick = 256) { - $this->plugin = $plugin; - $this->plot = $plot; - $this->plotBeginPos = $plugin->getPlotPosition($plot); - $this->level = $this->plotBeginPos->getWorld(); - $plotLevel = $plugin->getLevelSettings($plot->levelName); - $plotSize = $plotLevel->plotSize; - $this->xMax = (int)($this->plotBeginPos->x + $plotSize); - $this->zMax = (int)($this->plotBeginPos->z + $plotSize); - $this->height = $plotLevel->groundHeight; - $this->fillBlock = $plotFillBlock; - $this->bottomBlock = $plotLevel->bottomBlock; - $this->maxBlocksPerTick = $maxBlocksPerTick; - $this->pos = new Vector3($this->plotBeginPos->x, 0, $this->plotBeginPos->z); + public function __construct(private MyPlot $plugin, private BasePlot $plot, private Block $plotFillBlock, private int $maxBlocksPerTick = 256){ + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($plot->levelName); + $this->plotLevel = $plugin->getLevelSettings($plot->levelName); + $this->aabb = $aabb = $this->plugin->getPlotBB($plot); + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); $plugin->getLogger()->debug("Plot Fill Task started at plot $plot->X;$plot->Z"); } - public function onRun() : void { - foreach($this->level->getEntities() as $entity) { - if($this->plugin->getPlotBB($this->plot)->isVectorInXZ($entity->getPosition())) { - if(!$entity instanceof Player) { + public function onRun() : void{ + foreach($this->world->getEntities() as $entity){ + if($this->aabb->isVectorInXZ($entity->getPosition()) and + $entity->getPosition()->y <= $this->plotLevel->groundHeight + ){ + if(!$entity instanceof Player){ $entity->flagForDespawn(); - }else { + }else{ $this->plugin->teleportPlayerToPlot($entity, $this->plot); } } } $blocks = 0; - while($this->pos->x < $this->xMax) { - while($this->pos->z < $this->zMax) { - while($this->pos->y < $this->level->getMaxY()) { - if($this->pos->y === 0) { - $block = $this->bottomBlock; - }elseif($this->pos->y <= $this->height) { - $block = $this->fillBlock; - }else { + for(; $this->pos->x < $this->aabb->maxX; ++$this->pos->x, $this->pos->z = $this->aabb->minZ){ + for(; $this->pos->z < $this->aabb->maxZ; ++$this->pos->z, $this->pos->y = $this->aabb->minY){ + for(; $this->pos->y < $this->aabb->maxY; ++$this->pos->y){ + if($this->pos->y === $this->aabb->minY) + $block = $this->plotLevel->bottomBlock; + elseif($this->pos->y < $this->plotLevel->groundHeight) + $block = $this->plotFillBlock; + else $block = VanillaBlocks::AIR(); - } - $this->level->setBlock($this->pos, $block, false); - $blocks++; - if($blocks >= $this->maxBlocksPerTick) { + $this->world->setBlock($this->pos, $block, false); + + if(++$blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); } - $this->pos->y++; } - $this->pos->y = 0; - $this->pos->z++; } - $this->pos->z = $this->plotBeginPos->z; - $this->pos->x++; } - foreach($this->plugin->getPlotChunks($this->plot) as [$chunkX, $chunkZ, $chunk]) { - foreach($chunk->getTiles() as $tile) { - $tile->close(); - } + foreach($this->plugin->getPlotChunks($this->plot) as [$chunkX, $chunkZ, $chunk]){ + if($chunk === null) + continue; + foreach($chunk->getTiles() as $tile) + if($this->aabb->isVectorInXZ($tile->getPosition()) and + $tile->getPosition()->y <= $this->plotLevel->groundHeight + ){ + $tile->close(); + } } $this->plugin->getLogger()->debug("Plot Fill task completed at {$this->plotBeginPos->x};{$this->plotBeginPos->z}"); } diff --git a/src/MyPlot/task/RoadFillTask.php b/src/MyPlot/task/RoadFillTask.php index 1d4adde4..977f9304 100644 --- a/src/MyPlot/task/RoadFillTask.php +++ b/src/MyPlot/task/RoadFillTask.php @@ -3,121 +3,170 @@ namespace MyPlot\task; use MyPlot\MyPlot; -use MyPlot\Plot; -use pocketmine\block\Block; +use MyPlot\plot\MergedPlot; +use MyPlot\PlotLevelSettings; use pocketmine\block\VanillaBlocks; +use pocketmine\math\Axis; +use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\scheduler\CancelTaskException; use pocketmine\scheduler\Task; +use pocketmine\world\format\Chunk; use pocketmine\world\World; class RoadFillTask extends Task{ - protected MyPlot $plugin; - protected Plot $start; - protected Plot $end; - protected World $level; - protected int $height; - protected ?Vector3 $plotBeginPos; - protected int $xMax; - protected int $zMax; - protected Block $roadBlock; - protected Block $groundBlock; - protected Block $bottomBlock; - protected int $maxBlocksPerTick; - protected Vector3 $pos; - protected bool $fillCorner; - protected int $cornerDirection = -1; - - public function __construct(MyPlot $plugin, Plot $start, Plot $end, bool $fillCorner = false, int $cornerDirection = -1, int $maxBlocksPerTick = 256) { - if($start->isSame($end)) - throw new \Exception("Plot arguments cannot be the same plot or already be merged"); + public const LOW_BORDER = 0; + public const HIGH_BORDER = 1; + public const BOTH_BORDERS = 2; - $this->plugin = $plugin; - $this->start = $start; - $this->end = $end; - $this->fillCorner = $fillCorner; - $this->cornerDirection = $cornerDirection === -1 ? -1 : Facing::opposite($cornerDirection); - - $this->plotBeginPos = $plugin->getPlotPosition($start, false); - $this->level = $this->plotBeginPos->getWorld(); + protected AxisAlignedBB $aabb; + protected Vector3 $plotBeginPos; + protected PlotLevelSettings $plotLevel; + protected Vector3 $pos; + protected World $world; - $plotLevel = $plugin->getLevelSettings($start->levelName); + public function __construct(private MyPlot $plugin, private MergedPlot $start, private int $direction, private int $handleBorder = self::BOTH_BORDERS, private int $maxBlocksPerTick = 256){ + $this->world = $this->plugin->getServer()->getWorldManager()->getWorldByName($start->levelName); + $this->plotLevel = $plotLevel = $plugin->getLevelSettings($start->levelName); $plotSize = $plotLevel->plotSize; - $roadWidth = $plotLevel->roadWidth; - $this->height = $plotLevel->groundHeight; - $this->roadBlock = $plotLevel->plotFloorBlock; - $this->groundBlock = $plotLevel->plotFillBlock; - $this->bottomBlock = $plotLevel->bottomBlock; - - if(($start->Z - $end->Z) === 1){ // North Z- - $this->plotBeginPos = $this->plotBeginPos->subtract(0, 0, $roadWidth); - $this->xMax = (int) ($this->plotBeginPos->x + $plotSize); - $this->zMax = (int) ($this->plotBeginPos->z + $roadWidth); - }elseif(($start->X - $end->X) === -1){ // East X+ - $this->plotBeginPos = $this->plotBeginPos->add($plotSize, 0, 0); - $this->xMax = (int) ($this->plotBeginPos->x + $roadWidth); - $this->zMax = (int) ($this->plotBeginPos->z + $plotSize); - }elseif(($start->Z - $end->Z) === -1){ // South Z+ - $this->plotBeginPos = $this->plotBeginPos->add(0, 0, $plotSize); - $this->xMax = (int) ($this->plotBeginPos->x + $plotSize); - $this->zMax = (int) ($this->plotBeginPos->z + $roadWidth); - }elseif(($start->X - $end->X) === 1){ // West X- - $this->plotBeginPos = $this->plotBeginPos->subtract($roadWidth, 0, 0); - $this->xMax = (int) ($this->plotBeginPos->x + $roadWidth); - $this->zMax = (int) ($this->plotBeginPos->z + $plotSize); - } - - $this->maxBlocksPerTick = $maxBlocksPerTick; - $this->pos = new Vector3($this->plotBeginPos->x, 0, $this->plotBeginPos->z); + $totalSize = $plotSize + $plotLevel->roadWidth; + $aabb = $plugin->getPlotBB($start); + $this->aabb = $aabb = match ($direction) { + Facing::NORTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->minZ - $plotLevel->roadWidth, + $aabb->maxX, + $aabb->maxY, + $aabb->minZ + ), + Facing::EAST => new AxisAlignedBB( + $aabb->maxX + ($totalSize * ($this->start->xWidth - 1)), + $aabb->minY, + $aabb->minZ, + $aabb->maxX + ($totalSize * ($this->start->xWidth - 1)) + $plotLevel->roadWidth, + $aabb->maxY, + $aabb->maxZ + ), + Facing::SOUTH => new AxisAlignedBB( + $aabb->minX, + $aabb->minY, + $aabb->maxZ + ($totalSize * ($this->start->zWidth - 1)), + $aabb->maxX, + $aabb->maxY, + $aabb->maxZ + ($totalSize * ($this->start->zWidth - 1)) + $plotLevel->roadWidth + ), + Facing::WEST => new AxisAlignedBB( + $aabb->minX - $plotLevel->roadWidth, + $aabb->minY, + $aabb->minZ, + $aabb->minX, + $aabb->maxY, + $aabb->maxZ + ), + default => throw new \InvalidArgumentException("Invalid direction $direction") + }; + $this->plotBeginPos = $this->pos = new Vector3( + $aabb->minX, + $aabb->minY, + $aabb->minZ + ); - $plugin->getLogger()->debug("Road Clear Task started between plots $start->X;$start->Z and $end->X;$end->Z"); + $plugin->getLogger()->debug("Road Clear Task started between plots $start->X;$start->Z facing" . Facing::toString($direction)); } - public function onRun() : void { - foreach($this->level->getEntities() as $entity) { - if($entity->getPosition()->x > $this->pos->x - 1 and $entity->getPosition()->x < $this->xMax + 1) { - if($entity->getPosition()->z > $this->pos->z - 1 and $entity->getPosition()->z < $this->zMax + 1) { - if(!$entity instanceof Player){ - $entity->flagForDespawn(); - }else{ - $this->plugin->teleportPlayerToPlot($entity, $this->start); - } + public function onRun() : void{ + foreach($this->world->getEntities() as $entity){ + if($this->aabb->isVectorInXZ($entity->getPosition())){ + if(!$entity instanceof Player){ + $entity->flagForDespawn(); + }else{ + $this->plugin->teleportPlayerToPlot($entity, $this->start); } } } $blocks = 0; - while($this->pos->x < $this->xMax) { - while($this->pos->z < $this->zMax) { - while($this->pos->y < $this->level->getMaxY()) { - if($this->pos->y === 0) - $block = $this->bottomBlock; - elseif($this->pos->y < $this->height) - $block = $this->groundBlock; - elseif($this->pos->y === $this->height) - $block = $this->roadBlock; + for(; $this->pos->x < $this->aabb->maxX; ++$this->pos->x, $this->pos->z = $this->aabb->minZ){ + for(; $this->pos->z < $this->aabb->maxZ; ++$this->pos->z, $this->pos->y = $this->aabb->minY){ + for(; $this->pos->y < $this->aabb->maxY; ++$this->pos->y){ + if($this->pos->y === $this->aabb->minY) + $block = $this->plotLevel->bottomBlock; + elseif($this->pos->y < $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFillBlock; + elseif($this->pos->y === $this->plotLevel->groundHeight) + $block = $this->plotLevel->plotFloorBlock; + elseif($this->pos->y === $this->plotLevel->groundHeight + 1 and + ( + ( + Facing::axis($this->direction) === Axis::X and + ( + ( + ( + $this->handleBorder === self::LOW_BORDER or + $this->handleBorder === self::BOTH_BORDERS + ) and + $this->pos->z === $this->aabb->maxZ + ) or ( + ( + $this->handleBorder === self::HIGH_BORDER or + $this->handleBorder === self::BOTH_BORDERS + ) and + $this->pos->z === $this->aabb->minZ + ) + ) + ) or ( + Facing::axis($this->direction) === Axis::Z and + ( + ( + ( + $this->handleBorder === self::LOW_BORDER or + $this->handleBorder === self::BOTH_BORDERS + ) and + $this->pos->x === $this->aabb->maxX + ) or ( + ( + $this->handleBorder === self::HIGH_BORDER or + $this->handleBorder === self::BOTH_BORDERS + ) and + $this->pos->x === $this->aabb->minX + ) + ) + ) + ) + ) + $block = $this->plotLevel->wallBlock; else $block = VanillaBlocks::AIR(); + $this->world->setBlock($this->pos, $block, false); - $this->level->setBlock($this->pos, $block, false); - $this->pos->y++; - - $blocks++; - if($blocks >= $this->maxBlocksPerTick) { + if(++$blocks >= $this->maxBlocksPerTick){ $this->setHandler(null); $this->plugin->getScheduler()->scheduleDelayedTask($this, 1); throw new CancelTaskException(); } } - $this->pos->y = 0; - $this->pos->z++; } - $this->pos->z = $this->plotBeginPos->z; - $this->pos->x++; } - $this->plugin->getLogger()->debug("Plot Road Clear task completed at {$this->start->X};{$this->start->Z}"); - $this->plugin->getScheduler()->scheduleTask(new BorderCorrectionTask($this->plugin, $this->start, $this->end, $this->fillCorner, $this->cornerDirection)); + $aabb = $this->aabb; + $xMin = $aabb->minX >> Chunk::COORD_MASK; + $zMin = $aabb->minZ >> Chunk::COORD_MASK; + $xMax = $aabb->maxX >> Chunk::COORD_MASK; + $zMax = $aabb->maxZ >> Chunk::COORD_MASK; + + $level = $this->plugin->getServer()->getWorldManager()->getWorldByName($this->start->levelName); + for($x = $xMin; $x <= $xMax; ++$x){ + for($z = $zMin; $z <= $zMax; ++$z){ + $chunk = $level->getChunk($x, $z); + if($chunk === null) + continue; + foreach($chunk->getTiles() as $tile) + if($aabb->isVectorInXZ($tile->getPosition())) + $tile->close(); + } + } + $this->plugin->getLogger()->debug("Plot Road Clear task completed at {$this->start->X};{$this->start->Z}"); } } \ No newline at end of file diff --git a/src/MyPlot/utils/AsyncVariants.php b/src/MyPlot/utils/AsyncVariants.php new file mode 100644 index 00000000..585634ed --- /dev/null +++ b/src/MyPlot/utils/AsyncVariants.php @@ -0,0 +1,13 @@ + $value){ + $result[$key] = $callback === null ? $value : yield from $callback($value, $key); + } + return $result; + } +} \ No newline at end of file diff --git a/src/MyPlot/utils/Utils.php b/src/MyPlot/utils/Utils.php new file mode 100644 index 00000000..6bd62729 --- /dev/null +++ b/src/MyPlot/utils/Utils.php @@ -0,0 +1,24 @@ +maxX - $alignedBB->minX; + $height = $alignedBB->maxY - $alignedBB->minY; + $length = $alignedBB->maxZ - $alignedBB->minZ; + if($width <= 0 or $length <= 0 or $height <= 0) + throw new \InvalidArgumentException("AxisAlignedBB cannot have a width, length, or height of 0"); + + return match ($axis) { + Axis::X => new AxisAlignedBB(0, 0, 0, $width, $length, $height), + Axis::Y => new AxisAlignedBB(0, 0, 0, $length, $height, $width), + Axis::Z => new AxisAlignedBB(0, 0, 0, $height, $width, $length), + default => throw new \InvalidArgumentException("Invalid axis $axis") + }; + } +} \ No newline at end of file