提供: Minecraft Modding Wiki
移動先: 案内検索

警告: ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。ログインまたはアカウントを作成すれば、あなたの編集はその利用者名とともに表示されるほか、その他の利点もあります。

この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 編集中の文章
19行目: 19行目:
 
#* 第五引数(boolean):ディメンションをアンロードしないかどうか
 
#* 第五引数(boolean):ディメンションをアンロードしないかどうか
 
# 「DimensionManager#registerDimension」を呼び出し、こちらにもディメンションを登録します。
 
# 「DimensionManager#registerDimension」を呼び出し、こちらにもディメンションを登録します。
 
 
<source lang="java" line>
 
package samplemod;
 
 
import net.minecraft.world.DimensionType;
 
import net.minecraftforge.common.DimensionManager;
 
import net.minecraftforge.fml.common.Mod;
 
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
 
import samplemod.world.sample.WorldProviderSample;
 
 
@Mod(modid = SampleMod.MOD_ID, name = SampleMod.MOD_NAME, version = SampleMod.MOD_VERSION)
 
public class SampleMod {
 
    public static final String MOD_ID = "samplemod";
 
    public static final String MOD_NAME = "Sample Mod";
 
    public static final String MOD_VERSION = "0.1.0";
 
 
    public static DimensionType SAMPLE_DIMENSION;
 
 
    @Mod.EventHandler
 
    public void preInit(FMLPreInitializationEvent event) {
 
        SAMPLE_DIMENSION = DimensionType.register("Sample Dimension", "_sample", DimensionManager.getNextFreeDimId(), WorldProviderSample.class, false);
 
        DimensionManager.registerDimension(SAMPLE_DIMENSION.getId(), SAMPLE_DIMENSION);
 
 
    }
 
 
}
 
 
</source>
 
  
 
==== WorldProvider ====
 
==== WorldProvider ====
56行目: 27行目:
 
# 「DimensionType」の項で得た、このWorldProviderに対応する「DimensionType」列挙子を「getDimensionType」から返します。
 
# 「DimensionType」の項で得た、このWorldProviderに対応する「DimensionType」列挙子を「getDimensionType」から返します。
  
