1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ブロックをスポーンさせるスポナーを作成する

Last updated at Posted at 2024-03-15

環境

PaperAPI : 1.20.4-R0.1

完成物イメージ

手順

CreatureSpawner を取得する

まず、全ての設定をのせるスポナーを座標などから取得します。
スポナーは、機能的ブロックのインタフェースである BlockState の実装クラスである CreatureSpawner クラスなのでキャスト等を用いて取得します。

// World型 world: スポナーが存在するワールド
// Location型 location: スポナーの座標を示す Location
Block block = world.getBlockAt(location);
CreatureSpawner spawner = (CreatureSpawner) block.getBlockState();

FallingBlock を作成する

スポーンさせるためのエンティティを作成します。
ここで必要な Entity 型は、実際にゲーム内にスポーンさせないとうまく掴めないため、一度ブロックデータを何も設定しない状態でスポーンさせます。

Entity entity = world.spawn(location, EntityType.FALLING_BLOCK.getEntityClass());
FallingBlock fallingBlock = (FallingBlock) entity;

World#createEntity を用いるとワールドにエンティティをスポーンさせずに掴むことができます。
しかしこの方法でスポーンさせたエンティティは、ワールドをアンロードした後に操作しようとするとメモリリークを起こすため、私としては World#createEntity() の使用を推奨しません。(このメソッドが非推奨にされているわけではなく、公式も「メモリリークを起こす危険性があるから扱いには気をつけてね」と言っているだけなので)

Note: The created entity keeps a reference to the world it was created in, care should be taken that the entity does not outlive the world instance as this will lead to memory leaks.

PaperMC 1.20.4-R0.1 JavaDoc RegionAccessor#createEntity() より


おそらく、ワールドをアンロードする Bukkit#unloadWorld()Server#unloadWorld() が対象のワールドのインスタンスを finalize して強制的に破棄 (を GC へ要求) するため、エンティティからの参照だけが残り続けて結果的にメモリリークが発生する、というものだと考えられます。

PaperMC 1.20.4-R0.1 JavaDoc Bukkit#unloadWorld()

ブロック種別を設定する

上記の手順で作成した FallingBlock を湧かせようとスポナーに登録しても空気ブロックを湧かせてしまうので、ブロック種別を変更します。

もともと持っている BlockState をコピーして取得した新しい BlockState に対して setType を実行し、ブロックの種別を変更します。

そして、コピーしたものを FallingBlock#setBlockState() で落下ブロックに設定し、既存の設定を上書きします。

BlockState copied = fallingBlock.getBlockState().copy();
copied.setType(Material.DIAMOND_BLOCK);
fallingBlock.setBlockState(copied);

作成した FallingBlock をスポナーに登録する

spawner.setSpawnedEntity(fallingBlock.createSnapshot());

(この setSpawnedEntity という関数は引数に EntitySnapshot しか受け付けないのにも拘らず、Entity から EntitySnapshot を作成する唯一の手段である Entity#createEntitySnapshot() が実験的なメソッドであり、動作の保証をしないことを示すアノテーションをつけられているというこのチグハグさはどうにかしてほしいところです。)

データの更新を適用する

BlockState の実装クラスはすべて update() を実行しないことにはデータの更新が行われません。
忘れずに実行しましょう。

spawner.update();
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?