Fix teleportation

This commit is contained in:
Runemoro 2017-12-18 01:48:58 -05:00
parent 915bc41a08
commit 30e735385f
14 changed files with 76 additions and 32 deletions

View file

@ -45,12 +45,12 @@ public abstract class BlockDimDoorBase extends BlockDoor implements ITileEntityP
if (!(doorState.getBlock() instanceof BlockDoor)) return;
if (doorState.getValue(BlockDoor.OPEN) && entityIn.timeUntilPortal == 0) {
entityIn.timeUntilPortal = 50; // 2.5s
toggleDoor(worldIn, pos, false);
TileEntityEntranceRift rift = getRift(worldIn, pos, state);
if (!rift.teleport(entityIn) && entityIn instanceof EntityPlayer) {
DimDoors.chat((EntityPlayer) entityIn, "Teleporting failed because this entrance has no destinations!");
} else if (rift.isCloseAfterPassThrough()) { // TODO: move logic to TileEntityEntranceRift?
worldIn.destroyBlock(pos, false);
boolean successful = rift.teleport(entityIn);
if (successful)entityIn.timeUntilPortal = 0;
if (successful && entityIn instanceof EntityPlayer) {
if(!state.getValue(POWERED)) toggleDoor(worldIn, pos, false); // TODO: config option playerClosesDoorBehind
if (rift.isCloseAfterPassThrough()) worldIn.destroyBlock(pos, false);
}
}
}

View file

@ -53,7 +53,7 @@ public class PocketCommand extends CommandBase {
Pocket pocket = PocketGenerator.generatePocketFromTemplate(dim, 0, template, new VirtualLocation(0, 0, 0, 0,0));
// TODO: options for linking back/not setting entrance
pocket.setup();
TileEntityRift entrance = (TileEntityRift) player.world.getTileEntity(pocket.getEntrance().getPos());
TileEntityRift entrance = (TileEntityRift) player.world.getTileEntity(pocket.getEntrance().getPos()); // TODO: what about no entrances?
entrance.teleportTo(player);
} else {
DimDoors.chat(player, "You must be in a pocket dimension to use this command!");

View file

@ -12,9 +12,10 @@ public class ItemBlockFabric extends ItemBlock {
public ItemBlockFabric() {
super(ModBlocks.FABRIC);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setMaxDamage(0);
setHasSubtypes(true);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockFabric.ID);
setRegistryName(BlockFabric.ID);
}

View file

@ -17,6 +17,7 @@ public class ItemDimDoor extends ItemDoor {
public ItemDimDoor() {
super(ModBlocks.DIMENSIONAL_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDimDoorIron.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDimDoorIron.ID));
}

View file

@ -17,6 +17,7 @@ public class ItemDimDoorGold extends ItemDoor {
public ItemDimDoorGold() {
super(ModBlocks.GOLD_DIMENSIONAL_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDimDoorGold.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDimDoorGold.ID));
}

View file

@ -17,6 +17,7 @@ public class ItemDimDoorPersonal extends ItemDoor {
public ItemDimDoorPersonal() {
super(ModBlocks.PERSONAL_DIMENSIONAL_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDimDoorPersonal.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDimDoorPersonal.ID));
}

View file

@ -17,6 +17,7 @@ public class ItemDimDoorUnstable extends ItemDoor {
public ItemDimDoorUnstable() {
super(ModBlocks.UNSTABLE_DIMENSIONAL_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDimDoorUnstable.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDimDoorUnstable.ID));
}

View file

@ -17,6 +17,7 @@ public class ItemDimDoorWarp extends ItemDoor {
public ItemDimDoorWarp() {
super(ModBlocks.WARP_DIMENSIONAL_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDimDoorWarp.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDimDoorWarp.ID));
}

View file

@ -11,6 +11,7 @@ public class ItemDoorGold extends ItemDoor {
public ItemDoorGold() {
super(ModBlocks.GOLD_DOOR);
setMaxStackSize(16);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDoorGold.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDoorGold.ID));
}

View file

