· 6 years ago · Sep 22, 2019, 02:56 PM
1<?php
2
3namespace Chalapa13\WorldGuard;
4
5use pocketmine\plugin\PluginBase;
6use pocketmine\command\{Command, CommandSender};
7use pocketmine\utils\TextFormat as TF;
8use pocketmine\Player;
9use pocketmine\level\Position;
10use pocketmine\permission\{Permission, Permissible, PermissionManager};
11use pocketmine\network\mcpe\protocol\SetTimePacket;
12use pocketmine\Server;
13
14class WorldGuard extends PluginBase {
15
16 const FLAGS = [
17 "pvp" => "true",
18 "effects" => [],
19 "blocked-cmds" => [],
20 "allowed-cmds" => [],
21 "use" => "false",
22 "item-drop" => "true",
23 "explosion" => "false",
24 "notify-enter" => "",
25 "notify-leave" => "",
26 "potions" => "true",
27 "allowed-enter" => "true",
28 "allowed-leave" => "true",
29 "game-mode" => 0,
30 "sleep" => "true",
31 "send-chat" => "true",
32 "receive-chat" => "true",
33 "enderpearl" => "true",
34 "fly-mode" => 0,
35 "eat" => "true",
36 "allow-damage-animals" => "true",
37 "allow-damage-monsters" => "true",
38 "allow-leaves-decay" => "true",
39 "allow-plant-growth" => "true",
40 "allow-spreading" => "true",
41 "allow-block-burn" => "true",
42 "priority" => 0,
43 ];
44
45 const FLAG_TYPE = [
46 "pvp" => "boolean",
47 "effects" => "array",
48 "blocked-cmds" => "array",
49 "allowed-cmds" => "array",
50 "use" => "boolean",
51 "item-drop" => "boolean",
52 "explosion" => "boolean",
53 "notify-enter" => "string",
54 "notify-leave" => "string",
55 "potions" => "boolean",
56 "allowed-enter" => "boolean",
57 "allowed-leave" => "boolean",
58 "game-mode" => "integer",
59 "sleep" => "boolean",
60 "send-chat" => "boolean",
61 "receive-chat" => "boolean",
62 "enderpearl" => "boolean",
63 "fly-mode" => "integer",
64 "eat" => "boolean",
65 "allow-damage-animals" => "boolean",
66 "allow-damage-monsters" => "boolean",
67 "allow-leaves-decay" => "boolean",
68 "allow-plant-growth" => "boolean",
69 "allow-spreading" => "boolean",
70 "allow-block-burn" => "boolean",
71 "priority" => "integer",
72 ];
73
74 const FLY_VANILLA = 0;
75 const FLY_ENABLE = 1;
76 const FLY_DISABLE = 2;
77 const FLY_SUPERVISED = 3;
78
79 public $creating = [];
80 private $process = [];
81 private $regions = [];
82 private $players = [];
83 public $muted = [];
84
85 /** TO-DO:
86 * Finish adding default messages to this array
87 * save them to messages.yml
88 * load them and use the modified messages instead of the hardcoded ones
89 */
90 public $messages = [];
91 public function onEnable()
92 {
93 if (!is_dir($path = $this->getDataFolder())) {
94 mkdir($path);
95 }
96
97 /**
98 * load regions if file exists and if not create a file
99 */
100 if (is_file($path.'regions.yml')) {
101 $regions = yaml_parse_file($path.'regions.yml');
102 } else {
103 yaml_emit_file($path.'regions.yml', []);
104 }
105
106 /**
107 * load messages if file exists and if not write the default ones
108 */
109 if(is_file($path.'messages.yml'))
110 {
111 $this->messages = yaml_parse_file($path.'messages.yml');
112 }
113 else{
114 $this->messages = array([
115 "denied-enter" => "You cannot enter this area.",
116 "denied-leave" => "You cannot leave this area.",
117 "no-permission-for-command" => "You do not have permission to use this command.",
118 "denied-eat" => "You cannot eat in this area.",
119 "denied-ender-pearls" => "You cannot use ender pearls in this area.",
120 "denied-chat" => "You cannot chat in this region.",
121 "denied-item-drop" => "You cannot drop items in this region.",
122 "denied-pvp" => "You cannot hurt players of this region.",
123 "denied-block-break" => "You cannot break blocks in this region.",
124 "denied-block-place" => "You cannot place blocks in this region.",
125 "denied-hurt-animal" => "You cannot hurt animals of this region.",
126 "denied-hurt-monster" => "You cannot hurt monsters of this region."
127 ]);
128
129 yaml_emit_file($path.'messages.yml', $this->messages);
130 }
131
132 if (isset($regions)) {
133 foreach ($regions as $name => $data) {
134 $this->regions[$name] = new Region($name, $data["pos1"], $data["pos2"], $data["level"], $data["flags"]);
135 }
136 }
137
138 $this->getServer()->getPluginManager()->registerEvents(new EventListener($this), $this);
139 }
140
141 public function onDisable()
142 {
143 $data = [];
144 foreach ($this->regions as $name => $region) {
145 $data[$name] = $region->toArray();
146 }
147 yaml_emit_file($this->getDataFolder().'regions.yml', $data);
148 }
149 public function nofly(Player $player, $mode) {
150 $this->getServer()->getPluginManager()->callEvent($ev = new PlayerFlyModeChangeEvent($this, $player, $mode));
151 if($ev->isCancelled()){
152 return false;
153 } else {
154 return true;
155 }
156 }
157
158 public function getRegion(string $region)
159 {
160 return $this->regions[$region] ?? "";
161 }
162
163 public function getRegionByPlayer(Player $player)
164 {
165 $reg = $this->getRegionOf($player);
166 return $reg !== "" ? $this->getRegion($reg) : "";
167 }
168
169 public function getRegionOf(Player $player): string
170 {
171 return $this->players[$player->getRawUniqueId()] ?? "";
172 }
173
174 public function regionExists(string $name) : bool
175 {
176 return isset($this->regions[$name]);
177 }
178
179 public function flagExists(string $flag) : bool
180 {
181 return isset(self::FLAGS[$flag]);
182 }
183
184 public function sessionizePlayer(Player $player)
185 {
186 foreach ($player->getEffects() as $effect) {
187 if ($effect->getDuration() >= 999999) {
188 $player->removeEffect($effect->getId());
189 }
190 }
191 $this->players[$player->getRawUniqueId()] = "";
192 $this->updateRegion($player);
193 }
194
195 public function getRegionFromPosition(Position $pos)
196 {
197 $name = $this->getRegionNameFromPosition($pos);
198 return $name !== "" ? $this->getRegion($name) : "";
199 }
200
201 public function getRegionNameFromPosition(Position $pos) : string
202 {
203 $highestPriorityName = "";
204 $highestPriority = -1;
205
206 foreach ($this->regions as $name => $region) {
207 if ($region->getLevelName() === $pos->getLevel()->getName()) {
208 $reg1 = $region->getPos1();
209 $reg2 = $region->getPos2();
210 $x = array_flip(range($reg1[0], $reg2[0]));
211 if (isset($x[$pos->x])) {
212 $y = array_flip(range($reg1[1], $reg2[1]));
213 if (isset($y[$pos->y])) {
214 $z = array_flip(range($reg1[2], $reg2[2]));
215 if (isset($z[$pos->z])) {
216 if($highestPriority<intval($region->getFlag("priority")))
217 {
218 $highestPriority = intval($region->getFlag("priority"));
219 $highestPriorityName = $name;
220 }
221 }
222 }
223 }
224 }
225 }
226 return $highestPriorityName;
227 }
228
229 public function onRegionChange(Player $player, string $oldregion, string $newregion)
230 {
231 $new = $this->getRegion($newregion);
232 $old = $this->getRegion($oldregion);
233
234 if ($old !== "") {
235 if ($old->getFlag("allowed-leave") === "false")
236 {
237 if(!$player->hasPermission("worldguard.leave." . $oldregion))
238 {
239 $player->sendMessage(TF::RED. $this->messages["denied-leave"]);
240 return false;
241 }
242 }
243 if (($msg = $old->getFlag("notify-leave")) !== "") {
244 $player->sendMessage(Utils::aliasParse($player, $msg));
245 }
246 if ($old->getFlag("receive-chat") === "false") {
247 unset($this->muted[$player->getRawUniqueId()]);
248 }
249 foreach ($player->getEffects() as $effect) {
250 if ($effect->getDuration() >= 999999) {
251 $player->removeEffect($effect->getId());
252 }
253 }
254 if ($old->getFlight() === self::FLY_SUPERVISED) {
255 Utils::disableFlight($player);
256 }
257 if ($old->getGamemode() !== ($gm = $this->getServer()->getDefaultGamemode())) {
258 $player->setGamemode($gm);
259 if ($gm === 0 || $gm === 2) Utils::disableFlight($player);
260 }
261 }
262
263 if ($new !== "") {
264 if ($new->getFlag("allowed-enter") === "false")
265 {
266 if(!$player->hasPermission("worldguard.enter." . $newregion))
267 {
268 $player->sendMessage(TF::RED. $this->messages["denied-enter"]);
269 return false;
270 }
271 }
272 if (($gm = $new->getGamemode()) !== $player->getGamemode()) {
273 $player->setGamemode($gm);
274 if ($gm === 0 || $gm === 2) Utils::disableFlight($player);
275 }
276 if (($msg = $new->getFlag("notify-enter")) !== "") {
277 $player->sendMessage(Utils::aliasParse($player, $msg));
278 }
279 if ($new->getFlag("receive-chat") === "false") {
280 $this->muted[$player->getRawUniqueId()] = $player;
281 }
282 if (($flight = $new->getFlight()) !== self::FLY_VANILLA) {
283 switch ($flight) {
284 case self::FLY_ENABLE:
285 case self::FLY_SUPERVISED:
286 if (!$player->getAllowFlight()) {
287 $player->setAllowFlight(true);
288 }
289 break;
290 case self::FLY_DISABLE:
291 if (!$player-->nofly()) {
292 Utils::disableFlight($player);
293 }
294 break;
295 }
296 }
297 $effects = $new->getEffects();
298 if (!empty($effects)) {
299 $player->removeAllEffects();
300 foreach ($effects as $effect) {
301 $player->addEffect($effect);
302 }
303 }
304 }
305
306 /*
307 if($new !== "")
308 {
309 if(($time = $new->getFlag("freeze-time")) !== -1 )
310 {
311 $pk = new SetTimePacket();
312 $pk->time = intval($time);
313 $player->dataPacket($pk);
314 }
315 else
316 {
317 $pk = new SetTimePacket();
318 $pk->time = intval($this->getServer()->getTick());
319 $player->dataPacket($pk);
320 }
321 }
322 else
323 {
324 $pk = new SetTimePacket();
325 $pk->time = intval($this->getServer()->getTick());
326 $player->dataPacket($pk);
327 }
328 */
329
330 return true;
331 }
332
333 public function updateRegion(Player $player)
334 {
335 $region = $this->players[$id = $player->getRawUniqueId()];
336 if (($newRegion = $this->getRegionNameFromPosition($player->getPosition())) !== $region) {
337 $this->players[$id] = $newRegion;
338 return $this->onRegionChange($player, $region, $newRegion);
339 }
340 return true;
341 }
342
343 public function processCreation(Player $player)
344 {
345 if (isset($this->creating[$id = $player->getRawUniqueId()], $this->process[$id])) {
346 $name = $this->process[$id];
347 $map = $this->creating[$id];
348 $level = $map[0][3];
349 unset($map[0][3], $map[1][3]);
350 $this->regions[$name] = new Region($name, $map[0], $map[1], $level, self::FLAGS);
351 unset($this->process[$id], $this->creating[$id]);
352
353 /* add permission for accesing this region */
354 $permission = new Permission("worldguard.enter." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
355 $permission->addParent("worldguard.enter", true);
356 PermissionManager::getInstance()->addPermission($permission);
357
358 /* add permission for leaving this region */
359 $permission = new Permission("worldguard.leave." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
360 $permission->addParent("worldguard.leave", true);
361 PermissionManager::getInstance()->addPermission($permission);
362
363 /* add permission for building in this region */
364 $permission = new Permission("worldguard.build." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
365 $permission->addParent("worldguard.build", true);
366 PermissionManager::getInstance()->addPermission($permission);
367
368 /* add permission for breaking blocks in this region */
369 $permission = new Permission("worldguard.break." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
370 $permission->addParent("worldguard.break", true);
371 PermissionManager::getInstance()->addPermission($permission);
372
373 /* add permission for editing blocks in this region */
374 $permission = new Permission("worldguard.edit." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
375 $permission->addParent("worldguard.edit", true);
376 PermissionManager::getInstance()->addPermission($permission);
377
378 /* add permission for eating in this region */
379 $permission = new Permission("worldguard.eat." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
380 $permission->addParent("worldguard.eat", true);
381 PermissionManager::getInstance()->addPermission($permission);
382
383 /* add permission for dropping items in this region */
384 $permission = new Permission("worldguard.drop." . $name, "Allows player to enter the " . $name . " region.", Permission::DEFAULT_OP);
385 $permission->addParent("worldguard.drop", true);
386 PermissionManager::getInstance()->addPermission($permission);
387
388 /* add permission for using chests in this region */
389 $permission = new Permission("worldguard.usechest." . $name, "Allows player to use chests in " . $name . " region.", Permission::DEFAULT_OP);
390 $permission->addParent("worldguard.usechest", true);
391 PermissionManager::getInstance()->addPermission($permission);
392
393 $permission = new Permission("worldguard.usechestender." . $name, "Allows player to use ender chests in " . $name . " region.", Permission::DEFAULT_OP);
394 $permission->addParent("worldguard.usechestender", true);
395 PermissionManager::getInstance()->addPermission($permission);
396
397 /* add permission for using enchanting tables in this region */
398 $permission = new Permission("worldguard.enchantingtable." . $name, "Allows player to use enchanting table in " . $name . " region.", Permission::DEFAULT_OP);
399 $permission->addParent("worldguard.enchantingtable", true);
400 PermissionManager::getInstance()->addPermission($permission);
401
402 /* add permission for using doors in this region */
403 $permission = new Permission("worldguard.usedoors." . $name, "Allows player to use doors in " . $name . " region.", Permission::DEFAULT_OP);
404 $permission->addParent("worldguard.usedoors", true);
405 PermissionManager::getInstance()->addPermission($permission);
406
407 /* add permission for using trapdoors in this region */
408 $permission = new Permission("worldguard.usetrapdoors." . $name, "Allows player to use trapdoors in " . $name . " region.", Permission::DEFAULT_OP);
409 $permission->addParent("worldguard.usetrapdoors", true);
410 PermissionManager::getInstance()->addPermission($permission);
411
412 /* add permission for using gates in this region */
413 $permission = new Permission("worldguard.usegates." . $name, "Allows player to use gates in " . $name . " region.", Permission::DEFAULT_OP);
414 $permission->addParent("worldguard.usegates", true);
415 PermissionManager::getInstance()->addPermission($permission);
416
417 /* add permission for using furnaces in this region */
418 $permission = new Permission("worldguard.usefurnaces." . $name, "Allows player to use furnaces in " . $name . " region.", Permission::DEFAULT_OP);
419 $permission->addParent("worldguard.usefurnaces", true);
420 PermissionManager::getInstance()->addPermission($permission);
421
422 /* add permission for using anvils in this region */
423 $permission = new Permission("worldguard.useanvil." . $name, "Allows player to use anvils in " . $name . " region.", Permission::DEFAULT_OP);
424 $permission->addParent("worldguard.useanvil", true);
425 PermissionManager::getInstance()->addPermission($permission);
426
427 return $name;
428 }
429 return false;
430 }
431
432 public function onCommand(CommandSender $issuer, Command $cmd, string $label, array $args): bool
433 {
434 switch (strtolower($cmd->getName())) {
435 case "region":
436 if (!$issuer->hasPermission("worldguard.create") || !$issuer->hasPermission("worldguard.modify") || !$issuer->hasPermission("worldguard.delete")) {
437 $issuer->sendMessage($this->messages["no-permission-for-command"]);
438 return false;
439 }
440 if (isset($args[0])) {
441 switch ($args[0]) {
442 case "create":
443 if (!$issuer->hasPermission("worldguard.create")) {
444 $issuer->sendMessage($this->messages["no-permission-for-command"]);
445 return false;
446 }
447 if (isset($args[1])) {
448 if (!ctype_alnum($args[1])) {
449 $issuer->sendMessage(TF::RED.'Region name must be alpha numeric.');
450 return false;
451 }
452 if ($this->regionExists($args[1])) {
453 $issuer->sendMessage(TF::RED.'This region already exists. Redefine it using /region redefine '.$args[1].', or remove it using /region remove '.$args[1]);
454 return false;
455 } else {
456 unset($this->creating[$id = $issuer->getRawUniqueId()], $this->process[$id]);
457 $this->creating[$id] = [];
458 $this->process[$id]= $args[1];
459 $issuer->sendMessage(TF::LIGHT_PURPLE.'Right-Click two positions to complete creating your region ('.$args[1].').');
460 }
461 } else {
462 $issuer->sendMessage(TF::RED.'/region create <name>');
463 }
464 break;
465 case "delete":
466 if (!$issuer->hasPermission("worldguard.delete")) {
467 $issuer->sendMessage($this->messages["no-permission-for-command"]);
468 return false;
469 }
470 if (isset($args[1])) {
471 if (!ctype_alnum($args[1])) {
472 $issuer->sendMessage(TF::RED.'Region name must be alpha numeric.');
473 return false;
474 }
475 if ($this->regionExists($args[1])) {
476 unset($this->regions[$args[1]]);
477 foreach ($this->getServer()->getOnlinePlayers() as $player) {
478 $this->updateRegion($player);
479 }
480 $issuer->sendMessage(TF::YELLOW.'You have deleted the region: '.$args[1]);
481 } else {
482 $issuer->sendMessage(TF::RED.$args[1].' region does not exist. Use /region list to get a list of all regions.');
483 }
484 } else {
485 $issuer->sendMessage(TF::RED.'/region delete <name>');
486 }
487 break;
488 case "list":
489 $msg = TF::LIGHT_PURPLE."Regions: \n".TF::LIGHT_PURPLE;
490 if (empty($this->regions)) {
491 $msg .= "You haven't created any regions yet. Use /region create <name> to create your first region.";
492 } else {
493 $msg .= implode(TF::WHITE.', '.TF::LIGHT_PURPLE, array_keys($this->regions));
494 }
495 $issuer->sendMessage($msg);
496 break;
497 case "redefine":
498 if (!isset($args[1])) {
499 $issuer->sendMessage(TF::RED.'/region redefine <region>');
500 return false;
501 }
502 else{
503 if (!$this->regionExists($args[1])) {
504 $issuer->sendMessage(TF::RED.$args[1].' region does not exist. Use /region list to get a list of all regions.');
505 return false;
506 }
507 else {
508 unset($this->creating[$id = $issuer->getRawUniqueId()], $this->process[$id]);
509 $this->creating[$id] = [];
510 $this->process[$id]= $args[1];
511 $issuer->sendMessage(TF::LIGHT_PURPLE.'Right-Click two positions to redefine your region ('.$args[1].').');
512 }
513 }
514 break;
515 case "getplayer":
516 if (isset($args[1])) {
517 if (($player = $this->getServer()->getPlayerExact($args[1])) !== null) {
518 $reg = $this->getRegionOf($player);
519 if ($reg !== "") {
520 $issuer->sendMessage(TF::YELLOW.$player->getName().' is in '.$reg.'.');
521 } else {
522 $issuer->sendMessage(TF::YELLOW.$player->getName().'is not in any region.');
523 }
524 } else {
525 $issuer->sendMessage(TF::RED.$args[1].' is offline.');
526 }
527 } else {
528 $issuer->sendMessage(TF::RED.'/region getplayer <player>');
529 }
530 break;
531 case "flag":
532 case "flags":
533 if (!$issuer->hasPermission("worldguard.modify")) {
534 $issuer->sendMessage($this->messages["no-permission-for-command"]);
535 return false;
536 }
537 if (isset($args[1], $args[2])) {
538 if (!$this->regionExists($args[2])) {
539 $issuer->sendMessage(TF::RED.'The specified region does not exist. Use /region list to get a list of all regions.');
540 return false;
541 }
542 if ($args[1] !== "get") {
543 if (!isset($args[3])) {
544 $issuer->sendMessage(TF::RED."You haven't specified the <flag>.");
545 return false;
546 } elseif (!$this->flagExists($args[3])) {
547 $issuer->sendMessage(TF::RED."The specified flag does not exist. Available flags:\n".TF::LIGHT_PURPLE.implode(TF::WHITE.', '.TF::LIGHT_PURPLE, array_keys(self::FLAGS)));
548 return false;
549 }
550 }
551 switch ($args[1]) {
552 case "get":
553 $flags = $this->getRegion($args[2])->getFlagsString();
554 $issuer->sendMessage(TF::LIGHT_PURPLE.$args[2]."'s flags:\n".$flags);
555 break;
556 case "set":
557 if (!isset($args[4])) {
558 $issuer->sendMessage(TF::RED.'You must specify the <value> of the flag.');
559 return false;
560 }
561 $val = $args;
562 unset($val[0], $val[1], $val[2], $val[3]);
563 $opt = $this->getRegion($args[2])->setFlag($args[3], array_values($val));
564 if ($opt !== null) {
565 $issuer->sendMessage($opt);
566 } else {
567 $issuer->sendMessage(TF::YELLOW.'Flag has been updated successfully.');
568 }
569 break;
570 case "reset":
571 $this->getRegion($args[2])->resetFlag($args[3]);
572 break;
573 }
574 } else {
575 $issuer->sendMessage(TF::RED."/region flags <get/set/reset> <region> <flag> <value>\n".TF::GRAY.'<value> argument is only needed if you are setting the flag.');
576 }
577 break;
578 }
579 } else {
580 $issuer->sendMessage(implode("\n".TF::LIGHT_PURPLE, [
581 "WorldGuard (by Chalapa) Help Page",
582 " ",
583 " ",
584 "/region create <name> - Define a new region.",
585 "/region list - List all regions.",
586 "/region flags get <region> - Get <region>'s flags.",
587 "/region flags reset <region> <flag> - Reset <region>'s <flag> to default.",
588 "/region flags set <region> <flag> <value> - Modify <value> of the <region>'s flag.",
589 ]));
590 }
591 break;
592 }
593 return true;
594 }
595}