Quickly make team deathmatch plugin with PMMP

Aug 24, 2020 PHP PMMP

#Foreword I will make a team death match quickly using the library The plugins you create should not interfere with any other plugins

Completed is here

Contents of the plugin to be created

Create a game with /create and join with /join The score increases with each kill, and when the set upper limit is reached or the time limit is exceeded, the game is over Display timer on BossBar and match status on Scoreboard

#Install library The library used is team_game_system

with the dependency of team_game_system form_builder slot_menu_system will also be introduced.

Use scoreboard_system in scoreboard API Use bossbar_system in the bossbar API

Go to the plugins folder at the command prompt

git clone https://github.com/MineDeepRock/team_game_system
git clone https://github.com/MineDeepRock/form_builder
git clone https://github.com/MineDeepRock/slot_menu_system
git clone https://github.com/MineDeepRock/scoreboard_system
git clone https://github.com/MineDeepRock/bossbar_system

This is OK

#Create project Create a folder called TeamDeathMatch.

name: TeamDeathMatch
main: TeamDeathMatch\Main
version: 1.0.0
api: 3.0.0

depend:
  -TeamGameSystem
  -FormBuilder
  -SlotMenuSystem

Completion with # Composer Please see only those who want to complement with Composer

{
  "name": "Your name/TeamDeathMatch",
  "authors": [
    {
      "name": "your name"
    }
  ],
  "autoload": {
    "psr-4": {
      "": [
        "src/"
      ]
    }
  },
  "repositories": [
    {
      "type": "git",
      "name": "suinua/form_builder",
      "url": "https://github.com/MineDeepRock/form_builder"
    },
    {
      "type": "git",
      "name": "suinua/slot_menu_system",
      "url": "https://github.com/MineDeepRock/slot_menu_system"
    },
    {
      "type": "git",
      "name": "suinua/scoreboard_system",
      "url": "https://github.com/MineDeepRock/scoreboard_system"
    },
    {
      "type": "git",
      "name": "suinua/bossbar_system",
      "url": "https://github.com/MineDeepRock/bossbar_system"
    },
    {
      "type": "git",
      "name": "suinua/team_game_system",
      "url": "https://github.com/MineDeepRock/team_game_system"
    }
  ],
  "require": {
    "pocketmine/pocketmine-mp": "3.14.2",
    "suinua/form_builder": "dev-master",
    "suinua/slot_menu_system": "dev-master",
    "suinua/team_game_system": "dev-master",
    "suinua/scoreboard_system": "dev-master",
    "suinua/bossbar_system": "dev-master"
  }
}

Write code

Creating the Main class

<?php

namespace tdm;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener
{
    public function onEnable() {
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
}

Create a game from Form

Create a form to create a game

Create src/tdm/GameTypeList.php as preparation

<?php


namespace tdm;


use team_game_system\model\GameType;

class GameTypeList
{
    static function TeamDeathMatch(): GameType {
        return new GameType("TeamDeathMatch");
    }
}

Create src\tdm\CreateTeamDeathMatchForm

<?php


namespace tdm;


use form_builder\models\custom_form_elements\Input;
use form_builder\models\custom_form_elements\Label;
use form_builder\models\CustomForm;
use pocketmine\Player;
use pocketmine\scheduler\ClosureTask;
use pocketmine\scheduler\TaskScheduler;
use pocketmine\utils\TextFormat;
use team_game_system\model\Game;
use team_game_system\model\Score;
use team_game_system\model\Team;
use team_game_system\TeamGameSystem;

class CreateTeamDeathMatchForm extends CustomForm
{

    private $scheduler;

    private $timeLimit;
    private $maxPlayersCount;
    private $maxScore;

    public function __construct(TaskScheduler $scheduler) {
        $this->scheduler = $scheduler;

        $this->maxScore = new Input("Victory score", "", "20");
        $this->maxPlayersCount = new Input("People limit", "", "");
        $this->timeLimit = new Input("Time limit (seconds)", "", "300");

        parent::__construct("", [
            new Label ("Please leave blank if none"),
            $this->maxScore,
            $this->maxPlayersCount,
            $this->timeLimit,
        ]);
    }

