4
1

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 5 years have passed since last update.

Minecraft 1.12.2 生成アルゴリズムが変わってもエンダーアイは最も距離が近いエンド要塞を指す

Last updated at Posted at 2019-02-26

Minecraft攻略日記です。

環境

  • Minecraft 1.12.2 Java Edition
  • forgeSrc-1.12.2-14.23.4.2705

背景

Minecraftの地上世界にはエンドへの要塞(Stronghold)が存在する。

これは世界に限られた箇所にしか存在せず、攻略するにはエンダーアイを投げて探さなければならない。エンダーアイは最寄りのエンド遺跡に向かって飛んでいく。


さて、エンド要塞の個数はバージョン1.9の更新時に、以前の3か所から128か所に増えた。そしてそれらの要塞はリング状の領域に特定の個数ずつ配置されているらしい電子殻

で、その中に The strongholds are generated at roughly equal angles from the center point of the world (for instance, each stronghold in a ring of 3 is in the region of 120 degrees from the others, measured from the origin). なる文で説明される配置で要塞が存在するという。つまり概ね等間隔ということだ。


一方、以下のサイトの図では等間隔ではなく角度もばらばらに存在している。

これは各リングを均等にn個のピースに分割し、各ピースのどこかに要塞がスポーンするということなのだろうと、私は勝手に想像している[要検証]

疑問

まあそれはそうとして、ここで一つ問題が出てくる。エンダーアイは最寄りの(距離的に最短の)遺跡を指すのか?それとも、投げた座標が所属するピースにある遺跡を指すのか?

処理上は明らかに後者の方が楽そうだ。座標をピース位置に変換して要塞座標にすれば求まる。前者だと少なくとも周辺の要塞を数個知らなければいけない。

なお、英語版Wikiではthe nearest strongholdに飛ぶと書いてある。

調査

その謎を究明すべく、エンダーアイの右クリック処理(net.minecraft.item.ItemEnderEye.onItemRightClick)を調べた。そこでは次のようなコードで座標を取得していた。

BlockPos blockpos = ((WorldServer)worldIn).getChunkProvider().getNearestStructurePos(worldIn, "Stronghold", new BlockPos(playerIn), false);

要塞の座標の計算はアイテムのイベントに書かれているのではなく「最寄りの構造物の座標」を返す関数に要塞を指定して取得するようだ。次のメソッドを経由して目的の場所にたどり着いた。

  • net.minecraft.world.gen.ChunkProviderServer.getNearestStructurePos
  • net.minecraft.world.gen.ChunkGeneratorOverworld.getNearestStructurePos

以下が最寄りのエンド要塞の位置を返すメソッドnet.minecraft.world.gen.structure.MapGenStronghold.getNearestStructurePos及び付属のメソッドである。

public BlockPos getNearestStructurePos(World worldIn, BlockPos pos, boolean findUnexplored)
{
    if (!this.ranBiomeCheck) {
        this.generatePositions();
        this.ranBiomeCheck = true;
    }

    BlockPos blockpos = null;
    BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(0, 0, 0);
    double d0 = Double.MAX_VALUE;

    for (ChunkPos chunkpos : this.structureCoords) {
        blockpos$mutableblockpos.setPos((chunkpos.x << 4) + 8, 32, (chunkpos.z << 4) + 8);
        double d1 = blockpos$mutableblockpos.distanceSq(pos);

        if (blockpos == null) {
            blockpos = new BlockPos(blockpos$mutableblockpos);
            d0 = d1;
        } else if (d1 < d0) {
            blockpos = new BlockPos(blockpos$mutableblockpos);
            d0 = d1;
        }
    }

    return blockpos;
}

private void generatePositions()
{
	this.initializeStructureData(this.world);
	int i = 0;
	ObjectIterator lvt_2_1_ = this.structureMap.values().iterator();

	while (lvt_2_1_.hasNext()) {
		StructureStart structurestart = (StructureStart) lvt_2_1_.next();

		if (i < this.structureCoords.length) {
			this.structureCoords[i++] = new ChunkPos(structurestart.getChunkPosX(), structurestart.getChunkPosZ());
		}
	}

	Random random = new Random();
	random.setSeed(this.world.getSeed());
	double d1 = random.nextDouble() * Math.PI * 2.0D;
	int j = 0;
	int k = 0;
	int l = this.structureMap.size();

	if (l < this.structureCoords.length) {
		for (int i1 = 0; i1 < this.structureCoords.length; ++i1) {
			double d0 = 4.0D * this.distance + this.distance * (double) j * 6.0D + (random.nextDouble() - 0.5D) * this.distance * 2.5D;
			int j1 = (int) Math.round(Math.cos(d1) * d0);
			int k1 = (int) Math.round(Math.sin(d1) * d0);
			BlockPos blockpos = this.world.getBiomeProvider().findBiomePosition((j1 << 4) + 8, (k1 << 4) + 8, 112, this.allowedBiomes, random);

			if (blockpos != null) {
				j1 = blockpos.getX() >> 4;
				k1 = blockpos.getZ() >> 4;
			}

			if (i1 >= l) {
				this.structureCoords[i1] = new ChunkPos(j1, k1);
			}

			d1 += (Math.PI * 2D) / (double) this.spread;
			++k;

			if (k == this.spread) {
				++j;
				k = 0;
				this.spread += 2 * this.spread / (j + 1);
				this.spread = Math.min(this.spread, this.structureCoords.length - i1);
				d1 += random.nextDouble() * Math.PI * 2.0D;
			}
		}
	}
}

this.structureCoordsは128要素の配列で、要塞座標列が入っている。未初期化の状態で要塞の座標にアクセスしたときにはじめて計算処理generatePositionsが行われる。getNearestStructurePosを見ると、どう見ても最寄りの要塞を取得しているように見える。

要塞の座標決定部分については今回は行わない(あとでやるかもしれないから資料としてコードを丸上げしておく)。

結果

エンダーアイは、未生成のものも含むワールド中のすべてのエンド要塞の中から最も距離的に近いものを指す

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?