From 07d6e486474cd4ec2a689f54e2a686fe731d1d04 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Tue, 26 Dec 2017 04:17:24 -0500 Subject: [PATCH] Fixes to teleportation logic --- .../java/com/zixiken/dimdoors/DimDoors.java | 5 +- .../com/zixiken/dimdoors/shared/DDConfig.java | 3 - .../zixiken/dimdoors/shared/EventHandler.java | 24 +++--- .../dimdoors/shared/VirtualLocation.java | 15 ++++ .../blocks/BlockDimensionalDoorPersonal.java | 2 +- .../blocks/BlockDimensionalDoorTransient.java | 2 +- .../dimdoors/shared/pockets/Pocket.java | 6 +- .../shared/pockets/PocketRegistry.java | 14 ++- .../shared/rifts/EscapeDestination.java | 24 ++++-- .../shared/rifts/LimboDestination.java | 5 +- .../shared/rifts/NewPublicDestination.java | 2 +- .../rifts/PocketEntranceDestination.java | 2 +- .../shared/rifts/PrivateDestination.java | 17 ++-- .../rifts/PrivatePocketExitDestination.java | 34 ++++++-- .../dimdoors/shared/rifts/RiftRegistry.java | 85 +++++++++++++++++-- .../dimdoors/shared/rifts/TileEntityRift.java | 6 +- .../tools/PocketSchematicGenerator.java | 11 ++- .../limbodimension/WorldProviderLimbo.java | 7 +- src/main/java/ddutils/Location.java | 2 +- src/main/java/ddutils/nbt/NBTUtils.java | 12 ++- 20 files changed, 209 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/zixiken/dimdoors/DimDoors.java b/src/main/java/com/zixiken/dimdoors/DimDoors.java index 235d6ba0..dddb109c 100644 --- a/src/main/java/com/zixiken/dimdoors/DimDoors.java +++ b/src/main/java/com/zixiken/dimdoors/DimDoors.java @@ -8,6 +8,7 @@ import com.zixiken.dimdoors.shared.items.ModItems; import com.zixiken.dimdoors.shared.world.gateways.GatewayGenerator; import lombok.Getter; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.text.TextComponentString; @@ -78,7 +79,7 @@ public class DimDoors { return !isClient(); } - public static void chat(EntityPlayer player, String text) { - player.sendMessage(new TextComponentString("[DimDoors] " + text)); + public static void chat(Entity entity, String text) { + entity.sendMessage(new TextComponentString("[DimDoors] " + text)); } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java b/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java index 81ffde1b..64bc29af 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java +++ b/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java @@ -12,13 +12,10 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import scala.actors.threadpool.Arrays; /** - * * @author Robijnvogel */ public final class DDConfig { - public static final boolean HAVE_CONFIG_DEFAULTS_BEEN_CHECKED_FOR_CORRECTNESS = false; //@todo check this at each non-alpha release. This field does not have a use in the mod itself, but should ensure that the developers of this mod, don't forget to resetToConfigDefaults the config defaults to the right values before releasing a non-alpha release - public static File configurationFolder; @Getter private static int pocketGridSize = 32; @Getter private static int maxPocketSize = 15; diff --git a/src/main/java/com/zixiken/dimdoors/shared/EventHandler.java b/src/main/java/com/zixiken/dimdoors/shared/EventHandler.java index e62c69df..89f8cd9d 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/EventHandler.java +++ b/src/main/java/com/zixiken/dimdoors/shared/EventHandler.java @@ -2,32 +2,21 @@ package com.zixiken.dimdoors.shared; import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.shared.pockets.PocketRegistry; +import com.zixiken.dimdoors.shared.rifts.RiftRegistry; import com.zixiken.dimdoors.shared.world.DimDoorDimensions; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.DamageSource; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityEvent; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; public final class EventHandler { - @SubscribeEvent - public static void onPlayerJoinWorld(EntityJoinWorldEvent event) { - Entity entity = event.getEntity(); - if(entity instanceof EntityPlayer && !entity.world.isRemote) { // check that it's a player first to avoid calling String.contains for every entity - if (!DDConfig.HAVE_CONFIG_DEFAULTS_BEEN_CHECKED_FOR_CORRECTNESS && !DimDoors.VERSION.contains("a")) { // default values were not checked in non-alpha version - EntityPlayer player = (EntityPlayer) entity; - DimDoors.chat(player, "The default values for the config files for this non-alpha version of DimDoors have not been sufficiently checked on correctness. Please notify the developer about this ONLY IF no newer version of this mod is available."); - } - } - } - - @SubscribeEvent(priority = EventPriority.LOWEST) // don't let other mods do something based on the event + @SubscribeEvent(priority = EventPriority.HIGHEST) // don't let other mods do something based on the event public static void onLivingHurt(LivingHurtEvent event) { Entity entity = event.getEntity(); if (entity.dimension == DimDoorDimensions.limbo.getId() && event.getSource() == DamageSource.FALL) { @@ -50,4 +39,11 @@ public final class EventHandler { } } } + + @SubscribeEvent(priority=EventPriority.LOWEST) + public static void onDimensionChange(PlayerEvent.PlayerChangedDimensionEvent event) { + if (DimDoorDimensions.isPocketDimension(event.fromDim) && !DimDoorDimensions.isPocketDimension(event.toDim)) { + RiftRegistry.setOverworldRift(event.player.getCachedUniqueIdString(), null); + } + } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/VirtualLocation.java b/src/main/java/com/zixiken/dimdoors/shared/VirtualLocation.java index 8b08c793..3529b499 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/VirtualLocation.java +++ b/src/main/java/com/zixiken/dimdoors/shared/VirtualLocation.java @@ -68,6 +68,7 @@ public class VirtualLocation { // TODO: use BlockPos/Location return virtualLocation; } + // TODO: world-seed based transformations and pocket selections? public VirtualLocation transformDepth(int depth) { // TODO: Config option for block ratio between depths (see video of removed features) Random random = new Random(); int depthDiff = Math.abs(this.depth - depth); @@ -78,6 +79,20 @@ public class VirtualLocation { // TODO: use BlockPos/Location return new VirtualLocation(getDim(), getPos().offset(EnumFacing.EAST, xOffset).offset(EnumFacing.SOUTH, zOffset), depth); } + public VirtualLocation randomTransformDepth() { + float r = new Random().nextFloat(); + int newDepth; + if (r > 0.9) { // TODO: per-rift probabilities + newDepth = depth - 1; + } else if (r > 0.75) { + newDepth = depth; + } else { + newDepth = depth + 1; + } + if (newDepth < 1) newDepth = 1; + return transformDepth(newDepth); + } + public Location projectToWorld() { return transformDepth(0).location; } diff --git a/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorPersonal.java b/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorPersonal.java index 9b25f976..6b7e15b9 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorPersonal.java +++ b/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorPersonal.java @@ -33,7 +33,7 @@ public class BlockDimensionalDoorPersonal extends BlockDimensionalDoor { if (rift.getWorld().provider instanceof WorldProviderPersonalPocket) { destination = PrivatePocketExitDestination.builder().build(); // exit } else { - destination = PrivateDestination.builder().build(); // entrance + destination = PrivateDestination.builder().build(); // entrances } rift.setSingleDestination(destination); rift.setChaosWeight(0); // TODO: generated schematic exits too diff --git a/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorTransient.java b/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorTransient.java index 297983ff..ad6e1049 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorTransient.java +++ b/src/main/java/com/zixiken/dimdoors/shared/blocks/BlockDimensionalDoorTransient.java @@ -6,7 +6,7 @@ import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; -public class BlockDimensionalDoorTransient extends BlockDimensionalDoor { // TODO: convert to a more general entrance block (like nether portals) +public class BlockDimensionalDoorTransient extends BlockDimensionalDoor { // TODO: convert to a more general entrances block (like nether portals) public static final String ID = "transient_dimensional_door"; diff --git a/src/main/java/com/zixiken/dimdoors/shared/pockets/Pocket.java b/src/main/java/com/zixiken/dimdoors/shared/pockets/Pocket.java index 856675ef..81307ba9 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/pockets/Pocket.java +++ b/src/main/java/com/zixiken/dimdoors/shared/pockets/Pocket.java @@ -21,7 +21,7 @@ public class Pocket { // TODO: better visibilities @Getter private int z; // Grid y @Getter @Setter private int size; // In chunks TODO: non chunk-based size, better bounds such as minX, minZ, maxX, maxZ, etc. @Getter @Setter private VirtualLocation virtualLocation; // The non-pocket dimension from which this dungeon was created - @Getter @Setter Location entrance; // TODO: multiple entrances + @Getter @Setter Location entrance; @Getter List riftLocations; @Getter int dimID; // Not saved @@ -161,7 +161,9 @@ public class Pocket { // TODO: better visibilities if (dest instanceof PocketExitDestination) { destIterator.remove(); destIterator.add(new WeightedRiftDestination(linkTo, wdest.getWeight(), wdest.getGroup(), dest)); - if (rift instanceof TileEntityEntranceRift) ((TileEntityEntranceRift) rift).setPlaceRiftOnBreak(true); + if (rift instanceof TileEntityEntranceRift && !rift.isAlwaysDelete()) { + ((TileEntityEntranceRift) rift).setPlaceRiftOnBreak(true); // We modified the door's state + } rift.markDirty(); } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/pockets/PocketRegistry.java b/src/main/java/com/zixiken/dimdoors/shared/pockets/PocketRegistry.java index efc223a8..e66489f4 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/pockets/PocketRegistry.java +++ b/src/main/java/com/zixiken/dimdoors/shared/pockets/PocketRegistry.java @@ -1,5 +1,7 @@ package com.zixiken.dimdoors.shared.pockets; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.zixiken.dimdoors.shared.DDConfig; import ddutils.math.GridUtils; import com.zixiken.dimdoors.DimDoors; @@ -19,7 +21,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.storage.MapStorage; import net.minecraft.world.storage.WorldSavedData; -public class PocketRegistry extends WorldSavedData { +public class PocketRegistry extends WorldSavedData { // TODO: unregister pocket entrances, private pocket entrances/exits private static final String DATA_NAME = DimDoors.MODID + "_pockets"; @Getter private static final int DATA_VERSION = 0; // IMPORTANT: Update this and upgradeRegistry when making changes. @@ -28,7 +30,7 @@ public class PocketRegistry extends WorldSavedData { @Getter private int maxPocketSize; @Getter private int privatePocketSize; @Getter private int publicPocketSize; - private Map privatePocketMap; // Player UUID -> Pocket ID, in pocket dim only + private BiMap privatePocketMap; // Player UUID -> Pocket ID, in pocket dim only @Getter private Map pockets; // TODO: remove getter? @Getter private int nextID; @@ -66,7 +68,7 @@ public class PocketRegistry extends WorldSavedData { nextID = 0; pockets = new HashMap<>(); - privatePocketMap = new HashMap<>(); + privatePocketMap = HashBiMap.create(); } @Override @@ -85,7 +87,7 @@ public class PocketRegistry extends WorldSavedData { maxPocketSize = nbt.getInteger("maxPocketSize"); privatePocketSize = nbt.getInteger("privatePocketSize"); publicPocketSize = nbt.getInteger("publicPocketSize"); - privatePocketMap = NBTUtils.readMapStringInteger(nbt.getCompoundTag("privatePocketMap")); + privatePocketMap = NBTUtils.readBiMapStringInteger(nbt.getCompoundTag("privatePocketMap")); nextID = nbt.getInteger("nextID"); pockets = new HashMap<>(); @@ -189,6 +191,10 @@ public class PocketRegistry extends WorldSavedData { return id; } + public String getPrivatePocketOwner(int id) { + return privatePocketMap.inverse().get(id); + } + public void setPrivatePocketID(String playerUUID, int id) { privatePocketMap.put(playerUUID, id); markDirty(); diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/EscapeDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/EscapeDestination.java index b9e97375..130665bf 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/EscapeDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/EscapeDestination.java @@ -1,7 +1,10 @@ package com.zixiken.dimdoors.shared.rifts; -import ddutils.EntityUtils; +import com.zixiken.dimdoors.DimDoors; +import com.zixiken.dimdoors.shared.VirtualLocation; +import com.zixiken.dimdoors.shared.world.limbodimension.WorldProviderLimbo; import ddutils.Location; +import ddutils.TeleportUtils; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -25,14 +28,23 @@ public class EscapeDestination extends RiftDestination { @Override public boolean teleport(TileEntityRift rift, Entity entity) { - String uuid = EntityUtils.getEntityOwnerUUID(entity); + String uuid = entity.getCachedUniqueIdString(); if (uuid != null) { Location destLoc = RiftRegistry.getOverworldRift(uuid); - RiftRegistry.setOverworldRift(uuid, null); // forget the last used escape rift - // TODO: teleport the player to random coordinates based on depth around destLoc - return true; + if (destLoc != null && destLoc.getTileEntity() instanceof TileEntityRift) { + TeleportUtils.teleport(entity, new VirtualLocation(destLoc, rift.virtualLocation.getDepth()).projectToWorld()); // TODO + return true; + } else { + if (destLoc == null) { + DimDoors.chat(entity, "You didn't use a rift to enter so you ended up in Limbo!"); // TODO: better messages, localization + } else { + DimDoors.chat(entity, "The rift you used to enter has closed so you ended up in Limbo!"); + } + TeleportUtils.teleport(entity, WorldProviderLimbo.getLimboSkySpawn(entity)); // TODO: do we really want to spam limbo with items? + return true; + } } else { - return false; // Non-player/owned entity tried to escape/leave private pocket + return false; // No escape info for that entity } } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/LimboDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/LimboDestination.java index 8844012a..59ac0756 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/LimboDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/LimboDestination.java @@ -1,5 +1,7 @@ package com.zixiken.dimdoors.shared.rifts; +import com.zixiken.dimdoors.shared.world.limbodimension.WorldProviderLimbo; +import ddutils.TeleportUtils; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -23,6 +25,7 @@ public class LimboDestination extends RiftDestination { @Override public boolean teleport(TileEntityRift rift, Entity entity) { - throw new RuntimeException("Not yet implemented!"); + TeleportUtils.teleport(entity, WorldProviderLimbo.getLimboSkySpawn(entity)); // TODO: do we really want to spam Limbo with items? + return false; } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/NewPublicDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/NewPublicDestination.java index f7ed2667..bf3d8b48 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/NewPublicDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/NewPublicDestination.java @@ -25,7 +25,7 @@ public class NewPublicDestination extends RiftDestination { // TODO: more config @Override public boolean teleport(TileEntityRift rift, Entity entity) { - Pocket pocket = PocketGenerator.generatePublicPocket(rift.virtualLocation != null ? rift.virtualLocation.toBuilder().depth(-1).build() : null); // TODO: random transform + Pocket pocket = PocketGenerator.generatePublicPocket(rift.virtualLocation != null ? rift.virtualLocation.randomTransformDepth() : null); // TODO: random transform pocket.setup(); pocket.linkPocketTo(new GlobalDestination(rift.getLocation())); rift.makeDestinationPermanent(weightedDestination, pocket.getEntrance()); diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/PocketEntranceDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/PocketEntranceDestination.java index 52587509..0b9d87af 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/PocketEntranceDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/PocketEntranceDestination.java @@ -65,7 +65,7 @@ public class PocketEntranceDestination extends RiftDestination { @Override public boolean teleport(TileEntityRift rift, Entity entity) { - if (entity instanceof EntityPlayer) DimDoors.chat((EntityPlayer) entity, "The entrance of this dungeon has not been linked. Either this is a bug or you are in dungeon-building mode."); + if (entity instanceof EntityPlayer) DimDoors.chat((EntityPlayer) entity, "The entrances of this dungeon has not been linked. Either this is a bug or you are in dungeon-building mode."); return false; } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivateDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivateDestination.java index 4cbc38d6..4924a6cb 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivateDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivateDestination.java @@ -1,5 +1,6 @@ package com.zixiken.dimdoors.shared.rifts; +import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.shared.pockets.Pocket; import com.zixiken.dimdoors.shared.pockets.PocketGenerator; import com.zixiken.dimdoors.shared.pockets.PocketRegistry; @@ -35,25 +36,27 @@ public class PrivateDestination extends RiftDestination { PocketRegistry privatePocketRegistry = PocketRegistry.getForDim(DimDoorDimensions.getPrivateDimID()); RiftRegistry privateRiftRegistry = RiftRegistry.getForDim(DimDoorDimensions.getPrivateDimID()); Pocket pocket = privatePocketRegistry.getPocket(privatePocketRegistry.getPrivatePocketID(uuid)); - if (pocket == null) { // generate the private pocket and get its entrance // TODO: use VirtualLocation.fromLoc vvv - pocket = PocketGenerator.generatePrivatePocket(rift.virtualLocation != null ? rift.virtualLocation.toBuilder().depth(-2).build() : null); // set to where the pocket was first created + if (pocket == null) { // generate the private pocket and get its entrances + pocket = PocketGenerator.generatePrivatePocket(rift.virtualLocation != null ? rift.virtualLocation.toBuilder().depth(-1).build() : null); // set to where the pocket was first created pocket.setup(); privatePocketRegistry.setPrivatePocketID(uuid, pocket.getId()); ((TileEntityRift) pocket.getEntrance().getTileEntity()).teleportTo(entity); + privateRiftRegistry.setPrivatePocketExit(uuid, rift.getLocation()); return true; } else { - Location destLoc = privateRiftRegistry.getPrivatePocketEntrance(uuid); // get the last used entrance - if (destLoc == null) destLoc = pocket.getEntrance(); // if there's none, then set the target to the main entrance - if (destLoc == null) { // if the pocket entrance is gone, then create a new private pocket - pocket = PocketGenerator.generatePrivatePocket(rift.virtualLocation != null ? rift.virtualLocation.toBuilder().depth(-2).build() : null); + Location destLoc = privateRiftRegistry.getPrivatePocketEntrance(uuid); // get the last used entrances + if (destLoc == null) destLoc = pocket.getEntrance(); // if there's none, then set the target to the main entrances + if (destLoc == null) { // if the pocket entrances is gone, then create a new private pocket + DimDoors.log.info("All entrances are gone, creating a new private pocket!"); + pocket = PocketGenerator.generatePrivatePocket(rift.virtualLocation != null ? rift.virtualLocation.toBuilder().depth(-1).build() : null); pocket.setup(); privatePocketRegistry.setPrivatePocketID(uuid, pocket.getId()); destLoc = pocket.getEntrance(); } ((TileEntityRift) destLoc.getTileEntity()).teleportTo(entity); + privateRiftRegistry.setPrivatePocketExit(uuid, rift.getLocation()); return true; } - // 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. } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivatePocketExitDestination.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivatePocketExitDestination.java index c4e1fb38..17b847f0 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivatePocketExitDestination.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/PrivatePocketExitDestination.java @@ -1,11 +1,14 @@ package com.zixiken.dimdoors.shared.rifts; import com.zixiken.dimdoors.DimDoors; +import com.zixiken.dimdoors.shared.pockets.Pocket; import com.zixiken.dimdoors.shared.pockets.PocketRegistry; import com.zixiken.dimdoors.shared.world.DimDoorDimensions; +import com.zixiken.dimdoors.shared.world.limbodimension.WorldProviderLimbo; import com.zixiken.dimdoors.shared.world.pocketdimension.WorldProviderPersonalPocket; import ddutils.EntityUtils; import ddutils.Location; +import ddutils.TeleportUtils; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -29,25 +32,42 @@ public class PrivatePocketExitDestination extends RiftDestination { // TODO: mer } @Override - public boolean teleport(TileEntityRift rift, Entity entity) { // TODO: don't use overworld rift, use last used entrance rift + public boolean teleport(TileEntityRift rift, Entity entity) { Location destLoc; String uuid = EntityUtils.getEntityOwnerUUID(entity); if (uuid != null) { PocketRegistry privatePocketRegistry = PocketRegistry.getForDim(DimDoorDimensions.getPrivateDimID()); RiftRegistry privateRiftRegistry = RiftRegistry.getForDim(DimDoorDimensions.getPrivateDimID()); - destLoc = RiftRegistry.getOverworldRift(uuid); - RiftRegistry.setOverworldRift(uuid, null); // forget the last used overworld rift TODO: move this on dimension change event + destLoc = privateRiftRegistry.getPrivatePocketExit(uuid); if (rift.getWorld().provider instanceof WorldProviderPersonalPocket && privatePocketRegistry.getPrivatePocketID(uuid) == privatePocketRegistry.posToID(rift.getPos())) { privateRiftRegistry.setPrivatePocketEntrance(uuid, rift.getLocation()); // Remember which exit was used for next time the pocket is entered } if (destLoc == null || !(destLoc.getTileEntity() instanceof TileEntityRift)) { - if (entity instanceof EntityPlayer) DimDoors.chat((EntityPlayer) entity, "Either you did not enter using a rift or the rift you entered through no longer exists!"); - return false; // TODO: send to limbo + if (destLoc == null) { + DimDoors.chat(entity, "You did not use a rift to enter this pocket so you ended up in limbo!"); + } else { + DimDoors.chat(entity, "The rift you entered through no longer exists so you ended up in limbo!"); + } + TeleportUtils.teleport(entity, WorldProviderLimbo.getLimboSkySpawn(entity)); + return false; + } else { + ((TileEntityRift) destLoc.getTileEntity()).teleportTo(entity); + return true; } } else { return false; // Non-player/owned entity tried to escape/leave private pocket } - ((TileEntityRift) destLoc.getTileEntity()).teleportTo(entity); - return true; } + + @Override + public void register(TileEntityRift rift) { + PocketRegistry privatePocketRegistry = PocketRegistry.getForDim(rift.getLocation().getDim()); + Pocket pocket = privatePocketRegistry.getPocketAt(rift.getPos()); + String uuid = privatePocketRegistry.getPrivatePocketOwner(pocket.getId()); + if (uuid != null) { + RiftRegistry.getForDim(DimDoorDimensions.getPrivateDimID()).addPrivatePocketEntrance(uuid, rift.getLocation()); + } + } + + // TODO: unregister } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/RiftRegistry.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/RiftRegistry.java index 1594f0fa..490594d9 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/RiftRegistry.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/RiftRegistry.java @@ -27,7 +27,9 @@ public class RiftRegistry extends WorldSavedData { @Getter private static final int DATA_VERSION = 0; // IMPORTANT: Update this and upgradeRegistry when making changes. @Getter private final Map rifts = new HashMap<>(); // TODO: store relative locations too (better location class supporting relative, etc) - @Getter private final Map privatePocketEntrances = new HashMap<>(); // TODO: more general group-group linking + @Getter private final Map privatePocketEntrances = new HashMap<>(); // Player UUID -> last rift used to exit pocket TODO: split into PrivatePocketRiftRegistry subclass + @Getter private final Map> privatePocketEntranceLists = new HashMap<>(); // Player UUID -> private pocket entrances TODO: split into PrivatePocketRiftRegistry subclass + @Getter private final Map privatePocketExits = new HashMap<>(); // Player UUID -> last rift used to enter pocket @Getter private final Map overworldRifts = new HashMap<>(); @Getter private int dim; @@ -168,6 +170,26 @@ public class RiftRegistry extends WorldSavedData { Location rift = Location.readFromNBT(privatePocketEntranceNBTC.getCompoundTag("location")); privatePocketEntrances.put(uuid, rift); } + + NBTTagList privatePocketEntranceListsNBT = (NBTTagList) nbt.getTag("privatePocketEntranceLists"); + for (NBTBase privatePocketEntranceListNBT : privatePocketEntranceListsNBT) { // TODO: move to NBTUtils + NBTTagCompound privatePocketEntranceListNBTC = (NBTTagCompound) privatePocketEntranceListNBT; + String uuid = privatePocketEntranceListNBTC.getString("uuid"); + NBTTagList entrancesNBT = (NBTTagList) privatePocketEntranceListNBTC.getTag("locationList"); + for (NBTBase entranceNBT : entrancesNBT) { + NBTTagCompound entranceNBTC = (NBTTagCompound) entranceNBT; + Location rift = Location.readFromNBT(entranceNBTC); + privatePocketEntranceLists.get(uuid).add(rift); + } + } + + NBTTagList privatePocketExitsNBT = (NBTTagList) nbt.getTag("privatePocketExits"); + for (NBTBase privatePocketExitNBT : privatePocketExitsNBT) { // TODO: move to NBTUtils + NBTTagCompound privatePocketExitNBTC = (NBTTagCompound) privatePocketExitNBT; + String uuid = privatePocketExitNBTC.getString("uuid"); + Location rift = Location.readFromNBT(privatePocketExitNBTC.getCompoundTag("location")); + privatePocketExits.put(uuid, rift); + } NBTTagList overworldRiftsNBT = (NBTTagList) nbt.getTag("overworldRifts"); for (NBTBase overworldRiftNBT : overworldRiftsNBT) { // TODO: move to NBTUtils @@ -178,8 +200,7 @@ public class RiftRegistry extends WorldSavedData { } } - @SuppressWarnings("unused") - private static boolean upgradeRegistry(NBTTagCompound nbt, int oldVersion) { + private static boolean upgradeRegistry(@SuppressWarnings("unused") NBTTagCompound nbt, int oldVersion) { if (oldVersion > DATA_VERSION) throw new RuntimeException("Upgrade the mod!"); // TODO: better exceptions switch (oldVersion) { case -1: // No version tag @@ -217,7 +238,31 @@ public class RiftRegistry extends WorldSavedData { privatePocketEntrancesNBT.appendTag(privatePocketEntranceNBT); } nbt.setTag("privatePocketEntrances", privatePocketEntrancesNBT); - + + NBTTagList privatePocketEntranceListsNBT = new NBTTagList(); + for (HashMap.Entry> privatePocketEntranceList : privatePocketEntranceLists.entrySet()) { // TODO: move to NBTUtils + if (privatePocketEntranceList.getValue() == null) continue; + NBTTagCompound privatePocketEntranceListNBT = new NBTTagCompound(); + privatePocketEntranceListNBT.setString("uuid", privatePocketEntranceList.getKey()); + NBTTagList entranceListNBT = new NBTTagList(); + for (Location entrance : privatePocketEntranceList.getValue()) { + entranceListNBT.appendTag(Location.writeToNBT(entrance)); + } + privatePocketEntranceListNBT.setTag("locationList", entranceListNBT); + privatePocketEntranceListsNBT.appendTag(privatePocketEntranceListNBT); + } + nbt.setTag("privatePocketEntranceLists", privatePocketEntranceListsNBT); + + NBTTagList privatePocketExitsNBT = new NBTTagList(); + for (HashMap.Entry privatePocketExit : privatePocketExits.entrySet()) { // TODO: move to NBTUtils + if (privatePocketExit.getValue() == null) continue; + NBTTagCompound privatePocketExitNBT = new NBTTagCompound(); + privatePocketExitNBT.setString("uuid", privatePocketExit.getKey()); + privatePocketExitNBT.setTag("location", Location.writeToNBT(privatePocketExit.getValue())); + privatePocketExitsNBT.appendTag(privatePocketExitNBT); + } + nbt.setTag("privatePocketExits", privatePocketExitsNBT); + NBTTagList overworldRiftsNBT = new NBTTagList(); for (HashMap.Entry overworldRift : overworldRifts.entrySet()) { if (overworldRift.getValue() == null) continue; @@ -315,7 +360,18 @@ public class RiftRegistry extends WorldSavedData { } public Location getPrivatePocketEntrance(String playerUUID) { - return privatePocketEntrances.get(playerUUID); + Location entrance = privatePocketEntrances.get(playerUUID); + List entrances = privatePocketEntranceLists.computeIfAbsent(playerUUID, k -> new ArrayList<>()); + while ((entrance == null || !(entrance.getTileEntity() instanceof TileEntityRift)) && entrances.size() > 0) { + if (entrance != null) entrances.remove(entrance); + entrance = entrances.get(0); + } + privatePocketEntrances.put(playerUUID, entrance); + return entrance; + } + + public void addPrivatePocketEntrance(String playerUUID, Location rift) { + privatePocketEntranceLists.computeIfAbsent(playerUUID, k -> new ArrayList<>()).add(rift); } public void setPrivatePocketEntrance(String playerUUID, Location rift) { @@ -323,12 +379,29 @@ public class RiftRegistry extends WorldSavedData { markDirty(); } + public Location getPrivatePocketExit(String playerUUID) { + return privatePocketExits.get(playerUUID); + } + + public void setPrivatePocketExit(String playerUUID, Location rift) { + if (rift != null) { + privatePocketExits.put(playerUUID, rift); + } else { + privatePocketExits.remove(playerUUID); + } + markDirty(); + } + public static Location getOverworldRift(String playerUUID) { // TODO: since this is per-world, move to different registry? return getForDim(0).overworldRifts.get(playerUUID); // store in overworld, since that's where per-world player data is stored } public static void setOverworldRift(String playerUUID, Location rift) { - getForDim(0).overworldRifts.put(playerUUID, rift); + if (rift != null) { + getForDim(0).overworldRifts.put(playerUUID, rift); + } else { + getForDim(0).overworldRifts.remove(playerUUID); + } getForDim(0).markDirty(); } diff --git a/src/main/java/com/zixiken/dimdoors/shared/rifts/TileEntityRift.java b/src/main/java/com/zixiken/dimdoors/shared/rifts/TileEntityRift.java index 13749ed3..f8c2a0aa 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/rifts/TileEntityRift.java +++ b/src/main/java/com/zixiken/dimdoors/shared/rifts/TileEntityRift.java @@ -37,7 +37,7 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { / @Getter protected boolean preserveRotation; @Getter protected float yaw; @Getter protected float pitch; - @Getter protected boolean alwaysDelete; // Delete the rift when an entrance rift is broken even if the state was changed or destinations link there. + @Getter protected boolean alwaysDelete; // Delete the rift when an entrances rift is broken even if the state was changed or destinations link there. @Getter protected float chaosWeight; // TODO: option to convert to door on teleportTo? @@ -178,7 +178,7 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { / addDestination(destination, 1, 0); } - public void setChaosWeight(int chaosWeight) { + public void setChaosWeight(float chaosWeight) { this.chaosWeight = chaosWeight; markDirty(); } @@ -226,7 +226,7 @@ public abstract class TileEntityRift extends TileEntity implements ITickable { / pocketRegistry.markDirty(); } } - // TODO: inform pocket that entrance was destroyed (we'll probably need an isPrivate field on the pocket) + // TODO: inform pocket that entrances was destroyed (we'll probably need an isPrivate field on the pocket) } public void updateAvailableLinks() { // Update available link info on rift type change or on virtualLocation change diff --git a/src/main/java/com/zixiken/dimdoors/shared/tools/PocketSchematicGenerator.java b/src/main/java/com/zixiken/dimdoors/shared/tools/PocketSchematicGenerator.java index 51defe33..3b5db870 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/tools/PocketSchematicGenerator.java +++ b/src/main/java/com/zixiken/dimdoors/shared/tools/PocketSchematicGenerator.java @@ -2,11 +2,12 @@ package com.zixiken.dimdoors.shared.tools; import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.server.DDProxyServer; +import com.zixiken.dimdoors.shared.blocks.BlockDimensionalDoor; import com.zixiken.dimdoors.shared.blocks.BlockFabric; import com.zixiken.dimdoors.shared.blocks.ModBlocks; import com.zixiken.dimdoors.shared.rifts.*; +import com.zixiken.dimdoors.shared.tileentities.TileEntityEntranceRift; import ddutils.schem.Schematic; -import net.minecraft.block.Block; import net.minecraft.block.BlockDoor; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; @@ -106,7 +107,7 @@ public final class PocketSchematicGenerator { return schematics; } - private static Schematic generatePocketSchematic(String baseName, int pocketSize, IBlockState outerWallBlockState, IBlockState innerWallBlockState, Block doorBlock, RiftDestination exitDest, float chaosWeight) { + private static Schematic generatePocketSchematic(String baseName, int pocketSize, IBlockState outerWallBlockState, IBlockState innerWallBlockState, BlockDimensionalDoor doorBlock, RiftDestination exitDest, float chaosWeight) { int size = (pocketSize + 1) * 16 - 1; // -1 so that the door can be centered // Set schematic info @@ -152,11 +153,13 @@ public final class PocketSchematicGenerator { // Generate the rift TileEntities schematic.tileEntities = new ArrayList<>(); - TileEntityRift rift = (TileEntityRift) doorBlock.createTileEntity(null, doorBlock.getDefaultState()); + TileEntityEntranceRift rift = (TileEntityEntranceRift) doorBlock.createTileEntity(null, doorBlock.getDefaultState()); rift.setSingleDestination(PocketEntranceDestination.builder() .ifDestinations(Collections.singletonList(new WeightedRiftDestination(exitDest, 1, 0))) .build()); - rift.setChaosWeight(0); + rift.setChaosWeight(chaosWeight); + + rift.setPlaceRiftOnBreak(true); NBTTagCompound tileNBT = rift.serializeNBT(); tileNBT.setInteger("x", (size - 1) / 2); tileNBT.setInteger("y", 5); diff --git a/src/main/java/com/zixiken/dimdoors/shared/world/limbodimension/WorldProviderLimbo.java b/src/main/java/com/zixiken/dimdoors/shared/world/limbodimension/WorldProviderLimbo.java index b674772f..42c19d5d 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/world/limbodimension/WorldProviderLimbo.java +++ b/src/main/java/com/zixiken/dimdoors/shared/world/limbodimension/WorldProviderLimbo.java @@ -82,9 +82,9 @@ public class WorldProviderLimbo extends WorldProvider { return new LimboGenerator(world, world.getSeed()); } - public static Location getLimboSkySpawn(EntityPlayer player) { - int x = (int) player.posX + MathHelper.clamp(player.world.rand.nextInt(), -100, 100); // TODO: -properties.LimboEntryRange, properties.LimboEntryRange); - int z = (int) player.posZ + MathHelper.clamp(player.world.rand.nextInt(), -100, 100); // TODO: -properties.LimboEntryRange, properties.LimboEntryRange); + public static Location getLimboSkySpawn(Entity entity) { // TODO: move this into projectToLimbo + int x = (int) entity.posX + MathHelper.clamp(entity.world.rand.nextInt(), -100, 100); // TODO: -properties.LimboEntryRange, properties.LimboEntryRange); + int z = (int) entity.posZ + MathHelper.clamp(entity.world.rand.nextInt(), -100, 100); // TODO: -properties.LimboEntryRange, properties.LimboEntryRange); return new Location(DimDoorDimensions.limbo.getId(), x, 700, z); } @@ -100,7 +100,6 @@ public class WorldProviderLimbo extends WorldProvider { return DimDoorDimensions.limbo; } - @SideOnly(Side.CLIENT) @Override public Vec3d getSkyColor(Entity cameraEntity, float partialTicks) { diff --git a/src/main/java/ddutils/Location.java b/src/main/java/ddutils/Location.java index 85588cb0..4d76b530 100644 --- a/src/main/java/ddutils/Location.java +++ b/src/main/java/ddutils/Location.java @@ -52,7 +52,7 @@ public class Location implements Serializable { } public WorldServer getWorld() { - return DimensionManager.getWorld(dim); + return WorldUtils.getWorld(dim); } public static Location getLocation(TileEntity tileEntity) { diff --git a/src/main/java/ddutils/nbt/NBTUtils.java b/src/main/java/ddutils/nbt/NBTUtils.java index 1b771619..6fa70cf5 100644 --- a/src/main/java/ddutils/nbt/NBTUtils.java +++ b/src/main/java/ddutils/nbt/NBTUtils.java @@ -1,12 +1,14 @@ package ddutils.nbt; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.Vec3i; import java.util.HashMap; import java.util.Map; -public final class NBTUtils { +public final class NBTUtils { // TODO: make these fill rather than return a map public static Map readMapStringInteger(NBTTagCompound nbt) { HashMap map = new HashMap<>(); for (String str : nbt.getKeySet()) { @@ -15,6 +17,14 @@ public final class NBTUtils { return map; } + public static BiMap readBiMapStringInteger(NBTTagCompound nbt) { + BiMap map = HashBiMap.create(); + for (String str : nbt.getKeySet()) { + map.put(str, nbt.getInteger(str)); + } + return map; + } + public static NBTTagCompound writeMapStringInteger(Map map) { NBTTagCompound tagCompound = new NBTTagCompound(); for (String str : map.keySet()) {