WorldLifecycle
MoripaFishing-Integration-WorldLifecycle
Core (MoripaFishing) に依存する公式 Integration。以下の機能を提供します。
- 環境の適用 (
EnvironmentApplier): Core が決めた時刻・ゲームルールADVANCE_TIME・ワールドボーダー・スポーン地点を Bukkit ワールドへ適用 - ワールドの作成・アンロード (
BukkitWorldLifecycle): ジェネレーター定義を使った釣りワールドの作成と、削除時のアンロード - プレイヤーの 参加時テレポート: 参加したプレイヤーを釣りワールドのスポーン地点へ移動
Core 自体は Bukkit ワールドへ一切書き込みません。本 Integration と Weather を 導入しない限り、ワールドの時刻・ゲームルール・スポーン・ボーダーは変更されません。 仕組みの全体像は Integration とは を参照してください。
導入
-
plugins/に Core とリリースのMoripaFishing-world-lifecycle-<version>.jarを配置する (プラグイン名はMoripaFishing-Integration-WorldLifecycle)。 -
サーバーを起動する。本 Integration は Core に必須依存しているため (
paper-plugin.ymlのserver("MoripaFishing", Load.BEFORE, required = true))、Core の後にロードされます。 Core が無いと本 Integration は起動しません。 -
起動時に次のログが出ます。
[MoripaFishing-Integration-WorldLifecycle] MoripaFishing-Integration-WorldLifecycle enabled (generators: [normal, terra, void]).
有効化時に WorldLifecycle と WorldStateApplier を ServicesManager に登録します。
登録は本 Integration の無効化時に自動で解除されます。
環境の適用
EnvironmentApplier は Core から届く WorldState のうち、次の項目だけを適用します。
| 項目 | 適用内容 |
|---|---|
doDaylightCycle | ゲームルール ADVANCE_TIME に毎回書き込む |
time | null でなければワールド時刻に設定する。null なら時刻に触れない |
border | null でなければワールドボーダーの中心とサイズを設定する。null ならボーダーに触れない |
spawn | ワールドのスポーン地点がブロック座標または向き (yaw) で異なる場合だけ設定する (Paper はスポーンをブロック単位で保持するため) |
時刻の計算 (実時刻同期・固定時刻) とゲームルールの値は Core が決めます。詳細は 気候の設定 を参照してください。
ボーダーを他のプラグインで管理したい場合は、ワールド設定の world.border を null にします (ワールド設定)。
ワールドの作成とアンロード
BukkitWorldLifecycle は Core の WorldLifecycle SPI を実装します。
createWorld(worldKey, generatorId): ジェネレーター定義からWorldCreatorを組み立ててBukkit.createWorldを呼びます。 同じキーのワールドが既にある場合やジェネレーター ID が不明な場合は何もせずfalseを返します。unloadWorld(worldKey): ワールドを保存せずにアンロードします。未ロードの場合やアンロードに失敗した場合 (プレイヤーが残っているなど) はfalseを返します。getGeneratorIds(): 読み込んだジェネレーター ID の一覧を返します。
Core は次の場面でこれらを呼びます。
- サーバー起動後 (
ServerLoadEvent): 定義済みで未ロードの管理ワールドを、ワールド設定のworld.generatorで作成する (外部ワールドは作成しない) /mf world create <id> <generator>: 新しい釣りワールドを定義して作成する。補完候補はgetGeneratorIds()から供給される/mf world delete <world>: ロード済みの釣りワールドをアンロードしてから定義を削除する
ジェネレーター定義
ジェネレーター定義は本 Integration の内部形式で、plugins/MoripaFishing-Integration-WorldLifecycle/generator/ に置きます。
初回起動時に同梱の terra.json / void.json / normal.json が書き出されます。
{
"id": "terra",
"generator": "Terra:OVERWORLD",
"type": null,
"biomeProvider": null,
"generatorSetting": null
}{
"id": "void",
"generator": null,
"type": "FLAT",
"biomeProvider": null,
"generatorSetting": "{\"layers\": [{\"block\": \"air\", \"height\": 1}], \"biome\":\"plains\"}"
}normal.json は id を除く全フィールドが null で、Bukkit の既定生成にそのまま任せる定義です。
| フィールド | 型 | 説明 |
|---|---|---|
id | string | ジェネレーター ID。ワールド設定の world.generator から参照される |
generator | string? | WorldCreator.generator() に渡される文字列 (プラグイン名) |
type | string? | WorldType 名 (NORMAL / FLAT / LARGE_BIOMES / AMPLIFIED) |
biomeProvider | string? | 全座標に同じバイオームを返す固定バイオーム名 (例: minecraft:plains) |
generatorSetting | string? | ジェネレーター設定文字列 |
ディレクトリ内の JSON ファイルはすべて読み込まれるため、任意の JSON を置くだけでジェネレーターを追加できます。 不正なファイルは警告を出して読み飛ばします。詳細は ジェネレーター設定 を参照してください。
参加時テレポート
プレイヤーがサーバーに参加した際、釣りワールドのスポーン地点へ自動でテレポートします。
テレポート先は参加のたびに決めます。管理ワールドでは Core の公開 API から取得したワールド設定の world.spawn、外部ワールド では Bukkit ワールドのスポーン地点を使います。
設定は plugins/MoripaFishing-Integration-WorldLifecycle/join-teleport.yml に置きます (初回起動時に既定値が書き出されます)。
enabled: true
worldId: null
onlyFirstJoin: false| フィールド | 型 | 説明 |
|---|---|---|
enabled | boolean | 参加時テレポート機能の有効/無効 (デフォルト: true) |
worldId | string? | テレポート先の釣りワールドID。null の場合は Core のデフォルトワールドを使用 |
onlyFirstJoin | boolean | true の場合、サーバーに初めて参加したプレイヤーにのみテレポートを行う (デフォルト: false) |
テレポートの直前に AnglerJoinTeleportEvent が発火します。
キャンセルするとテレポートは行われず、setDestination で移動先を差し替えられます。
設定どおりに動かない場合は、次の条件に当てはまっていないか確認してください。
worldIdが未定義の場合は何もしません (設定ミスの典型例)- 対象の Bukkit ワールドがロードされていない場合も何もしません
join-teleport.ymlの読み込みに失敗した場合は警告を出して既定値で続行しますenabledがfalseの場合はリスナー自体を登録しません
独自の WorldStateApplier を書く
本 Integration と同じ仕組みで、Core が決めた状態を独自の方法で適用できます。
WorldStateApplier は登録された全件が呼ばれるため、公式 Integration と併用できます。
class DaylightOnlyApplier : WorldStateApplier {
override fun apply(state: WorldState) {
// メインスレッドで呼ばれる。未ロードのワールドは無視する
val world = Bukkit.getWorld(state.worldKey) ?: return
world.setGameRule(GameRules.ADVANCE_TIME, state.doDaylightCycle)
// null は「変更しない」
state.time?.let { world.time = it }
}
}
class MyPlugin : JavaPlugin() {
override fun onEnable() {
server.servicesManager.register(
WorldStateApplier::class.java,
DaylightOnlyApplier(),
this,
ServicePriority.Normal,
)
}
}依存の宣言・型の制約・WorldState の契約は Integration とは を参照してください。