Swallow794 (トーク | 投稿記録) (ディメンションの生成まで作成) |
Swallow794 (トーク | 投稿記録) (Dimension間移動について、PlayerList#transferEntityToWorldは私の方で転送に成功していない(詳しくは未検証)ので、強引な手法を記述) |
||
130行目: | 130行目: | ||
==== Teleporter ==== | ==== Teleporter ==== | ||
+ | 「net.minecraft.world.Teleporter」は移動するEntityの現在座標をもとにポータルを生成するクラスです。 | ||
+ | |||
+ | EntityがDimension移動するのに使われる「net.minecraft.entity.Entity#changeDimension」では、「net.minecraft.world.WorldServer#getDefaultTeleporter」を呼び出し、「WorldServer#worldTeleporter」を得ています。 | ||
+ | |||
+ | ===== PlayerList#transferEntityToWorldを利用する場合 ===== | ||
+ | (未検証) | ||
+ | |||
+ | ===== 強引にEntity#changeDimensionを利用する場合 ===== | ||
+ | # AccessTransformerを使って、「private final」な「WorldServer#worldTeleporter」、SRG名「field_85177_Q」のアクセス修飾子を「public」にする(下ソース参照、net.minecraftforge.fml.relauncher.ReflectionHelperでも可)。 | ||
+ | # 転送時、元々のWorldServer#worldTeleporterを退避して、好きなTeleporterインスタンスを代入。Entity#changeDimensionを呼んでEntityを移動させ、WorldServer#worldTeleporterを復元する。 | ||
+ | |||
+ | META-INF/<modid>_at.cfg | ||
+ | <source lang="text"> | ||
+ | public-f net.minecraft.world.WorldServer field_85177_Q #worldTeleporter non-final | ||
+ | </source> | ||
+ | |||
+ | 2の例 | ||
+ | <source lang="java" line> | ||
+ | public static <T extends Entity> void transferEntity(World worldIn, BlockPos portalPos, T entityIn, | ||
+ | int destDimension, Function<WorldServer, Teleporter> funcTeleporter, | ||
+ | Consumer<T> callback) { | ||
+ | entityIn.setPortal(portalPos); | ||
+ | entityIn.timeUntilPortal = 10; | ||
+ | |||
+ | if (!worldIn.isRemote && !entityIn.isDead) { | ||
+ | MinecraftServer server = entityIn.getServer(); | ||
+ | WorldServer destServer = server.worldServerForDimension(destDimension); | ||
+ | |||
+ | Teleporter teleporter = funcTeleporter.apply(destServer); | ||
+ | Teleporter cache = destServer.worldTeleporter; // Access Transformer | private final -> public | ||
+ | |||
+ | destServer.worldTeleporter = teleporter; | ||
+ | T clone = (T) entityIn.changeDimension(destDimension); | ||
+ | callback.accept(clone); // 座標設定等 | ||
+ | |||
+ | destServer.worldTeleporter = cache; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | </source> |
2017年3月26日 (日) 02:19時点における版
この記事は"Minecraft Forge Universal 13.19.0.xxx~"を前提MODとしています。 |
目次
ディメンションの追加
ディメンションを生成する
DimensionType
「net.minecraft.world.DimensionType」は、ディメンションを登録する列挙型です。
ForgeがDimensionTypeに列挙子を追加するメソッド「DimensionType#register」を用意してくれているので、これを使います。
- 「net.minecraftforge.common.DimensionManager#getNextFreeDimId」から、使用可能なディメンションID(int)を取得します。
- 「DimensionType#register」を呼び出し、「DimensionType」型の戻り値を得ます。これが追加された列挙子で、WorldProviderで使います。
- 第一引数(String):ディメンションの名前(e.g. Overworld、Nether、The End)
- 第二引数(String):ディメンションのセーブデータ等で使う後置詞(e.g. _nether、_end)
- 第三引数(int):1で取得したID
- 第四引数(Class<? extends WorldProvider>):WorldProviderのクラス(下で解説)
- 第五引数(boolean):ディメンションをアンロードしないかどうか
- 「DimensionManager#registerDimension」を呼び出し、こちらにもディメンションを登録します。
WorldProvider
「net.minecraft.world.WorldProvider」は、ワールドの振る舞いを決定する抽象クラスです。
- 「WorldProvider」のサブクラスを作成します。
- コンストラクタから「WorldProvider#init」が呼ばれるので、WorldProviderのフィールド(下表参照)を好きなように変更してください。
- 「DimensionType」の項で得た、このWorldProviderに対応する「DimensionType」列挙子を「getDimensionType」から返します。
フィールド名 | 影響 | 参考 |
---|---|---|
doesWaterVaporize | 水の蒸発の有無 |
|
hasNoSky | 地図の描画、スポーン座標 |
|
hasSkyLight | 日光の有無 |
|
biomeProvider | バイオームの決定 | 下で解説 |
メソッド名 | 影響 | 参考 |
---|---|---|
calculateCelestialAngle | 昼夜の移り変わり | 0fで真昼(エンド)、.5fで真夜中(ネザー)
|
createChunkGenerator | チャンクの地形等、生成手法の決定 | net.minecraft.world.chunk.IChunkGeneratorを実装したクラスのインスタンスを作成して返す。詳しくは下で解説。 |
canRespawnHere | リスポーンの可否 | |
isSurfaceWorld | 空の描画の有無 | |
getVoidFogYFactor | 奈落の霧(Japan Wiki)の開始Y座標 | |
getHorizon | 地平線の高さ | |
doesXZShowFog | 霧の描画の有無 |
|
getWelcomeMessage | ディメンション入場時のメッセージ?(未使用) | |
getDepartMessage | ディメンション退場時のメッセージ?(未使用) |
BiomeProvider
「net.minecraft.world.biome.BiomeProvider」は、バイオームを決定するクラスです。
サブクラス「net.minecraft.world.biome.BiomeProviderSingle」は、単一バイオームのディメンションを作成するのに使うことができます(ネザー、エンドで使用)。
オーバーワールドでは、「net.minecraft.world.gen.layer.GenLayer#initializeAllBiomeGenerators」、「net.minecraft.world.biome.BiomeProvider#getModdedBiomeGenerators」を通じて得られた「GenLayer」の「#getInts」からバイオームIDを取得しています。
IChunkGenerator
「net.minecraft.world.chunk.IChunkGenerator」は、チャンクの地形や構造物を生成するインターフェースです。
- 「IChunkGenerator」を実装したクラスを作成します。コンストラクタでWorldProviderからWorldのインスタンスを受け取ってください。チャンクのインスタンス化に使います。
- 「#provideChunk」を実装します。第一引数はチャンクのX座標、第二引数はチャンクのZ座標です。
- 「net.minecraft.world.chunk.ChunkPrimer」をインスタンス化します。
- 上のWorld、ChunkPrimerを使って「net.minecraft.world.chunk.Chunk」をインスタンス化します。
- Chunk#setBlockStateなどを使って、上のChunkに地形を生成します。
- Chunkにバイオームを割り当てます。
- net.minecraft.world.chunk.ChunkProviderHellの手法
- Chunk#getBiomeArrayの戻り値としてバイオーム割り当てに使用するバイオームIDのbyte配列を得ます。
- 上のWorldからBiomeProviderを取得し、BiomeProvider#getBiomesから、チャンク座標に対応するバイオームのBiome配列を得ます。
- byte配列のindexに対応するバイオームIDをBiome配列から取り出して代入します(配列はオブジェクトなので、Chunkが持つ配列が変更されます)。
メソッド名 | 操作 | 参考 |
---|---|---|
provideChunk | チャンクのインスタンス化、地形生成 | |
populate | 湖、鉱石、ダンジョン等の生成 | |
generateStructures | 構造物の追加生成(海底遺跡で使用) | |
getPossibleCreatures | EntityCreatureの自然スポーン設定
|
|
getStrongholdGen | ダンジョンを生成するブロック座標を返す。なければnull。 | オーバーワールドの要塞を見つけるエンダーアイで使用。
|
recreateStructures | ダンジョン等MapGenBaseのサブクラスのインスタンスがあればMapGenBase#generateを呼ぶ。
チャンクをファイルから読み込む時に呼ばれる模様。ブロック生成以外の構造物のデータを読み込む? |
|
ポータルを作成する
Teleporter
「net.minecraft.world.Teleporter」は移動するEntityの現在座標をもとにポータルを生成するクラスです。
EntityがDimension移動するのに使われる「net.minecraft.entity.Entity#changeDimension」では、「net.minecraft.world.WorldServer#getDefaultTeleporter」を呼び出し、「WorldServer#worldTeleporter」を得ています。
PlayerList#transferEntityToWorldを利用する場合
(未検証)
強引にEntity#changeDimensionを利用する場合
- AccessTransformerを使って、「private final」な「WorldServer#worldTeleporter」、SRG名「field_85177_Q」のアクセス修飾子を「public」にする(下ソース参照、net.minecraftforge.fml.relauncher.ReflectionHelperでも可)。
- 転送時、元々のWorldServer#worldTeleporterを退避して、好きなTeleporterインスタンスを代入。Entity#changeDimensionを呼んでEntityを移動させ、WorldServer#worldTeleporterを復元する。
META-INF/<modid>_at.cfg
public-f net.minecraft.world.WorldServer field_85177_Q #worldTeleporter non-final
2の例
public static <T extends Entity> void transferEntity(World worldIn, BlockPos portalPos, T entityIn, int destDimension, Function<WorldServer, Teleporter> funcTeleporter, Consumer<T> callback) { entityIn.setPortal(portalPos); entityIn.timeUntilPortal = 10; if (!worldIn.isRemote && !entityIn.isDead) { MinecraftServer server = entityIn.getServer(); WorldServer destServer = server.worldServerForDimension(destDimension); Teleporter teleporter = funcTeleporter.apply(destServer); Teleporter cache = destServer.worldTeleporter; // Access Transformer | private final -> public destServer.worldTeleporter = teleporter; T clone = (T) entityIn.changeDimension(destDimension); callback.accept(clone); // 座標設定等 destServer.worldTeleporter = cache; } }