    function onSubmit(Player $player): void {
        $maxScore = $this->maxScore->getResult();
        $maxScore = $maxScore === "" ?null :new Score(intval($maxScore));

        $maxPlayersCount = $this->maxPlayersCount->getResult();
        $maxPlayersCount = $maxPlayersCount === ""? null :inttval($maxPlayersCount);

        $timeLimit = $this->timeLimit->getResult();
        $timeLimit = $timeLimit === "" ?null :intval($timeLimit);

        //team
        $teams = [
            Team::asNew("Red", TextFormat::RED),
            Team::asNew("Blue", TextFormat::BLUE),
        ];

        // Select map (we will register the map in Minecraft later)
        $map = TeamGameSystem::selectMap("city", $teams);
        // create a game$game = Game::asNew(GameTypeList::TeamDeathMatch(), $map, $teams, $maxScore, $maxPlayersCount, $timeLimit);
        //ゲームを登録
        TeamGameSystem::registerGame($game);

        
        //試合がひらかれてから20秒後にスタートされるように
        $gameId = $game->getId();
        $this->scheduler->scheduleDelayedTask(new ClosureTask(function (int $tick) use ($gameId): void {
            TeamGameSystem::startGame($this->scheduler, $gameId);
        }), 20 * 20);
    }

    function onClickCloseButton(Player $player): void { }
}

Formからゲームに参加する

<?php


namespace tdm;


use form_builder\models\simple_form_elements\SimpleFormButton;
use form_builder\models\SimpleForm;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
use team_game_system\TeamGameSystem;

class TeamDeathMatchListForm extends SimpleForm
{

    public function __construct() {
        $buttons = [];

        foreach (TeamGameSystem::findGamesByType(GameTypeList::TeamDeathMatch()) as $game) {
            $gameId = $game->getId();
            $map = $game->getMap();

            $maxScore = $game->getMaxScore() === null ? "無し" : $game->getMaxScore()->getValue();

            $timeLimit = $game->getTimeLimit() === null ? "無し" : $game->getTimeLimit() . "秒";

            $participantsCount = count(TeamGameSystem::getGamePlayersData($gameId));
            $participants = $game->getMaxPlayersCount() === null ? $participantsCount : "{$participantsCount}/{$game->getMaxPlayersCount()}";

            $buttons[] = new SimpleFormButton(
                "ゲームモード:" . TextFormat::BOLD . strval($game->getType()) . TextFormat::RESET .
                ",マップ:" . TextFormat::BOLD . $map->getName() . TextFormat::RESET .
                "\n勝利判定:" . TextFormat::BOLD . $maxScore . TextFormat::RESET .
                ",時間制限:" . TextFormat::BOLD . $timeLimit . TextFormat::RESET .
                ",参加人数:" . TextFormat::BOLD . $participants . TextFormat::RESET,
                null,
                function (Player $player) use ($gameId) {
                    TeamGameSystem::joinGame($player, $gameId);
                }
            );
        }

        parent::__construct("チームデスマッチ一覧", "", $buttons);
    }

    function onClickCloseButton(Player $player): void { }
}

コマンドからフォームを呼び出す

plugin.ymlに以下を付け足します

commands:
  create:
    usage: "/create"
    description: ""
  join:
    usage: "/join"
    description: ""

src/tdm/Main.phpを編集します

<?php

namespace tdm;

use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\event\Listener;
use pocketmine\Player;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener
{
    public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
        if ($sender instanceof Player) {
            switch ($label) {
                case "create":
                    $sender->sendForm(new CreateTeamDeathMatchForm($this->getScheduler()));
                    return true;
                case "join":
                    $sender->sendForm(new TeamDeathMatchListForm());
                    return true;
            }
        }

        return false;
    }
}

スコアボードの作成

src\tdm\TeamDeathMatchScoreboard.phpを作成します

<?php


namespace tdm;


use pocketmine\Player;
use scoreboard_system\models\Score;
use scoreboard_system\models\Scoreboard;
use scoreboard_system\models\ScoreboardSlot;
use scoreboard_system\models\ScoreSortType;
use team_game_system\model\Game;

