このシリーズのまとめはこちら:
umagame.hatenablog.jp
こんばんは。
記事のストックがやばいのでもうすぐ毎日投稿が終わります。多分。
はじめに
今回はディメンションを作ります。
前回:
umagame.hatenablog.jp
ディメンションを作る
ディメンションのクラス
まずはディメンションのクラスをworld/dimensionに作ります。
Dimensionを継承して、メソッド、コンストラクタを追加します。
package com.umagame.dirtmod.world.dimension;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.ChunkGenerator;
public class DimensionDirt extends Dimension{
public DimensionDirt(World p_i225788_1_, DimensionType p_i225788_2_, float p_i225788_3_) {
super(p_i225788_1_, p_i225788_2_, p_i225788_3_);
TODO
}
@Override
public ChunkGenerator<?> createChunkGenerator() {
TODO
return null;
}
@Override
public BlockPos findSpawn(ChunkPos chunkPosIn, boolean checkValid) {
TODO
return null;
}
@Override
public BlockPos findSpawn(int posX, int posZ, boolean checkValid) {
TODO
return null;
}
@Override
public float calculateCelestialAngle(long worldTime, float partialTicks) {
TODO
return 0;
}
@Override
public boolean isSurfaceWorld() {
TODO
return false;
}
@Override
public Vec3d getFogColor(float celestialAngle, float partialTicks) {
TODO
return null;
}
@Override
public boolean canRespawnHere() {
TODO
return false;
}
@Override
public boolean doesXZShowFog(int x, int z) {
TODO
return false;
}
}
とりあえずコンストラクタは3つ目のfloatを0にしておきます。
(この数字についてはよくわかりませんが、通常世界が0、ネザーが0.1、エンドが0になっているので0にしておきます。)
メソッドは上から順に
- チャンクジェネレータ(後ほど作ります)
- スポーン地点(リスポーンできないようにするので、今回はnull)
- CelestialAngle(これはまじでわからない。太陽と月の角度らしいけど、今回は他からコピペします)
- 地上の世界かどうか(今回はtrue)
- 霧の色(今回は通常世界と同じ)
- リスポーンできるかどうか(今回はfalse)
- 霧の有無(ネザーのみtrueです。今回はfalse)
を設定できます。
コードはこんな感じ。
package com.umagame.dirtmod.world.dimension;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.ChunkGenerator;
public class DimensionDirt extends Dimension{
public DimensionDirt(World p_i225788_1_, DimensionType p_i225788_2_) {
super(p_i225788_1_, p_i225788_2_,0.0F);
}
@Override
public ChunkGenerator<?> createChunkGenerator() {
return new DirtChunkGenerator(world, new DirtBiomeProvider(), new DirtGenSettings());
}
@Override
public BlockPos findSpawn(ChunkPos chunkPosIn, boolean checkValid) {
return null;
}
@Override
public BlockPos findSpawn(int posX, int posZ, boolean checkValid) {
return null;
}
@Override
public float calculateCelestialAngle(long worldTime, float partialTicks) {
double d0 = MathHelper.frac((double)worldTime / 24000.0D - 0.25D);
double d1 = 0.5D - Math.cos(d0 * Math.PI) / 2.0D;
return (float)(d0 * 2.0D + d1) / 3.0F;
}
@Override
public boolean isSurfaceWorld() {
return true;
}
@Override
public Vec3d getFogColor(float celestialAngle, float partialTicks) {
float f = MathHelper.cos(celestialAngle * ((float)Math.PI * 2F)) * 2.0F + 0.5F;
f = MathHelper.clamp(f, 0.0F, 1.0F);
float f1 = 0.7529412F;
float f2 = 0.84705883F;
float f3 = 1.0F;
f1 = f1 * (f * 0.94F + 0.06F);
f2 = f2 * (f * 0.94F + 0.06F);
f3 = f3 * (f * 0.91F + 0.09F);
return new Vec3d((double)f1, (double)f2, (double)f3);
}
@Override
public boolean canRespawnHere() {
return false;
}
@Override
public boolean doesXZShowFog(int x, int z) {
return false;
}
}
とりあえずこれでディメンション自体のクラスはOKです。
GenSettingsのクラス
生成の設定のクラスをworld/dimensionに作ります。
このクラスではディメンションの生成の設定をできます。
設定は色々ありますが、とりあえず今回は通常世界でいう石ブロックを圧縮された土ブロックに変えておきます。
詳しくはGenerationSettingsクラスを見てください。
package com.umagame.dirtmod.world.dimension;
import com.umagame.dirtmod.init.DirtModBlocks;
import net.minecraft.block.BlockState;
import net.minecraft.world.gen.GenerationSettings;
public class DirtGenSettings extends GenerationSettings{
@Override
public BlockState getDefaultBlock() {
return DirtModBlocks.SUPER_COMPRESSED_DIRT.getDefaultState();
}
}
チャンクジェネレータのクラス
チャンクジェネレータのクラスをworld/dimensionに作ります。
コードは超難解なので他からコピペします。
package com.umagame.dirtmod.world.dimension;
import net.minecraft.util.Util;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IWorld;
import net.minecraft.world.WorldType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.provider.BiomeProvider;
import net.minecraft.world.gen.NoiseChunkGenerator;
import net.minecraft.world.gen.OctavesNoiseGenerator;
public class DirtChunkGenerator extends NoiseChunkGenerator<DirtGenSettings>{
private static final float[] field_222576_h = Util.make(new float[25], (p_222575_0_) -> {
for (int i = -2; i <= 2; ++i) {
for (int j = -2; j <= 2; ++j) {
float f = 10.0F / MathHelper.sqrt((float) (i * i + j * j) + 0.2F);
p_222575_0_[i + 2 + (j + 2) * 5] = f;
}
}
});
private final OctavesNoiseGenerator depthNoise;
private final boolean isAmplified;
public DirtChunkGenerator(IWorld worldIn, BiomeProvider provider, DirtGenSettings settingsIn) {
super(worldIn, provider, 4, 8, 256, settingsIn, true);
this.randomSeed.skip(2620);
this.depthNoise = new OctavesNoiseGenerator(this.randomSeed, 15, 0);
this.isAmplified = worldIn.getWorldInfo().getGenerator() == WorldType.AMPLIFIED;
}
@Override
protected double[] func_222549_a(int p_222549_1_, int p_222549_2_) {
double[] adouble = new double[2];
float f = 0.0F;
float f1 = 0.0F;
float f2 = 0.0F;
int j = this.getSeaLevel();
float f3 = this.biomeProvider.func_225526_b_(p_222549_1_, j, p_222549_2_).getDepth();
for (int k = -2; k <= 2; ++k) {
for (int l = -2; l <= 2; ++l) {
Biome biome = this.biomeProvider.func_225526_b_(p_222549_1_ + k, j, p_222549_2_ + l);
float f4 = biome.getDepth();
float f5 = biome.getScale();
if (this.isAmplified && f4 > 0.0F) {
f4 = 1.0F + f4 * 2.0F;
f5 = 1.0F + f5 * 4.0F;
}
float f6 = field_222576_h[k + 2 + (l + 2) * 5] / (f4 + 2.0F);
if (biome.getDepth() > f3) {
f6 /= 2.0F;
}
f += f5 * f6;
f1 += f4 * f6;
f2 += f6;
}
}
f = f / f2;
f1 = f1 / f2;
f = f * 0.9F + 0.1F;
f1 = (f1 * 4.0F - 1.0F) / 8.0F;
adouble[0] = (double) f1 + this.getNoiseDepthAt(p_222549_1_, p_222549_2_);
adouble[1] = (double) f;
return adouble;
}
@Override
protected double func_222545_a(double p_222545_1_, double p_222545_3_, int p_222545_5_) {
double d1 = ((double) p_222545_5_ - (8.5D + p_222545_1_ * 8.5D / 8.0D * 4.0D)) * 12.0D * 128.0D / 256.0D
/ p_222545_3_;
if (d1 < 0.0D) {
d1 *= 4.0D;
}
return d1;
}
@Override
protected void func_222548_a(double[] p_222548_1_, int p_222548_2_, int p_222548_3_) {
this.func_222546_a(p_222548_1_, p_222548_2_, p_222548_3_, (double) 684.412F, (double) 684.412F, 8.555149841308594D,
4.277574920654297D, 3, -10);
}
private double getNoiseDepthAt(int noiseX, int noiseZ) {
double d0 = this.depthNoise.func_215462_a((double) (noiseX * 200), 10.0D, (double) (noiseZ * 200), 1.0D, 0.0D, true)
* 65535.0D / 8000.0D;
if (d0 < 0.0D) {
d0 = -d0 * 0.3D;
}
d0 = d0 * 3.0D - 2.0D;
if (d0 < 0.0D) {
d0 = d0 / 28.0D;
} else {
if (d0 > 1.0D) {
d0 = 1.0D;
}
d0 = d0 / 40.0D;
}
return d0;
}
@Override
public int getGroundHeight() {
return 64;
}
@Override
public int getSeaLevel() {
return 63;
}
}
一番下のgetGroundHeightとgetSeaLevelで地面と海の高さを設定できます。
バイオームプロバイダのクラス
バイオームプロバイダのクラスをworld/dimensionに作ります。
このクラスで、ディメンション内のバイオームを指定します。
(今回は一つだけですが、biomeListに複数入れたらディメンションに複数のバイオームが出るようになると思います。多分。)
package com.umagame.dirtmod.world.dimension; import java.util.Set; import com.google.common.collect.ImmutableSet; import com.umagame.dirtmod.init.DirtModBiomes; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.provider.BiomeProvider; public class DirtBiomeProvider extends BiomeProvider{ private static final Set<Biome> biomeList = ImmutableSet.of(DirtModBiomes.DIRT); protected DirtBiomeProvider() { super(biomeList); } @Override public Biome func_225526_b_(int p_225526_1_, int p_225526_2_, int p_225526_3_) { return DirtModBiomes.DIRT; } }
ModDimensionのクラス
最後に、登録をするときに使うModDimensionのクラスを作ります。
ModDimensionを継承して、メソッドの戻り値をディメンションのクラスにします。
コンストラクタにsetRegistryNameを追加して、IDも設定しておきます。
package com.umagame.dirtmod.world.dimension;
import java.util.function.BiFunction;
import net.minecraft.world.World;
import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.dimension.DimensionType;
import net.minecraftforge.common.ModDimension;
public class DirtModDimension extends ModDimension{
public DirtModDimension() {
this.setRegistryName("dirt");
}
@Override
public BiFunction<World, DimensionType, ? extends Dimension> getFactory() {
return DimensionDirt::new;
}
}
ディメンションの登録
initに登録用クラスを作ります。
アイテムなどとは少し違った感じです。
package com.umagame.dirtmod.init;
import com.umagame.dirtmod.main.DirtMod;
import com.umagame.dirtmod.world.dimension.DirtModDimension;
import net.minecraftforge.common.ModDimension;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import net.minecraftforge.registries.ObjectHolder;
@ObjectHolder(DirtMod.MOD_ID)
@EventBusSubscriber(modid = DirtMod.MOD_ID, bus = Bus.MOD)
public class DirtModDimensions {
public static final ModDimension DIRT_DIMENSION = new DirtModDimension();
@SubscribeEvent
public static void onDimensionRegistryEvent(RegistryEvent.Register<ModDimension> event) {
event.getRegistry().register(new DirtModDimension());
}
}
ディメンションの登録はこれだけではだめで、もう一つクラスが必要です。
これから使うかもしれないのでmainに作ります。
正直名前はなんでもいいです。
DIMENSION_TYPE_RLのところにディメンションのIDを入力する必要があるので、忘れないように。
package com.umagame.dirtmod.main;
import com.umagame.dirtmod.init.DirtModDimensions;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.dimension.DimensionType;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.event.world.RegisterDimensionsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
@EventBusSubscriber(modid = DirtMod.MOD_ID, bus=Bus.FORGE)
public class CommonForgeEventHandler {
public static final ResourceLocation DIMENSION_TYPE_RL = new ResourceLocation(DirtMod.MOD_ID, "dirt");
@SubscribeEvent
public static void onRegisterDimensionsEvent(RegisterDimensionsEvent event) {
if (DimensionType.byName(DIMENSION_TYPE_RL) == null){
DimensionManager.registerDimension(DIMENSION_TYPE_RL, DirtModDimensions.DIRT_DIMENSION, null, true);
}
}
}
これでディメンションの追加は完了です。
起動して確認しましょう。
「/forge setdimension @p ディメンションID」でディメンションに移動できます。
石の部分もちゃんと変わっています。
さいごに
今回はここまでです。
今回は書いてる途中に結構バグが出たので、もしかしたらコードに誤りがあるかもしれません。
ディメンションはバイオームと同様に設定が多いので、今回紹介できなかった設定は結構あります。
ではでは。
次回:
umagame.hatenablog.jp