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

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

この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 編集中の文章
258行目: 258行目:
  
 
=== エンティティを転送する ===
 
=== エンティティを転送する ===
Entityの別のディメンションへの転送方法について解説します。バニラ+Forge環境で利用可能な転送用メソッドは二種類あります。
+
Entityの別のディメンションへの転送は、Entity#dimensionを変更したのち、出発地のディメンションに対応するWorldServerからEntityを削除、座標を変更してTeleporterを呼び出し、目的地のディメンションに対応するWorldServerインスタンスを渡してEntityのクローンを作成し、クローンを目的地に強制スポーンさせることで実現しています(Entity#changeDimensionの操作)。
 
 
一つ目の「net.minecraft.entity.Entity#changeDimension」は、ネザーポータル、エンドポータルによるディメンション間移動に使用されています。これは、まずEntity#dimensionを変更したのち、出発地のディメンションに対応するWorldServerからEntityを削除、座標を変更してTeleporterを呼び出し、目的地のディメンションに対応するWorldServerインスタンスを渡してEntityのクローンを作成し、クローンを目的地に強制スポーンさせることでディメンション間移動を実現しています。
 
  
 
クローンのEntity#dimensionはコンストラクタでWorldServerから取得されることになり、最初の代入は無駄にも思えますが、ポータルを生成するTeleporterに渡されるのは最初の(出発地側の)Entityであるため、Teleporter内ではコンストラクタに渡される目的地のWorldServerのディメンションIDとEntity#dimensionは一致することになります(バニラでは転送先はWorldServerから取って判定しているのだが)。
 
クローンの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」を経由して呼ばれています。
+
===== PlayerList#transferEntityToWorldを使用する手法 =====
 
+
(未検証)
<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で再利用します。
+
===== 強引に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を復元する。
  
また注意すべき点として、「PlayerList#transferEntityToWorld」は、出発地のWorldからEntityを削除しません。自分で出発地のWorldに対して「World#removeEntityDangerously」を呼んで、World及びChunkからEntityを削除する必要があります。
+
META-INF/<modid>_at.cfg
 +
<source lang="text">
 +
public-f net.minecraft.world.WorldServer field_85177_Q #worldTeleporter non-final
 +
</source>
  
===== 例:「触れるとディメンションを移動するブロック」を追加する =====
+
2の例。ただし以下の点で不完全。
 +
* エンド以外から転送する場合、ネザーへの転送では座標が1/8倍、オーバーワールドへの転送では座標が8倍される。
 +
** オーバーワールド-ネザー間では望ましいが、追加ディメンションからオーバーワールドに帰還するときTeleporterに渡される座標が狂う。
  
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,
 +
                                                    Consumer<T> callback) {
 +
    entityIn.setPortal(portalPos);
 +
    entityIn.timeUntilPortal = 10; // この2行は不要?
  
import net.minecraft.block.Block;
+
    if (!worldIn.isRemote && !entityIn.isDead) {
import net.minecraft.block.material.Material;
+
        MinecraftServer server = entityIn.getServer();
import net.minecraft.block.state.IBlockState;
+
        WorldServer destServer = server.worldServerForDimension(destDimension);
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;
+
        Teleporter teleporter = funcTeleporter.apply(destServer);
 +
        Teleporter cache = destServer.worldTeleporter; // Access Transformer | private final -> public
  
public class BlockTeleporter extends Block {
+
        destServer.worldTeleporter = teleporter;
 +
        T clone = (T) entityIn.changeDimension(destDimension);
 +
        callback.accept(clone); // 座標設定等
  
    public BlockTeleporter() {
+
         destServer.worldTeleporter = cache;
         super(Material.ROCK);
 
    }
 
  
    @Nullable
 
    @Override
 
    public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos) {
 
        return FULL_BLOCK_AABB.expandXyz(-.05d);
 
    }
 
 
    @Override
 
    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) {
 
        MinecraftServer server = worldIn.getMinecraftServer();
 
        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));
 
 
            if (entityIn instanceof EntityPlayerMP) {
 
                playerList.transferPlayerToDimension((EntityPlayerMP) entityIn, dest, teleporter);
 
            }
 
            else {
 
                int origin = entityIn.dimension;
 
                entityIn.dimension = dest;
 
                worldIn.removeEntityDangerously(entityIn);
 
 
                entityIn.isDead = false;
 
 
                playerList.transferEntityToWorld(entityIn, origin, server.worldServerForDimension(origin), server.worldServerForDimension(dest), teleporter);
 
            }
 
        }
 
 
     }
 
     }
 
}
 
}
 
 
</source>
 
</source>

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

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

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