class TeamDeathMatchScoreboard extends Scoreboard
{
    private static function create(Game $game): Scoreboard {
        $slot = ScoreboardSlot::sideBar();
        $scores = [
            new Score($slot, "====TeamDeathMatch====", 0, 0),
            new Score($slot, "Map:" . $game->getMap()->getName(), 1, 1),
        ];

        $index = count($scores);
        foreach ($game->getTeams() as $team) {
            $scores[] = new Score($slot, $team->getTeamColorFormat() . $team->getName() . ":" . $team->getScore()->getValue(), $index, $index);
            $index++;
        }

        return parent::__create($slot, "Server Name", $scores, ScoreSortType::smallToLarge());
    }

    static function send(Player $player, Game $game) {
        $scoreboard = self::create($game);
        parent::__send($player, $scoreboard);
    }

    static function update(Player $player, Game $game) {
        $scoreboard = self::create($game);
        parent::__update($player, $scoreboard);
    }
}

ボスバーの下準備

src\tdm\BossBarTypeList.phpを作成します

<?php


namespace tdm;


use bossbar_system\model\BossBarType;

class BossBarTypeList
{
    static function TeamDeathMatch(): BossBarType {
        return new BossBarType("TeamDeathMatch");
    }
}

ゲーム参加時にロビーにいた人に知らせる&途中参加の処理を書く

src\tdm\Main.phpを編集します

        $player = $event->getPlayer();
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($event->getGameId());

        //Do not process if it is related to games other than team deathmatch
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $level = Server::getInstance()->getLevelByName("lobby");
        foreach ($level->getPlayers() as $lobbyPlayer) {
            $lobbyPlayer->sendMessage($player->getName() ." joined the team deathmatch");
        }
        
        // Join halfway
        if ($game->isStarted()) {
            $playerData = TeamGameSystem::getPlayerData($player);
            //Set spawn point
            TeamGameSystem::setSpawnPoint($player);

            //Teleport
            $player->teleport($player->getSpawn());

            //notification
            $player->sendTitle("Team Deathmatch Start");
            $team = TeamGameSystem::getTeam($gameId, $playerData->getTeamId());
            $player->sendMessage("You are". $team->getTeamColorFormat() .$team->getName() .TextFormat::RESET. "");

            //Scoreboard set
            TeamDeathMatchScoreBoard::send($player, $game);
            // Set the boss bar
            $bossBar = new BossBar($player, BossBarTypeList::TeamDeathMatch(), "TeamDeathMatch", 0);
            $bossBar->send();

            // set item
            $player->getInventory()->setContents([
                ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
                ItemFactory::get(ItemIds::APPLE, 0, 10),
            ]);
        }
    }

Write the process at the start of the match

Edit src/tdm/Main.php

    public function onStartedGame(StartedGameEvent $event) {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);
        //Do not process if it is related to games other than team deathmatch
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);

        foreach ($playersData as $playerData) {
            $player = $this->getServer()->getPlayer($playerData->getName());

            //Set spawn point
            TeamGameSystem::setSpawnPoint($player);

            //Teleport
            $player->teleport($player->getSpawn());

            //notification
            $player->sendTitle("Team Deathmatch Start");
            $team = TeamGameSystem::getTeam($gameId, $playerData->getTeamId());
            $player->sendMessage("You are". $team->getTeamColorFormat() .$team->getName() .TextFormat::RESET. "");

            //Scoreboard set
            TeamDeathMatchScoreBoard::send($player, $game);
            // Set the boss bar
            $bossBar = new BossBar($player, BossBarTypeList::TeamDeathMatch(), "TeamDeathMatch", 0);
            $bossBar->send();

            // set item
            $player->getInventory()->setContents([
                ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
                ItemFactory::get(ItemIds::APPLE, 0, 10),
            ]);
        }
    }

So that the score will be included when you defeat the opponent

