前回の続きから始めます。
前回の
同じ表記なので$yawで代表して説明します。
まず、
さらに、
さらにメソッドの中身について、
このコードは、もともと親クラスであるEntityクラスで定義されていたteleportメソッドをスコープ定義演算子により呼び出しているものです。親クラスで定義されていたメソッドは子クラスが上書きしてしまうと呼び出されなくなってしまいますが、この
Playerの親クラスであるEntityを見るとその動作がさらに詳しくわかります。
setPositionAndRotationに注目です。これは名の通り位置とローテーションを決めるメソッドなのですが、途中で渡される値に
??というのは、左の値がnull(もしくはundefined)でなれけばその値を、そうでなければ右の値を渡すという演算子です。null合体演算子と呼ばれます。
そして、Entityクラスの$locationプロパティには現在の位置とローテーションが入っています。
したがって、$yawがnullの時には新しい水平回転として現在の水平回転が入ることになります。変わらない、という動作をするのです。
かなり長くなってしまいましたがここまでがteleportの説明です。
最後は飛ばしていきましょう!
しっかり追えましたか?
// 余裕があればもう少し書き加えたい
イベントを使うプラグインを読む
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)){
// 中略
}
// 中略 ...
}
$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);
}
しっかり追えましたか?
// 余裕があればもう少し書き加えたい