マインクラフト非公式フォーラム

本フォーラムでは多彩なサービスを提供しています。

利用方法は「Wiki」より確認できます。

ぜひご登録をお願いいたします!

PocketMine-MP [初心者・中級者向け]PocketMine-MPのソースコードの読み方 #2

前回の続きから始めます。

イベントを使うプラグインを読む​

Playerクラスのteleportメソッドはどのような内容か?​

同じことの繰り返しとなるのでPlayerクラスの内容を抜粋して表記します。
PHP:
    public function teleport(Vector3 $pos, ?float $yaw = null, ?float $pitch = null) : bool{
        if(parent::teleport($pos, $yaw, $pitch)){
            // 中略 ...
        }
    }
前回のonPlayerLogin()では見られなかった少し見慣れない表記が出てきました。まず、メソッドの宣言部分で第一引数はVector3型のようですが、後ろはどういった意味があるのでしょう?

同じ表記なので$yawで代表して説明します。
まず、$yawは?float型であるようです。型の前についている?nullable(null許容)の意味があり、float型の値のみでなく、nullも入れられるということを意味します。
さらに、$yaw = null となっていますが、これはデフォルト引数値と呼ばれるもので呼び出し側の引数が足りない時にその値が渡されたものとすることができます。
$yaw(水平方向への回転)が省略されたときにはnullが入るものとするということになります。

さらにメソッドの中身について、parent::teleport($pos, $yaw, $pitch)と呼ばれています。こちらは何でしょう?
このコードは、もともと親クラスであるEntityクラスで定義されていたteleportメソッドをスコープ定義演算子により呼び出しているものです。親クラスで定義されていたメソッドは子クラスが上書きしてしまうと呼び出されなくなってしまいますが、このparent::method()を用いることで子クラスの中から親クラスのメソッドを呼び出すことができるわけです。

$yawにnullが入るとどのような振る舞いをするのでしょうか?
Playerの親クラスであるEntityを見るとその動作がさらに詳しくわかります。
PHP:
    public function teleport(Vector3 $pos, ?float $yaw = null, ?float $pitch = null) : bool{
        // 中略 ...
        if($this->setPositionAndRotation($pos, $yaw ?? $this->location->yaw, $pitch ?? $this->location->pitch)){
                // 中略
        }
        // 中略 ...
    }
setPositionAndRotationに注目です。これは名の通り位置とローテーションを決めるメソッドなのですが、途中で渡される値に$yaw ?? $this->location->yawというものがあります。
??というのは、左の値がnull(もしくはundefined)でなれけばその値を、そうでなければ右の値を渡すという演算子です。null合体演算子と呼ばれます。

そして、Entityクラスの$locationプロパティには現在の位置とローテーションが入っています。
したがって、$yawがnullの時には新しい水平回転として現在の水平回転が入ることになります。変わらない、という動作をするのです。

かなり長くなってしまいましたがここまでがteleportの説明です。

最後は飛ばしていきましょう!

teleportに渡される変数を追う​

ここまできたら十分に理解ができているはずです。今まで培った知識をもとに、コードを見るだけでどのように処理が進むかわかるでしょう。

Loaderの親クラス, PluginBaseのコード​

PHP:
    final public function getServer() : Server{
        return $this->server;
    }

Serverのコード​

PHP:
    public function getWorldManager() : WorldManager{
        return $this->worldManager;
    }

WorldManagerのコード​

PHP:
    public function getDefaultWorld() : ?World{
        return $this->defaultWorld;
    }

PHP:
    public function getSafeSpawn(?Vector3 $spawn = null) : Position{
        if(!($spawn instanceof Vector3) or $spawn->y < 1){
            $spawn = $this->getSpawnLocation();
        }

        $max = $this->maxY;
        $v = $spawn->floor();
        $chunk = $this->getOrLoadChunkAtPosition($v);
        if($chunk === null){
            throw new WorldException("Cannot find a safe spawn point in non-generated terrain");
        }
        $x = (int) $v->x;
        $z = (int) $v->z;
        $y = (int) min($max - 2, $v->y);
        $wasAir = $this->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::AIR; //TODO: bad hack, clean up
        for(; $y > $this->minY; --$y){
            if($this->getBlockAt($x, $y, $z)->isFullCube()){
                if($wasAir){
                    $y++;
                    break;
                }
            }else{
                $wasAir = true;
            }
        }

        for(; $y >= $this->minY and $y < $max; ++$y){
            if(!$this->getBlockAt($x, $y + 1, $z)->isFullCube()){
                if(!$this->getBlockAt($x, $y, $z)->isFullCube()){
                    return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this);
                }
            }else{
                ++$y;
            }
        }

        return new Position($spawn->x, $y, $spawn->z, $this);
    }

しっかり追えましたか?
// 余裕があればもう少し書き加えたい
 
Top