edit src\tdm\Main.php

    public function onPlayerKilledPlayer(PlayerKilledPlayerEvent $event): void {
        $attacker = $event->getAttacker();
        $attackerData = TeamGameSystem::getPlayerData($attacker);

        //Do not process if it is related to games other than team deathmatch
        $game = TeamGameSystem::getGame($attackerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        TeamGameSystem::addScore($attackerData->getGameId(), $attackerData->getTeamId(), new Score(1));
    }

Update scoreboard when adding score

edit src\tdm\Main.php

    public function onAddedScore(AddedScoreEvent $event): void {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);

        //Do not process if it is related to games other than team deathmatch
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);

        foreach ($playersData as $playerData) {
            $player = $this->getServer()->getPlayer($playerData->getName());
            TeamDeathMatchScoreBoard::update($player, $game);
        }
    }

Set items when respawning

edit src\tdm\Main.php

    public function onRespawn(PlayerRespawnEvent $event) {
        $player = $event->getPlayer();
        $playerData = TeamGameSystem::getPlayerData($player);

        if ($playerData->getGameId() === null) return;
        
        //Do not process if it is related to games other than team deathmatch
        $game = TeamGameSystem::getGame($playerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;
        
        $player->getInventory()->setContents([
            ItemFactory::get(ItemIds::WOODEN_SWORD, 0, 1),
            ItemFactory::get(ItemIds::APPLE, 0, 10),
        ]);
    }

Erase the item drop on death

edit src\tdm\Main.php

    public function onPlayerDeath(PlayerDeathEvent $event) {$player = $event->getPlayer();
        $playerData = TeamGameSystem::getPlayerData($player);

        if ($playerData->getGameId() === null) return;

        //Do not process if it is related to games other than team deathmatch
        $game = TeamGameSystem::getGame($playerData->getGameId());
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;
        
        $event->setDrops([]);
    }

Update boss bar after match time

edit src\tdm\Main.php

    public function onUpdatedGameTimer(UpdatedGameTimerEvent $event): void {
        $gameId = $event->getGameId();
        $game = TeamGameSystem::getGame($gameId);
        //Do not process if it is related to games other than team deathmatch
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $playersData = TeamGameSystem::getGamePlayersData($gameId);
        $timeLimit = $event->getTimeLimit();
        $elapsedTime = $event->getElapsedTime();

        foreach ($playersData as $playerData) {
            $player = Server::getInstance()->getPlayer($playerData->getName());
            $bossBar = BossBar::findByType($player, BossBarTypeList::TeamDeathMatch());

            // If there is no time limit
            if ($timeLimit === null) {
                $bossBar->updateTitle("Elapsed time:" .$elapsedTime);
                continue;
            }

            $bossBar->updatePercentage($elapsedTime / $timeLimit);
            $bossBar->updateTitle($elapsedTime ."/" .$timeLimit);
        }
    }

Send participants to the lobby after the match

edit src\tdm\Main.php

    public function onFinishedGame(FinishedGameEvent $event): void {
        $game = $event->getGame();
        if (!$game->getType()->equals(GameTypeList::TeamDeathMatch())) return;

        $wonTeam = $event->getWonTeam();
        if ($wonTeam === null) {
            $message = "Draw";
        } else {
            $message = $wonTeam->getTeamColorFormat() .$wonTeam->getName() .TextFormat::RESET ."Win of!";
        }


        $playersData = $event->getPlayersData();

        // send it back to lobby
        $server = Server::getInstance();
        $level = $server->getLevelByName("lobby");
        foreach ($playersData as $playerData) {
            $player = $server->getPlayer($playerData->getName());
            // erase the scoreboard
            TeamDeathMatchScoreboard::delete($player);
            // erase the boss bar
            $bossBar = BossBar::findByType($player, BossBarTypeList::TeamDeathMatch());
            $bossBar->remove();

            $player->getInventory()->setContents([]);

            //Teleport
            $player->teleport($level->getSpawnLocation());

            //Send Messege
            $player->sendMessage($message);
        }
    }

This completes the plugin Next we will set the map

Map settings

  1. First, teleport to the map you want to register 2, type the /map command 3, select Create 4, enter the map name and send 5, 2 additional spawn point groups (can be 0 and 1) Select 6,0 and register some spawn points 1 Do the same 7, the end

Change mapname in line 54 of src\tdm\CreateTeamDeathMatchForm.php to the registered map name

$map = TeamGameSystem::selectMap("city", $teams);

that’s all
Thank you Bye