Fix teleport and geteways
This commit is contained in:
parent
368565944a
commit
a991da19cb
3 changed files with 176 additions and 77 deletions
|
@ -2,24 +2,112 @@ package org.dimdev.ddutils;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityList;
|
import net.minecraft.entity.EntityList;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.item.EntityEnderPearl;
|
||||||
|
import net.minecraft.entity.item.EntityItem;
|
||||||
|
import net.minecraft.entity.item.EntityMinecartContainer;
|
||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.entity.projectile.EntityThrowable;
|
||||||
import net.minecraft.network.NetHandlerPlayServer;
|
import net.minecraft.network.NetHandlerPlayServer;
|
||||||
import net.minecraft.network.play.server.*;
|
import net.minecraft.network.play.server.*;
|
||||||
import net.minecraft.potion.PotionEffect;
|
import net.minecraft.potion.PotionEffect;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.WorldProviderEnd;
|
||||||
import net.minecraft.world.WorldServer;
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraft.world.end.DragonFightManager;
|
||||||
import net.minecraftforge.common.ForgeHooks;
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
|
import org.dimdev.dimdoors.DimDoors;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
public final class TeleportUtils {
|
public final class TeleportUtils {
|
||||||
|
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Helper functions">
|
||||||
|
private static final Field invulnerableDimensionChange;
|
||||||
|
private static final Field thrower;
|
||||||
|
private static final Field enteredNetherPosition;
|
||||||
|
private static final Method captureCurrentPosition;
|
||||||
|
private static final Method copyDataFromOld;
|
||||||
|
private static final Method searchForOtherItemsNearby;
|
||||||
|
private static final Method updateplayers;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
invulnerableDimensionChange = MCPReflection.getMCPField(EntityPlayerMP.class, "invulnerableDimensionChange", "field_184851_cj");
|
||||||
|
thrower = MCPReflection.getMCPField(EntityThrowable.class, "thrower", "field_145801_f");
|
||||||
|
enteredNetherPosition = MCPReflection.getMCPField(EntityPlayerMP.class, "enteredNetherPosition", "field_193110_cw");
|
||||||
|
captureCurrentPosition = MCPReflection.getMCPMethod(NetHandlerPlayServer.class, "captureCurrentPosition", "func_184342_d");
|
||||||
|
copyDataFromOld = MCPReflection.getMCPMethod(Entity.class, "copyDataFromOld", "func_180432_n", Entity.class);
|
||||||
|
searchForOtherItemsNearby = MCPReflection.getMCPMethod(EntityItem.class, "searchForOtherItemsNearby", "func_85054_d");
|
||||||
|
updateplayers = MCPReflection.getMCPMethod(DragonFightManager.class, "updateplayers", "func_186100_j");
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setInvulnerableDimensionChange(EntityPlayerMP player, boolean value) {
|
||||||
|
try {
|
||||||
|
invulnerableDimensionChange.set(player, value);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setThrower(EntityThrowable entity, EntityLivingBase value) {
|
||||||
|
try {
|
||||||
|
thrower.set(entity, value);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setEnteredNetherPosition(EntityPlayerMP player, Vec3d value) {
|
||||||
|
try {
|
||||||
|
enteredNetherPosition.set(player, value);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void captureCurrentPosition(NetHandlerPlayServer connection) {
|
||||||
|
try {
|
||||||
|
captureCurrentPosition.invoke(connection);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyDataFromOld(Entity newEntity, Entity oldEntity) {
|
||||||
|
try {
|
||||||
|
copyDataFromOld.invoke(newEntity, oldEntity);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void searchForOtherItemsNearby(EntityItem item) {
|
||||||
|
try {
|
||||||
|
searchForOtherItemsNearby.invoke(item);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateplayers(DragonFightManager dragonFightManager) {
|
||||||
|
try {
|
||||||
|
updateplayers.invoke(dragonFightManager);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Entity teleport(Entity entity, Location location) {
|
public static Entity teleport(Entity entity, Location location) {
|
||||||
return teleport(entity, location, entity.rotationYaw, entity.rotationPitch);
|
return teleport(entity, location, entity.rotationYaw, entity.rotationPitch);
|
||||||
}
|
}
|
||||||
|
@ -36,8 +124,16 @@ public final class TeleportUtils {
|
||||||
return teleport(entity, WorldUtils.getDim(entity.getEntityWorld()), x, y, z, yaw, pitch);
|
return teleport(entity, WorldUtils.getDim(entity.getEntityWorld()), x, y, z, yaw, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// </editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teleports any kind of entity to any dimension, position, and pitch/yaw. Unlike the vanilla code, this doesn't do any
|
||||||
|
* actions such as creating nether portals and end platforms or showing the credits when leaving the end, and ignores the
|
||||||
|
* world moveFactor (ex. 8 in the nether). This code is safe to call from a block collision event.
|
||||||
|
*/
|
||||||
public static Entity teleport(Entity entity, int newDimension, double x, double y, double z, float yaw, float pitch) {
|
public static Entity teleport(Entity entity, int newDimension, double x, double y, double z, float yaw, float pitch) {
|
||||||
if (entity.world.isRemote || !(entity.world instanceof WorldServer) || entity.isDead) return entity; // dead means inactive, not a dead player
|
if (entity instanceof FakePlayer) return entity;
|
||||||
|
if (entity.world.isRemote || entity.isDead) return null; // dead means inactive, not a dead player
|
||||||
|
|
||||||
yaw = MathHelper.wrapDegrees(yaw);
|
yaw = MathHelper.wrapDegrees(yaw);
|
||||||
pitch = MathHelper.wrapDegrees(pitch);
|
pitch = MathHelper.wrapDegrees(pitch);
|
||||||
|
@ -48,88 +144,99 @@ public final class TeleportUtils {
|
||||||
int oldDimension = entity.dimension;
|
int oldDimension = entity.dimension;
|
||||||
// int newDimension = dim;
|
// int newDimension = dim;
|
||||||
|
|
||||||
// Workaround for https://bugs.mojang.com/browse/MC-123364
|
|
||||||
if (entity instanceof EntityPlayerMP) {
|
if (entity instanceof EntityPlayerMP) {
|
||||||
|
// Workaround for https://bugs.mojang.com/browse/MC-123364. Disables player-in-block checking, but doesn't seem
|
||||||
|
// to make the player actually noclip.
|
||||||
entity.noClip = true;
|
entity.noClip = true;
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent Minecraft from cancelling the position change being too big if the player is not in creative
|
// Prevent Minecraft from cancelling the position change being too big if the player is not in creative
|
||||||
// This has to be done when the teleport is done from the player moved function (so any block collision event too)
|
// This has to be done when the teleport is done from the player moved function (so any block collision event too)
|
||||||
if (entity instanceof EntityPlayerMP) {
|
// Not doing this will cause the player to be invisible for others.
|
||||||
EntityPlayerMP player = (EntityPlayerMP) entity;
|
setInvulnerableDimensionChange((EntityPlayerMP) entity, true);
|
||||||
try {
|
|
||||||
Field invulnerableDimensionChange = MCPReflection.getMCPField(EntityPlayerMP.class, "invulnerableDimensionChange", "field_184851_cj");
|
|
||||||
invulnerableDimensionChange.setBoolean(player, true);
|
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldDimension == newDimension) { // Based on CommandTeleport.doTeleport
|
if (oldDimension == newDimension) { // Based on CommandTeleport.doTeleport
|
||||||
if (entity instanceof EntityPlayerMP) {
|
if (entity instanceof EntityPlayerMP) {
|
||||||
EntityPlayerMP player = (EntityPlayerMP) entity;
|
EntityPlayerMP player = (EntityPlayerMP) entity;
|
||||||
player.connection.setPlayerLocation(
|
player.connection.setPlayerLocation(x, y, z, yaw, pitch, EnumSet.noneOf(SPacketPlayerPosLook.EnumFlags.class));
|
||||||
x,
|
// Fix for https://bugs.mojang.com/browse/MC-98153. See this comment: https://bugs.mojang.com/browse/MC-98153#comment-411524
|
||||||
y,
|
captureCurrentPosition(player.connection);
|
||||||
z,
|
|
||||||
yaw,
|
|
||||||
pitch,
|
|
||||||
EnumSet.noneOf(SPacketPlayerPosLook.EnumFlags.class));
|
|
||||||
// https://bugs.mojang.com/browse/MC-98153?focusedCommentId=411524&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-411524
|
|
||||||
try {
|
|
||||||
Method captureCurrentPosition = MCPReflection.getMCPMethod(NetHandlerPlayServer.class, "captureCurrentPosition", "func_184342_d");
|
|
||||||
captureCurrentPosition.invoke(player.connection);
|
|
||||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
entity.setLocationAndAngles(x, y, z, yaw, pitch);
|
entity.setLocationAndAngles(x, y, z, yaw, pitch);
|
||||||
}
|
}
|
||||||
entity.setRotationYawHead(yaw);
|
entity.setRotationYawHead(yaw);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
} else { // Based on EntityUtils.changeDimension
|
} else { // Based on Entity.changeDimension
|
||||||
MinecraftServer server = entity.getServer();
|
MinecraftServer server = entity.getServer();
|
||||||
WorldServer oldServer = server.getWorld(oldDimension);
|
WorldServer oldWorld = server.getWorld(oldDimension);
|
||||||
WorldServer newServer = server.getWorld(newDimension);
|
WorldServer newWorld = server.getWorld(newDimension);
|
||||||
|
|
||||||
// Allow other mods to cancel the event
|
// Allow other mods to cancel the event
|
||||||
if (!ForgeHooks.onTravelToDimension(entity, newDimension)) return entity;
|
if (!ForgeHooks.onTravelToDimension(entity, newDimension)) return entity;
|
||||||
|
|
||||||
if (entity instanceof EntityPlayerMP) {
|
if (entity instanceof EntityPlayerMP) {
|
||||||
EntityPlayerMP player = (EntityPlayerMP) entity;
|
EntityPlayerMP player = (EntityPlayerMP) entity;
|
||||||
// player.enteredNetherPosition = null;
|
|
||||||
|
// Setting this field seems to be useful for advancments. Adjusted dimension checks for non-vanilla
|
||||||
|
// dimension support (entering the nether from any dimension should trigger it now).
|
||||||
|
if (newDimension == -1) {
|
||||||
|
setEnteredNetherPosition(player, new Vec3d(player.posX, player.posY, player.posZ));
|
||||||
|
} else if (oldDimension != -1 && newDimension != 0) {
|
||||||
|
setEnteredNetherPosition(player, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send respawn packets to the player
|
||||||
player.dimension = newDimension;
|
player.dimension = newDimension;
|
||||||
player.connection.sendPacket(new SPacketRespawn(player.dimension, newServer.getDifficulty(), newServer.getWorldInfo().getTerrainType(), player.interactionManager.getGameType()));
|
player.connection.sendPacket(new SPacketRespawn(player.dimension, newWorld.getDifficulty(), newWorld.getWorldInfo().getTerrainType(), player.interactionManager.getGameType()));
|
||||||
|
player.mcServer.getPlayerList().updatePermissionLevel(player); // Sends an SPacketEntityStatus
|
||||||
|
|
||||||
// Remove from old world
|
// Remove player entity from the old world
|
||||||
player.mcServer.getPlayerList().updatePermissionLevel(player);
|
oldWorld.removeEntityDangerously(player);
|
||||||
oldServer.removeEntityDangerously(player);
|
|
||||||
|
// Move the player entity to new world
|
||||||
|
// We can't use PlayerList.transferEntityToWorld since for newDimension = 1, that would first teleport the
|
||||||
|
// player to the dimension's spawn before quickly teleporting the player to the correct position. Unlike the vanilla
|
||||||
|
// code, we don't use the world provider's moveFactor (ex. 8 blocks in the nether) and don't clip to the
|
||||||
|
// world border.
|
||||||
player.isDead = false;
|
player.isDead = false;
|
||||||
|
oldWorld.profiler.startSection("moving");
|
||||||
|
player.setLocationAndAngles(x, y, z, yaw, pitch);
|
||||||
|
// PlayerList.transferEntityToWorld does this for some reason when teleporting to the end, but it doesn't
|
||||||
|
// make any sense:
|
||||||
|
// if (entity.isEntityAlive()) oldWorld.updateEntityWithOptionalForce(entity, false);
|
||||||
|
oldWorld.profiler.endSection();
|
||||||
|
|
||||||
// Move to new world
|
oldWorld.profiler.startSection("placing");
|
||||||
oldServer.profiler.startSection("moving");
|
newWorld.spawnEntity(player);
|
||||||
player.setLocationAndAngles(x, y, z, yaw, pitch); // TODO: clamp to world border or -29999872, 29999872 like in original code?
|
newWorld.updateEntityWithOptionalForce(player, false);
|
||||||
if (entity.isEntityAlive()) oldServer.updateEntityWithOptionalForce(entity, false);
|
oldWorld.profiler.endSection();
|
||||||
oldServer.profiler.endSection();
|
player.setWorld(newWorld);
|
||||||
|
|
||||||
oldServer.profiler.startSection("placing");
|
|
||||||
newServer.spawnEntity(player);
|
|
||||||
newServer.updateEntityWithOptionalForce(player, false);
|
|
||||||
oldServer.profiler.endSection();
|
|
||||||
player.setWorld(newServer);
|
|
||||||
|
|
||||||
// Sync the player
|
// Sync the player
|
||||||
player.mcServer.getPlayerList().preparePlayer(player, oldServer);
|
player.mcServer.getPlayerList().preparePlayer(player, oldWorld);
|
||||||
player.connection.setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
player.connection.setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
|
||||||
player.interactionManager.setWorld(newServer);
|
// Fix for https://bugs.mojang.com/browse/MC-98153. See this comment: https://bugs.mojang.com/browse/MC-98153#comment-411524
|
||||||
|
captureCurrentPosition(player.connection);
|
||||||
|
player.interactionManager.setWorld(newWorld);
|
||||||
player.connection.sendPacket(new SPacketPlayerAbilities(player.capabilities));
|
player.connection.sendPacket(new SPacketPlayerAbilities(player.capabilities));
|
||||||
player.mcServer.getPlayerList().updateTimeAndWeatherForPlayer(player, newServer);
|
player.mcServer.getPlayerList().updateTimeAndWeatherForPlayer(player, newWorld);
|
||||||
player.mcServer.getPlayerList().syncPlayerInventory(player);
|
player.mcServer.getPlayerList().syncPlayerInventory(player);
|
||||||
for (PotionEffect potioneffect : player.getActivePotionEffects()) {
|
for (PotionEffect potioneffect : player.getActivePotionEffects()) {
|
||||||
player.connection.sendPacket(new SPacketEntityEffect(player.getEntityId(), potioneffect));
|
player.connection.sendPacket(new SPacketEntityEffect(player.getEntityId(), potioneffect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force WorldProviderEnd to check if end dragon bars should be removed. Duplicate end dragon bars even
|
||||||
|
// happen when leaving the end using an end portal while the dragon is alive, so this might be a vanilla
|
||||||
|
// or Forge bug (maybe the world is unloaded before checking players?). In vanilla, updateplayers is normally
|
||||||
|
// called every second.
|
||||||
|
if (oldWorld.provider instanceof WorldProviderEnd) {
|
||||||
|
DragonFightManager dragonFightManager = ((WorldProviderEnd) oldWorld.provider).getDragonFightManager();
|
||||||
|
updateplayers(dragonFightManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vanilla also plays SoundEvents.BLOCK_PORTAL_TRAVEL, we won't do this.
|
||||||
|
|
||||||
FMLCommonHandler.instance().firePlayerChangedDimensionEvent(player, oldDimension, newDimension);
|
FMLCommonHandler.instance().firePlayerChangedDimensionEvent(player, oldDimension, newDimension);
|
||||||
|
|
||||||
//player.prevBlockpos = null; // For frost walk. Is this needed? What about other fields?
|
//player.prevBlockpos = null; // For frost walk. Is this needed? What about other fields?
|
||||||
|
@ -139,39 +246,39 @@ public final class TeleportUtils {
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
} else {
|
} else {
|
||||||
|
if (entity instanceof EntityMinecartContainer) ((EntityMinecartContainer) entity).dropContentsWhenDead = false;
|
||||||
|
if (entity instanceof EntityEnderPearl) setThrower((EntityThrowable) entity, null); // Otherwise the player will be teleported to the hit position but in the same dimension
|
||||||
|
|
||||||
entity.world.profiler.startSection("changeDimension");
|
entity.world.profiler.startSection("changeDimension");
|
||||||
entity.dimension = newDimension;
|
entity.dimension = newDimension;
|
||||||
entity.world.removeEntity(entity);
|
entity.world.removeEntity(entity);
|
||||||
entity.isDead = false;
|
entity.isDead = false;
|
||||||
|
|
||||||
entity.world.profiler.startSection("reposition");
|
entity.world.profiler.startSection("reposition");
|
||||||
oldServer.updateEntityWithOptionalForce(entity, false);
|
oldWorld.updateEntityWithOptionalForce(entity, false);
|
||||||
|
|
||||||
entity.world.profiler.endStartSection("reloading");
|
entity.world.profiler.endStartSection("reloading");
|
||||||
Entity newEntity = EntityList.newEntity(entity.getClass(), newServer);
|
Entity newEntity = EntityList.newEntity(entity.getClass(), newWorld);
|
||||||
|
|
||||||
if (newEntity != null) {
|
if (newEntity != null) {
|
||||||
try {
|
copyDataFromOld(newEntity, entity);
|
||||||
Method copyDataFromOld = MCPReflection.getMCPMethod(Entity.class,"copyDataFromOld", "func_180432_n", Entity.class);
|
|
||||||
copyDataFromOld.invoke(newEntity, entity);
|
|
||||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
newEntity.setPositionAndRotation(x, y, z, yaw, pitch);
|
newEntity.setPositionAndRotation(x, y, z, yaw, pitch);
|
||||||
boolean oldForceSpawn = newEntity.forceSpawn;
|
boolean oldForceSpawn = newEntity.forceSpawn;
|
||||||
newEntity.forceSpawn = true;
|
newEntity.forceSpawn = true;
|
||||||
newServer.spawnEntity(newEntity);
|
newWorld.spawnEntity(newEntity);
|
||||||
newEntity.forceSpawn = oldForceSpawn;
|
newEntity.forceSpawn = oldForceSpawn;
|
||||||
newServer.updateEntityWithOptionalForce(newEntity, false);
|
newWorld.updateEntityWithOptionalForce(newEntity, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.isDead = true;
|
entity.isDead = true;
|
||||||
entity.world.profiler.endSection();
|
entity.world.profiler.endSection();
|
||||||
|
|
||||||
oldServer.resetUpdateEntityTick();
|
oldWorld.resetUpdateEntityTick();
|
||||||
newServer.resetUpdateEntityTick();
|
newWorld.resetUpdateEntityTick();
|
||||||
entity.world.profiler.endSection();
|
entity.world.profiler.endSection();
|
||||||
|
|
||||||
|
if (newEntity instanceof EntityItem) searchForOtherItemsNearby((EntityItem) newEntity); // TODO: This isn't in same-dimension teleportation in vanilla, but why?
|
||||||
|
|
||||||
return newEntity;
|
return newEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ public abstract class BlockSpecialAir extends Block {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public EnumBlockRenderType getRenderType(IBlockState state) {
|
public EnumBlockRenderType getRenderType(IBlockState state) {
|
||||||
return EnumBlockRenderType.INVISIBLE; // Tile EntityUtils Special Renderer
|
return EnumBlockRenderType.INVISIBLE; // Tile Entity Special Renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,8 @@ import net.minecraft.block.material.Material;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldProviderEnd;
|
||||||
|
import net.minecraft.world.WorldProviderHell;
|
||||||
import net.minecraft.world.chunk.IChunkProvider;
|
import net.minecraft.world.chunk.IChunkProvider;
|
||||||
import net.minecraft.world.gen.IChunkGenerator;
|
import net.minecraft.world.gen.IChunkGenerator;
|
||||||
import net.minecraftforge.fml.common.IWorldGenerator;
|
import net.minecraftforge.fml.common.IWorldGenerator;
|
||||||
|
@ -16,25 +18,17 @@ import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public class GatewayGenerator implements IWorldGenerator {
|
public class GatewayGenerator implements IWorldGenerator {
|
||||||
public static final int MAX_GATEWAY_GENERATION_CHANCE = 10000;
|
|
||||||
public static final int MAX_CLUSTER_GENERATION_CHANCE = 10000;
|
|
||||||
private static final int CLUSTER_GROWTH_CHANCE = 80;
|
private static final int CLUSTER_GROWTH_CHANCE = 80;
|
||||||
private static final int MAX_CLUSTER_GROWTH_CHANCE = 100;
|
private static final int MAX_CLUSTER_GROWTH_CHANCE = 100;
|
||||||
private static final int MIN_RIFT_Y = 4;
|
private static final int MIN_RIFT_Y = 4;
|
||||||
private static final int MAX_RIFT_Y = 240;
|
private static final int MAX_RIFT_Y = 240;
|
||||||
private static final int CHUNK_LENGTH = 16;
|
private static final int CHUNK_LENGTH = 16;
|
||||||
private static final int MAX_GATEWAY_GENERATION_ATTEMPTS = 10;
|
private static final int MAX_GATEWAY_GENERATION_ATTEMPTS = 10;
|
||||||
private static final int NETHER_DIMENSION_ID = -1;
|
|
||||||
private static final int END_DIMENSION_ID = 1;
|
|
||||||
|
|
||||||
private ArrayList<BaseGateway> gateways;
|
private ArrayList<BaseGateway> gateways;
|
||||||
private BaseGateway defaultGateway;
|
private BaseGateway defaultGateway;
|
||||||
|
|
||||||
public GatewayGenerator() {
|
public GatewayGenerator() {
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize() {
|
|
||||||
gateways = new ArrayList<>();
|
gateways = new ArrayList<>();
|
||||||
defaultGateway = new GatewayTwoPillars();
|
defaultGateway = new GatewayTwoPillars();
|
||||||
|
|
||||||
|
@ -46,10 +40,8 @@ public class GatewayGenerator implements IWorldGenerator {
|
||||||
@Override
|
@Override
|
||||||
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
||||||
// Don't generate rifts or gateways if the current world is a pocket dimension or the world is remote.
|
// Don't generate rifts or gateways if the current world is a pocket dimension or the world is remote.
|
||||||
// Also don't generate anything in the Nether, The End, or in Witchery's Spirit World.
|
// Also don't generate anything in the Nether or The End.
|
||||||
// We only match against Spirit World using hashing to speed up the process a little (hopefully).
|
if (world.isRemote || world.provider instanceof WorldProviderPocket || world.provider instanceof WorldProviderHell || world.provider instanceof WorldProviderEnd) {
|
||||||
int dimensionID = world.provider.getDimension();
|
|
||||||
if (world.isRemote || world.provider instanceof WorldProviderPocket || dimensionID == END_DIMENSION_ID || dimensionID == NETHER_DIMENSION_ID) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +52,7 @@ public class GatewayGenerator implements IWorldGenerator {
|
||||||
// Check if we're allowed to generate rift clusters in this dimension.
|
// Check if we're allowed to generate rift clusters in this dimension.
|
||||||
// If so, randomly decide whether to one.
|
// If so, randomly decide whether to one.
|
||||||
boolean clusterGenerated = false;
|
boolean clusterGenerated = false;
|
||||||
if (Arrays.binarySearch(ModConfig.world.riftClusterDimensionTypeBlacklist, world.provider.getDimensionType().getId()) != -1) {
|
if (Arrays.binarySearch(ModConfig.world.riftClusterDimensionTypeBlacklist, world.provider.getDimensionType().getId()) == -1) {
|
||||||
double clusterGenChance = ModConfig.world.clusterGenerationChance;
|
double clusterGenChance = ModConfig.world.clusterGenerationChance;
|
||||||
while (clusterGenChance > 0.0) {
|
while (clusterGenChance > 0.0) {
|
||||||
if (random.nextDouble() < clusterGenChance) {
|
if (random.nextDouble() < clusterGenChance) {
|
||||||
|
@ -90,7 +82,7 @@ public class GatewayGenerator implements IWorldGenerator {
|
||||||
|
|
||||||
// Check if we can place a Rift Gateway in this dimension, then randomly decide whether to place one.
|
// Check if we can place a Rift Gateway in this dimension, then randomly decide whether to place one.
|
||||||
// This only happens if a rift cluster was NOT generated.
|
// This only happens if a rift cluster was NOT generated.
|
||||||
if (!clusterGenerated && Arrays.binarySearch(ModConfig.world.gatewayDimensionTypeBlacklist, world.provider.getDimensionType().getId()) != -1) {
|
if (!clusterGenerated && Arrays.binarySearch(ModConfig.world.gatewayDimensionTypeBlacklist, world.provider.getDimensionType().getId()) == -1) {
|
||||||
double gatewayGenChance = ModConfig.world.gatewayGenerationChance;
|
double gatewayGenChance = ModConfig.world.gatewayGenerationChance;
|
||||||
while (gatewayGenChance > 0.0) {
|
while (gatewayGenChance > 0.0) {
|
||||||
if (random.nextDouble() < gatewayGenChance) {
|
if (random.nextDouble() < gatewayGenChance) {
|
||||||
|
|
Loading…
Reference in a new issue