@ -10,6 +10,7 @@ public class ItemDoorQuartz extends ItemDoor {
public ItemDoorQuartz() {
super(ModBlocks.QUARTZ_DOOR);
setCreativeTab(DimDoors.DIM_DOORS_CREATIVE_TAB);
setUnlocalizedName(BlockDoorQuartz.ID);
setRegistryName(new ResourceLocation(DimDoors.MODID, BlockDoorQuartz.ID));
}

View file

@ -50,6 +50,7 @@ public class Pocket { // TODO: better visibilities
pocket.z = nbt.getInteger("z");
pocket.size = nbt.getInteger("size");
if (nbt.hasKey("virtualLocation")) pocket.virtualLocation = VirtualLocation.readFromNBT(nbt.getCompoundTag("virtualLocation"));
if (nbt.hasKey("entrance")) pocket.entrance = Location.readFromNBT(nbt.getCompoundTag("entrance"));
pocket.playerUUIDs = new ArrayList<>();
NBTTagList playerUUIDsNBT = (NBTTagList) nbt.getTag("playerUUIDs");
@ -73,6 +74,7 @@ public class Pocket { // TODO: better visibilities
nbt.setInteger("z", pocket.z);
nbt.setInteger("size", pocket.size);
if (pocket.virtualLocation != null) nbt.setTag("virtualLocation", pocket.virtualLocation.writeToNBT());
if (pocket.entrance != null) nbt.setTag("entrance", Location.writeToNBT(pocket.entrance));
NBTTagList playerUUIDsNBT = new NBTTagList();
for (int i = 0; i < pocket.playerUUIDs.size(); i++) {
@ -153,6 +155,7 @@ public class Pocket { // TODO: better visibilities
destIterator.remove();
if (index == selectedEntranceIndex) {
entrance = new Location(rift.getWorld(), rift.getPos());
PocketRegistry.getForDim(dimID).markDirty();
List<WeightedRiftDestination> ifDestinations = ((RiftDestination.PocketEntranceDestination) dest).getIfDestinations();
for (WeightedRiftDestination ifDestination : ifDestinations) {
destIterator.add(new WeightedRiftDestination(ifDestination.getDestination(), ifDestination.getWeight() / wdest.getWeight(), ifDestination.getGroup()));
@ -190,7 +193,7 @@ public class Pocket { // TODO: better visibilities
if (dest.getType() == RiftDestination.EnumType.POCKET_EXIT) {
destIterator.remove();
destIterator.add(new WeightedRiftDestination(linkTo.withOldDestination(dest), wdest.getWeight(), wdest.getGroup()));
rift.notifyStateChanged();
rift.markStateChanged();
rift.markDirty();
}
}

View file

@ -209,7 +209,7 @@ public class RiftRegistry extends WorldSavedData {
NBTTagCompound privatePocketEntranceNBT = new NBTTagCompound();
privatePocketEntranceNBT.setString("uuid", privatePocketEntrance.getKey());
privatePocketEntranceNBT.setTag("location", Location.writeToNBT(privatePocketEntrance.getValue()));
riftsNBT.appendTag(privatePocketEntranceNBT);
privatePocketEntrancesNBT.appendTag(privatePocketEntranceNBT);
}
nbt.setTag("privatePocketEntrances", privatePocketEntrancesNBT);
@ -219,7 +219,7 @@ public class RiftRegistry extends WorldSavedData {
NBTTagCompound escapeRiftNBT = new NBTTagCompound();
escapeRiftNBT.setString("uuid", escapeRift.getKey());
escapeRiftNBT.setTag("location", Location.writeToNBT(escapeRift.getValue()));
riftsNBT.appendTag(escapeRiftNBT);
escapeRiftsNBT.appendTag(escapeRiftNBT);
}
nbt.setTag("escapeRifts", escapeRiftsNBT);
@ -313,6 +313,7 @@ public class RiftRegistry extends WorldSavedData {
public void setPrivatePocketEntrance(String playerUUID, Location rift) {
privatePocketEntrances.put(playerUUID, rift);
markDirty();
}
public static Location getEscapeRift(String playerUUID) { // TODO: since this is per-world, move to different registry?
@ -321,6 +322,7 @@ public class RiftRegistry extends WorldSavedData {
public static void setEscapeRift(String playerUUID, Location rift) {
getForDim(0).escapeRifts.put(playerUUID, rift);
getForDim(0).markDirty();
}
public static List<AvailableLinkInfo> getAvailableLinks() { // TODO: cache this

View file

@ -250,7 +250,10 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { /
public boolean teleport(Entity entity) { try { // TODO: return failiure message string rather than boolean
riftStateChanged = false;
if (destinations.size() == 0) return false;
if (destinations.size() == 0) {
if (entity instanceof EntityPlayer) DimDoors.chat((EntityPlayer) entity, "This rift has no destinations!");
return false;
}
Map<WeightedRiftDestination, Float> weightMap = new HashMap<>(); // TODO: cache this, faster implementation of single rift
for (WeightedRiftDestination destination : destinations) {
@ -273,10 +276,10 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { /
destLoc = destinationToLocation(dest);
break;
case NEW_PUBLIC:
Pocket publicPocket = PocketGenerator.generatePublicPocket(virtualLocation != null ? virtualLocation.toBuilder().depth(-1).build() : null); // TODO: random transform
publicPocket.setup();
publicPocket.linkPocketTo(destHere);
destLoc = publicPocket.getEntrance();
Pocket pocket = PocketGenerator.generatePublicPocket(virtualLocation != null ? virtualLocation.toBuilder().depth(-1).build() : null); // TODO: random transform
pocket.setup();
pocket.linkPocketTo(destHere);
destLoc = pocket.getEntrance();
if (destLoc != null) makeDestinationPermanent(weightedDestination, destLoc);
break;
case PRIVATE: // TODO: move logic to PrivatePocketTeleportDestination
@ -286,17 +289,17 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { /
if (uuid != null) {
PocketRegistry privatePocketRegistry = PocketRegistry.getForDim(DimDoorDimensions.getPrivateDimID());
RiftRegistry privateRiftRegistry = RiftRegistry.getForDim(DimDoorDimensions.getPrivateDimID());
Pocket privatePocket = privatePocketRegistry.getPocket(privatePocketRegistry.getPrivatePocketID(uuid));
if (privatePocket == null) { // generate the private pocket and get its entrance
privatePocket = PocketGenerator.generatePrivatePocket(virtualLocation != null ? virtualLocation.toBuilder().depth(-2).build() : null); // set to where the pocket was first created TODO: private pocket deletion
privatePocket.setup();
privatePocketRegistry.setPrivatePocketID(uuid, privatePocket.getId());
destLoc = privatePocket.getEntrance();
/*Pocket*/ pocket = privatePocketRegistry.getPocket(privatePocketRegistry.getPrivatePocketID(uuid));
if (pocket == null) { // generate the private pocket and get its entrance
pocket = PocketGenerator.generatePrivatePocket(virtualLocation != null ? virtualLocation.toBuilder().depth(-2).build() : null); // set to where the pocket was first created TODO: private pocket deletion
pocket.setup();
privatePocketRegistry.setPrivatePocketID(uuid, pocket.getId());
destLoc = pocket.getEntrance();
} else {
destLoc = privateRiftRegistry.getPrivatePocketEntrance(uuid); // get the last used entrance
if (destLoc == null) destLoc = privatePocket.getEntrance(); // if there's none, then set the target to the main entrance
if (destLoc == null) destLoc = pocket.getEntrance(); // if there's none, then set the target to the main entrance
}
privateRiftRegistry.setPrivatePocketEntrance(uuid, null); // forget the last entered entrance
// privateRiftRegistry.setPrivatePocketEntrance(uuid, null); // --forget the last entered entrance-- Actually, remember it. We'll eventually store it only in the rift registry, not in the pocket.
} else {
return false; // TODO: There should be a way to get other entities into your private pocket, though. Add API for other mods.
}
@ -316,7 +319,10 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { /
// TODO: teleport the player to random coordinates based on depth around destLoc
return true;
}
if (destLoc == null) return false; // TODO: The player probably teleported into the dungeon/private pocket and is now trying to escape... What should we do? Limbo?
if (destLoc == null) {
if (entity instanceof EntityPlayer) DimDoors.chat((EntityPlayer) entity, "You tried to escape a pocket or leave your private pocket, but you teleported into it!");
return false; // TODO: limbo?
}
} else {
return false; // Non-player/owned entity tried to escape/leave private pocket
}
@ -440,7 +446,7 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { /
deserializeNBT(tag);
}
public void notifyStateChanged() {
public void markStateChanged() {
riftStateChanged = true;
markDirty();
}

View file

@ -6,11 +6,13 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.play.server.*;
import net.minecraft.potion.PotionEffect;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.fml.common.FMLCommonHandler;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.EnumSet;
@ -29,6 +31,10 @@ public class TeleportUtils {
int oldDimension = entity.dimension;
int newDimension = location.getDimID();
if (entity instanceof EntityPlayerMP) {
entity.noClip = true;
}
if (oldDimension == newDimension) { // Based on CommandTeleport.doTeleport
if (entity instanceof EntityPlayerMP) {
((EntityPlayerMP) entity).connection.setPlayerLocation(
@ -49,25 +55,37 @@ public class TeleportUtils {
WorldServer newServer = server.getWorld(newDimension);
// Allow other mods to cancel the event
if (!ForgeHooks.onTravelToDimension(entity, newDimension)) return entity; // TODO: Original code returns null, but that might be a bug
if (!ForgeHooks.onTravelToDimension(entity, newDimension)) return entity;
if (entity instanceof EntityPlayerMP) {
EntityPlayerMP player = (EntityPlayerMP) entity;
// TODO: set invulnerableDimensionChange like in EntityPlayerMP?
try {
Field invulnerableDimensionChange = EntityPlayerMP.class.getDeclaredField("invulnerableDimensionChange"); // Prevents cancelling the position change in survival. TODO: necessary?
invulnerableDimensionChange.setAccessible(true);
invulnerableDimensionChange.setBoolean(player, true); // without this, there's a chance that the new player position gets cancelled
} catch (NoSuchFieldException|IllegalAccessException e) {
throw new RuntimeException(e);
}
// player.enteredNetherPosition = null;
player.dimension = newDimension;
player.connection.sendPacket(new SPacketRespawn(player.dimension, newServer.getDifficulty(), newServer.getWorldInfo().getTerrainType(), player.interactionManager.getGameType()));
// Remove from old world
player.connection.sendPacket(new SPacketRespawn(player.dimension, newServer.getDifficulty(), newServer.getWorldInfo().getTerrainType(), player.interactionManager.getGameType()));
player.mcServer.getPlayerList().updatePermissionLevel(player);
oldServer.removeEntityDangerously(player);
player.isDead = false;
// Move to new world
player.moveToBlockPosAndAngles(location.getPos(), yaw, pitch);
oldServer.updateEntityWithOptionalForce(entity, false);
player.setWorld(newServer);
newServer.spawnEntity(player); // TODO: necessary?
oldServer.profiler.startSection("moving");
player.moveToBlockPosAndAngles(location.getPos(), yaw, pitch); // TODO: clamp to world border or -29999872, 29999872 like in original code?
if (entity.isEntityAlive()) oldServer.updateEntityWithOptionalForce(entity, false);
oldServer.profiler.endSection();
oldServer.profiler.startSection("placing");
newServer.spawnEntity(player);
newServer.updateEntityWithOptionalForce(player, false);
oldServer.profiler.endSection();
player.setWorld(newServer);
// Sync the player
player.mcServer.getPlayerList().preparePlayer(player, oldServer);
@ -81,6 +99,13 @@ public class TeleportUtils {
}
FMLCommonHandler.instance().firePlayerChangedDimensionEvent(player, oldDimension, newDimension);
player.connection.sendPacket(new SPacketEffect(1032, BlockPos.ORIGIN, 0, false));
//player.prevBlockpos = null; // For frost walk. Is this needed? What about other fields?
/*player.lastExperience = -1;
player.lastHealth = -1.0F;
player.lastFoodLevel = -1;*/
return entity;
} else {
entity.world.profiler.startSection("changeDimension");