{| class="wikitable"
+
{|
 
!フィールド名!!影響!!参考
 
!フィールド名!!影響!!参考
 
|-
 
|-
75行目: 46行目:
  
  
{| class="wikitable"
+
{|
 
!メソッド名!!影響!!参考
 
!メソッド名!!影響!!参考
 
|-
 
|-
98行目: 69行目:
 
* net.minecraft.client.renderer.EntityRenderer#setupFog
 
* net.minecraft.client.renderer.EntityRenderer#setupFog
 
|-
 
|-
|getWelcomeMessage||ディメンション入場時のメッセージ?(未使用、Forge)||
+
|getWelcomeMessage||ディメンション入場時のメッセージ?(未使用)||
 
|-
 
|-
|getDepartMessage||ディメンション退場時のメッセージ?(未使用、Forge)||
+
|getDepartMessage||ディメンション退場時のメッセージ?(未使用)||
 
|}
 
|}
  
124行目: 95行目:
 
### byte配列のindexに対応するバイオームIDをBiome配列から取り出して代入します(配列はオブジェクトなので、Chunkが持つ配列が変更されます)。
 
### byte配列のindexに対応するバイオームIDをBiome配列から取り出して代入します(配列はオブジェクトなので、Chunkが持つ配列が変更されます)。
  
{| class="wikitable"
+
{|
 
!メソッド名!!操作!!参考
 
!メソッド名!!操作!!参考
 
|-
 
|-
155行目: 126行目:
 
|}
 
|}
  
===== 例:岩盤の床だけのチャンクを生成する =====
 
Y=0に岩盤の床があるだけのチャンクを生成します。
 
 
ChunkGeneratorEmpty.java
 
<source lang="java" line>
 
package samplemod.world.empty;
 
  
import net.minecraft.entity.EnumCreatureType;
+
=== ポータルを作成する ===
import net.minecraft.init.Blocks;
 
import net.minecraft.util.math.BlockPos;
 
import net.minecraft.world.World;
 
import net.minecraft.world.biome.Biome;
 
import net.minecraft.world.chunk.Chunk;
 
import net.minecraft.world.chunk.ChunkPrimer;
 
import net.minecraft.world.chunk.IChunkGenerator;
 
  
import javax.annotation.Nullable;
+
==== Teleporter ====
import java.util.List;
+
「net.minecraft.world.Teleporter」は移動するEntityの現在座標をもとにポータルを生成するクラスです。
  
public class ChunkGeneratorEmpty implements IChunkGenerator {
+
EntityがDimension移動するのに使われる「net.minecraft.entity.Entity#changeDimension」では、「net.minecraft.world.WorldServer#getDefaultTeleporter」を呼び出し、「WorldServer#worldTeleporter」を得ています。
    private World world;
 
  
    public ChunkGeneratorEmpty(World worldIn) {
+
===== PlayerList#transferEntityToWorldを利用する場合 =====
        world = worldIn;
+
(未検証)
    }
 
  
    public void genSurface(Chunk chunk) {
+
===== 強引にEntity#changeDimensionを利用する場合 =====
        for (int x = 0; x < 16; x++)
+
# AccessTransformerを使って、「private final」な「WorldServer#worldTeleporter」、SRG名「field_85177_Q」のアクセス修飾子を「public」にする(下ソース参照、net.minecraftforge.fml.relauncher.ReflectionHelperでも可)。
            for (int z = 0; z < 16; z++)
+
# 転送時、元々のWorldServer#worldTeleporterを退避して、好きなTeleporterインスタンスを代入。Entity#changeDimensionを呼んでEntityを移動させ、WorldServer#worldTeleporterを復元する。
                chunk.setBlockState(new BlockPos(x, 0, z), Blocks.BEDROCK.getDefaultState());
 
    }
 
 
 
    @Override
 
    public Chunk provideChunk(int x, int z) {
 
        ChunkPrimer chunkPrimer = new ChunkPrimer();
 
 
 
        Chunk chunk = new Chunk(world, chunkPrimer, x, z);
 
        genSurface(chunk);
 
 
 
        Biome[] abiome = world.getBiomeProvider().getBiomes(null, x * 16, z * 16, 16, 16);
 
        byte[] abyte = chunk.getBiomeArray();
 
 
 
        for (int i = 0; i < abiome.length; i++)
 
            abyte[i] = (byte) Biome.getIdForBiome(abiome[i]);
 
 
 
        chunk.resetRelightChecks();
 
        return chunk;
 
    }
 
 
 
    @Override
 
    public void populate(int x, int z) {
 
    }
 
 
 
    @Override
 
    public boolean generateStructures(Chunk chunkIn, int x, int z) {
 
        return false;
 
    }
 
 
 
    @Override
 
    public List<Biome.SpawnListEntry> getPossibleCreatures(EnumCreatureType creatureType, BlockPos pos) {
 
        return world.getBiome(pos).getSpawnableList(creatureType);
 
    }
 
 
 
    @Nullable
 
    @Override
 
    public BlockPos getStrongholdGen(World worldIn, String structureName, BlockPos position, boolean p_180513_4_) {
 
        return null;
 
    }
 
 
 
    @Override
 
    public void recreateStructures(Chunk chunkIn, int x, int z) {
 
 
 
    }
 
}
 
  
 +
META-INF/<modid>_at.cfg
 +
<source lang="text">
 +
public-f net.minecraft.world.WorldServer field_85177_Q #worldTeleporter non-final
 
</source>
 
</source>
  
 
+
2の例
=== ポータルを生成する ===
 
 
 
==== Teleporter ====
 
「net.minecraft.world.Teleporter」は移動するEntityの現在座標をもとにポータルを生成し、ポータル位置にEntityを移動させるクラスです。
 
 
 
EntityがDimension移動するのに使われる「net.minecraft.entity.Entity#changeDimension」では、「net.minecraft.world.WorldServer#getDefaultTeleporter」を呼び出し、Teleporter型の「WorldServer#worldTeleporter」を得ています。
 
 
 
また、Entityがエンド以外からネザーへ転送される時はTeleporter呼び出し前に座標が1/8倍され、エンド以外からオーバーワールドへ転送されるときは8倍されます(PlayerList#transferEntityToWorldではForgeによりデッドコード化されているため、座標は変更されない)。
 
 
 
# 「Teleporter」のサブクラスを作成します。コンストラクタで目的地のWorldServerを受け取ってください。
 
# 「makePortal」、「placeInExistingPortal」を再実装します。「placeInPortal」はエンドへの転送時の足場生成を変更する場合のみ、再実装するとよいでしょう。
 
 
 
{| class="wikitable"
 
!メソッド名!!操作
 
|-
 
|makePortal||バニラでは、ネザーポータルの生成位置決定と生成を行う。
 
|-
 
|placeInPortal||PlayerList#transferEntityToWorldから呼ばれる。バニラでは、エンド以外への転送の場合、placeInExistingPortalを呼び出し、falseが返されたらmakePortalを呼び、もう一度placeInExistingPortalを呼び出している。つまり、ポータルの存在の有無によってmakePortalが呼ばれるかどうかが変わり、makePortalで適切にポータルを生成していれば、既存のポータルまたは新しいポータルで転送できる。エンドへの転送の場合、足場となる黒曜石を生成している。
 
|-
 
|placeInExistingPortal||Entity#changeDimensionから呼ばれる。バニラでは、既存の「ポータルブロック」(Blocks.PORTAL)を探索し、見つからない場合falseを返す。見つかった場合、Entityをポータル座標に移動させてtrueを返す。また、キャッシュされていないポータル(座標)のキャッシュもここで行っている。
 
|-
 
|removeStalePortalLocations||worldTimeをもとに、古いポータル(座標)のキャッシュを削除する。
 
|}
 
 
 
=== エンティティを転送する ===
 
Entityの別のディメンションへの転送方法について解説します。バニラ+Forge環境で利用可能な転送用メソッドは二種類あります。
 
 
 
一つ目の「net.minecraft.entity.Entity#changeDimension」は、ネザーポータル、エンドポータルによるディメンション間移動に使用されています。これは、まずEntity#dimensionを変更したのち、出発地のディメンションに対応するWorldServerからEntityを削除、座標を変更してTeleporterを呼び出し、目的地のディメンションに対応するWorldServerインスタンスを渡してEntityのクローンを作成し、クローンを目的地に強制スポーンさせることでディメンション間移動を実現しています。
 
 
 
クローンのEntity#dimensionはコンストラクタでWorldServerから取得されることになり、最初の代入は無駄にも思えますが、ポータルを生成するTeleporterに渡されるのは最初の(出発地側の)Entityであるため、Teleporter内ではコンストラクタに渡される目的地のWorldServerのディメンションIDとEntity#dimensionは一致することになります(バニラでは転送先はWorldServerから取って判定しているのだが)。
 
 
 
二つ目の「net.minecraft.server.management.PlayerList#transferEntityToWorld」は、「net.minecraft.entity.player.EntityPlayerMP」で再実装された「#changeDimension」から「PlayerList#changePlayerDimension」を経由して呼ばれています。
 
 
 
<small>
 
バニラの「PlayerList#changePlayerDimension」は、ForgeによってTeleporter引数を追加したメソッド「#transferPlayerToDimension」に処理を移されています([https://github.com/MinecraftForge/MinecraftForge/blob/1.11.x/patches/minecraft/net/minecraft/server/management/PlayerList.java.patch#L151 GitHub/MinecraftForge/PlayerList.java.patch#L151])。「#transferPlayerToDimension」は、出発地のWorldServerからEntityPlayerMPを削除したのち、「#transferEntityToWorld」を呼び出しています。
 
</small>
 
 
 
<small>
 
バニラの「PlayerList#transferEntityToWorld」は、ForgeによってTeleporter引数を追加した同名メソッドに処理を移されています([https://github.com/MinecraftForge/MinecraftForge/blob/1.11.x/patches/minecraft/net/minecraft/server/management/PlayerList.java.patch#L179 GitHub/MinecraftForge/PlayerList.java.patch#L179])。
 
</small>
 
 
 
「PlayerList#transferEntityToWorld」のおおよその処理は「Entity#changeDimension」と同じですが、新しくEntityのインスタンスを作り直さず、「Entity#setWorld」を呼んで出発地のWorldに属するEntityインスタンスをそのまま目的地のWorldで再利用します。
 
 
 
また注意すべき点として、「PlayerList#transferEntityToWorld」は、出発地のWorldからEntityを削除しません。自分で出発地のWorldに対して「World#removeEntityDangerously」を呼んで、World及びChunkからEntityを削除する必要があります。
 
 
 
===== 例:「触れるとディメンションを移動するブロック」を追加する =====
 
 
 
BlockTeleporter.java
 
 
<source lang="java" line>
 
<source lang="java" line>
package samplemod.block;
+
public static <T extends Entity> void transferEntity(World worldIn, BlockPos portalPos, T entityIn,
 
+
                                                    int destDimension, Function<WorldServer, Teleporter> funcTeleporter,
import net.minecraft.block.Block;
+
                                                    Consumer<T> callback) {
import net.minecraft.block.material.Material;
+
    entityIn.setPortal(portalPos);
import net.minecraft.block.state.IBlockState;
+
     entityIn.timeUntilPortal = 10;
import net.minecraft.entity.Entity;
 
import net.minecraft.entity.player.EntityPlayerMP;
 
import net.minecraft.server.MinecraftServer;
 
import net.minecraft.server.management.PlayerList;
 
import net.minecraft.util.math.AxisAlignedBB;
 
import net.minecraft.util.math.BlockPos;
 
import net.minecraft.world.*;
 
import samplemod.SampleMod;
 
import samplemod.world.sample.TeleporterSample;
 
 
 
import javax.annotation.Nullable;
 
 
 
public class BlockTeleporter extends Block {
 
 
 
    public BlockTeleporter() {
 
        super(Material.ROCK);
 
    }
 
 
 
    @Nullable
 
    @Override
 
    public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos) {
 
        return FULL_BLOCK_AABB.expandXyz(-.05d);
 
     }
 
  
     @Override
+
     if (!worldIn.isRemote && !entityIn.isDead) {
    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) {
+
         MinecraftServer server = entityIn.getServer();
         MinecraftServer server = worldIn.getMinecraftServer();
+
         WorldServer destServer = server.worldServerForDimension(destDimension);
         if (server != null) {
 
            PlayerList playerList = server.getPlayerList();
 
            int dest = entityIn.dimension == DimensionType.OVERWORLD.getId() ? SampleMod.SAMPLE_DIMENSION.getId() : DimensionType.OVERWORLD.getId();
 
  
            Teleporter teleporter = new TeleporterSample(server.worldServerForDimension(dest));
+
        Teleporter teleporter = funcTeleporter.apply(destServer);
 +
        Teleporter cache = destServer.worldTeleporter; // Access Transformer | private final -> public
  
            if (entityIn instanceof EntityPlayerMP) {
+
        destServer.worldTeleporter = teleporter;
                playerList.transferPlayerToDimension((EntityPlayerMP) entityIn, dest, teleporter);
+
        T clone = (T) entityIn.changeDimension(destDimension);
            }
+
        callback.accept(clone); // 座標設定等
            else {
 
                int origin = entityIn.dimension;
 
                entityIn.dimension = dest;
 
                worldIn.removeEntityDangerously(entityIn);
 
  
                entityIn.isDead = false;
+
        destServer.worldTeleporter = cache;
  
                playerList.transferEntityToWorld(entityIn, origin, server.worldServerForDimension(origin), server.worldServerForDimension(dest), teleporter);
 
            }
 
        }
 
 
     }
 
     }
 
}
 
}
 
 
</source>
 
</source>

Minecraft Modding Wikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細はMinecraft Modding Wiki:著作権を参照)。 著作権保護されている作品は、許諾なしに投稿しないでください!

このページを編集するには、下記の確認用の質問に回答してください (詳細):

取り消し 編集の仕方 (新しいウィンドウで開きます)